diff options
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/asn1Decoding.c | 108 | ||||
-rw-r--r-- | src/benchmark.c | 157 | ||||
-rw-r--r-- | src/benchmark.h | 52 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rwxr-xr-x | tests/benchmark | 35 |
6 files changed, 316 insertions, 40 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 3080c40..b0ed06e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,4 +27,4 @@ asn1Parser_SOURCES = asn1Parser.c asn1Coding_SOURCES = asn1Coding.c -asn1Decoding_SOURCES = asn1Decoding.c +asn1Decoding_SOURCES = asn1Decoding.c benchmark.c benchmark.h diff --git a/src/asn1Decoding.c b/src/asn1Decoding.c index 2fa97a9..494f14b 100644 --- a/src/asn1Decoding.c +++ b/src/asn1Decoding.c @@ -31,6 +31,9 @@ #include <progname.h> #include <version-etc.h> #include <read-file.h> +#include "benchmark.h" + +static int decode(ASN1_TYPE definitions, const char* typeName, void* der, int der_len, int benchmark); /* This feature is available in gcc versions 2.5 and later. */ #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) @@ -74,11 +77,10 @@ main (int argc, char *argv[]) char *inputFileDerName = NULL; char *typeName = NULL; ASN1_TYPE definitions = ASN1_TYPE_EMPTY; - ASN1_TYPE structure = ASN1_TYPE_EMPTY; char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; int asn1_result = ASN1_SUCCESS; unsigned char *der; - int der_len = 0; + int der_len = 0, benchmark = 0; /* FILE *outputFile; */ set_program_name (argv[0]); @@ -89,7 +91,7 @@ main (int argc, char *argv[]) { option_result = - getopt_long (argc, argv, "hvc", long_options, &option_index); + getopt_long (argc, argv, "hbvc", long_options, &option_index); if (option_result == -1) break; @@ -99,6 +101,9 @@ main (int argc, char *argv[]) case 'h': /* HELP */ usage (EXIT_SUCCESS); break; + case 'b': + benchmark = 1; + break; case 'v': /* VERSION */ version_etc (stdout, program_name, PACKAGE, VERSION, "Fabio Fiorina", NULL); @@ -195,50 +200,17 @@ main (int argc, char *argv[]) fclose(inputFile); */ - asn1_result = asn1_create_element (definitions, typeName, &structure); - - /* asn1_print_structure(stdout,structure,"",ASN1_PRINT_ALL); */ - - - if (asn1_result != ASN1_SUCCESS) + if (decode( definitions, typeName, der, der_len, benchmark) != ASN1_SUCCESS) { - printf ("Structure creation: %s\n", asn1_strerror (asn1_result)); asn1_delete_structure (&definitions); - free (inputFileAsnName); free (inputFileDerName); free (typeName); free (der); exit (1); } - - asn1_result = - asn1_der_decoding (&structure, der, der_len, errorDescription); - printf ("\nDecoding: %s\n", asn1_strerror (asn1_result)); - if (asn1_result != ASN1_SUCCESS) - printf ("asn1Decoding: %s\n", errorDescription); - - printf ("\nDECODING RESULT:\n"); - asn1_print_structure (stdout, structure, "", ASN1_PRINT_NAME_TYPE_VALUE); - - /*****************************************/ - /* ONLY FOR TEST */ - /*****************************************/ - /* - der_len=10000; - option_index=0; - asn1_result=asn1_read_value(structure,"?2.content",der,&der_len); - outputFile=fopen("encryptedData.p12","w"); - while(der_len>0){ - fprintf(outputFile,"%c",der[option_index]); - der_len--; - option_index++; - } - fclose(outputFile); - */ - + asn1_delete_structure (&definitions); - asn1_delete_structure (&structure); free (der); @@ -251,3 +223,63 @@ main (int argc, char *argv[]) exit (0); } + +static int simple_decode(ASN1_TYPE definitions, const char* typeName, void* der, int der_len, int benchmark) +{ + +int asn1_result; +ASN1_TYPE structure = ASN1_TYPE_EMPTY; +char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE]; + + asn1_result = asn1_create_element (definitions, typeName, &structure); + + /* asn1_print_structure(stdout,structure,"",ASN1_PRINT_ALL); */ + + + if (asn1_result != ASN1_SUCCESS) + { + printf ("Structure creation: %s\n", asn1_strerror (asn1_result)); + return asn1_result; + } + + asn1_result = + asn1_der_decoding (&structure, der, der_len, errorDescription); + + if (!benchmark) printf ("\nDecoding: %s\n", asn1_strerror (asn1_result)); + if (asn1_result != ASN1_SUCCESS) + { + printf ("asn1Decoding: %s\n", errorDescription); + return asn1_result; + } + + if (!benchmark) + { + printf ("\nDECODING RESULT:\n"); + asn1_print_structure (stdout, structure, "", ASN1_PRINT_NAME_TYPE_VALUE); + } + asn1_delete_structure (&structure); + return ASN1_SUCCESS; +} + +static int decode(ASN1_TYPE definitions, const char* typeName, void* der, int der_len, int benchmark) +{ +struct benchmark_st st; + + if (benchmark == 0) return simple_decode(definitions, typeName, der, der_len, benchmark); + else + { + start_benchmark(&st); + + do + { + simple_decode(definitions, typeName, der, der_len, benchmark); + st.size++; + } + while(benchmark_must_finish == 0); + + stop_benchmark(&st, "structures"); + fprintf(stdout, "\n"); + + } + return ASN1_SUCCESS; +} diff --git a/src/benchmark.c b/src/benchmark.c new file mode 100644 index 0000000..8ab3f8c --- /dev/null +++ b/src/benchmark.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2011-2012 Free Software Foundation, Inc. + * + * This file is part of GnuTLS. + * + * GnuTLS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <sys/time.h> +#include <time.h> +#include <unistd.h> +#include "benchmark.h" + +int benchmark_must_finish = 0; + +#if defined(_WIN32) +#include <windows.h> +DWORD WINAPI +alarm_handler (LPVOID lpParameter) +{ + HANDLE wtimer = *((HANDLE *) lpParameter); + WaitForSingleObject (wtimer, INFINITE); + benchmark_must_finish = 1; + return 0; +} +#else +static void +alarm_handler (int signo) +{ + benchmark_must_finish = 1; +} +#endif + +static void +value2human (unsigned long bytes, double time, double *data, double *speed, + char *metric) +{ + if (bytes > 1000 && bytes < 1000 * 1000) + { + *data = ((double) bytes) / 1000; + *speed = *data / time; + strcpy (metric, "KB"); + return; + } + else if (bytes >= 1000 * 1000 && bytes < 1000 * 1000 * 1000) + { + *data = ((double) bytes) / (1000 * 1000); + *speed = *data / time; + strcpy (metric, "MB"); + return; + } + else if (bytes >= 1000 * 1000 * 1000) + { + *data = ((double) bytes) / (1000 * 1000 * 1000); + *speed = *data / time; + strcpy (metric, "GB"); + return; + } + else + { + *data = (double) bytes; + *speed = *data / time; + strcpy (metric, "bytes"); + return; + } +} + +void start_benchmark(struct benchmark_st * st) +{ + memset(st, 0, sizeof(*st)); +#ifndef _WIN32 + st->old_handler = signal (SIGALRM, alarm_handler); +#endif + gettime (&st->start); + benchmark_must_finish = 0; + +#if defined(_WIN32) + st->wtimer = CreateWaitableTimer (NULL, TRUE, NULL); + if (st->wtimer == NULL) + { + fprintf (stderr, "error: CreateWaitableTimer %u\n", GetLastError ()); + exit(1); + } + st->wthread = CreateThread (NULL, 0, alarm_handler, &st->wtimer, 0, NULL); + if (st->wthread == NULL) + { + fprintf (stderr, "error: CreateThread %u\n", GetLastError ()); + exit(1); + } + st->alarm_timeout.QuadPart = (2) * 10000000; + if (SetWaitableTimer (st->wtimer, &st->alarm_timeout, 0, NULL, NULL, FALSE) == 0) + { + fprintf (stderr, "error: SetWaitableTimer %u\n", GetLastError ()); + exit(1); + } +#else + alarm (2); +#endif + +} + +/* returns the elapsed time */ +double stop_benchmark(struct benchmark_st * st, const char* metric) +{ + double secs; + unsigned long lsecs; + struct timespec stop; + double dspeed, ddata; + char imetric[16]; + +#if defined(_WIN32) + if (st->wtimer != NULL) + CloseHandle (st->wtimer); + if (st->wthread != NULL) + CloseHandle (st->wthread); +#else + signal(SIGALRM, st->old_handler); +#endif + + gettime (&stop); + + lsecs = (stop.tv_sec * 1000 + stop.tv_nsec / (1000 * 1000) - + (st->start.tv_sec * 1000 + st->start.tv_nsec / (1000 * 1000))); + secs = lsecs; + secs /= 1000; + + if (metric == NULL) + { /* assume bytes/sec */ + value2human (st->size, secs, &ddata, &dspeed, imetric); + printf (" Processed %.2f %s in %.2f secs: ", ddata, imetric, secs); + printf ("%.2f %s/sec\n", dspeed, imetric); + } + else + { + ddata = (double) st->size; + dspeed = ddata / secs; + printf (" Processed %.2f %s in %.2f secs: ", ddata, metric, secs); + printf ("%.2f %s/sec\n", dspeed, metric); + } + + return secs; +} diff --git a/src/benchmark.h b/src/benchmark.h new file mode 100644 index 0000000..e7d3386 --- /dev/null +++ b/src/benchmark.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011-2012 Free Software Foundation, Inc. + * + * This file is part of GnuTLS. + * + * GnuTLS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <sys/time.h> +#include <time.h> +#include <signal.h> +#if defined(_WIN32) +# include <windows.h> +#endif +#include "timespec.h" /* gnulib gettime */ + +typedef void (*sighandler_t)(int); + +struct benchmark_st +{ + struct timespec start; + unsigned long size; + sighandler_t old_handler; +#if defined(_WIN32) + HANDLE wtimer; + HANDLE wthread; + LARGE_INTEGER alarm_timeout; +#endif +}; + +extern int benchmark_must_finish; + +void start_benchmark(struct benchmark_st * st); +double stop_benchmark(struct benchmark_st * st, const char* metric); + +inline static unsigned int +timespec_sub_ms (struct timespec *a, struct timespec *b) +{ + return (a->tv_sec * 1000 + a->tv_nsec / (1000 * 1000) - + (b->tv_sec * 1000 + b->tv_nsec / (1000 * 1000))); +} diff --git a/tests/Makefile.am b/tests/Makefile.am index 61c8737..a7f8336 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -27,7 +27,7 @@ EXTRA_DIST = Test_parser.asn Test_tree.asn Test_tree_asn1_tab.c \ # For crlf. EXTRA_DIST += crlf.cer -dist_check_SCRIPTS = crlf +dist_check_SCRIPTS = crlf benchmark dist_check_SCRIPTS += threadsafety diff --git a/tests/benchmark b/tests/benchmark new file mode 100755 index 0000000..17a006a --- /dev/null +++ b/tests/benchmark @@ -0,0 +1,35 @@ +#!/bin/sh + +# Copyright (C) 2006-2012 Free Software Foundation, Inc. +# +# Author: Simon Josefsson +# +# This file is part of LIBTASN1. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +set -e + +srcdir=${srcdir:-.} +ASN1DECODING=../src/asn1Decoding${EXEEXT} + +# The crlf.cer file is a normal certificate which contains bytes 0x0A +# (LF), 0x0D (CF), and 0xFF (EOF), all are known to cause failures +# when using fopen/fgetc/fscanf on streams on some systems (read: +# Windows). + +$ASN1DECODING \ + -b $srcdir/../examples/pkix.asn \ + $srcdir/crlf.cer \ + PKIX1Implicit88.Certificate |