2003-08-04 Moritz Schulte <moritz@g10code.com>
[libgcrypt.git] / tests / benchmark.c
1 /* benchmark.c - for libgcrypt
2  *      Copyright (C) 2002 Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser general Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <time.h>
27 #include <sys/times.h>
28 #include <gcrypt.h>
29
30 #define PGM "benchmark"
31 #define BUG() do {fprintf ( stderr, "Ooops at %s:%d\n", __FILE__ , __LINE__ );\
32                   exit(2);} while(0)
33
34
35 /* Helper for the start and stop timer. */
36 static clock_t started_at, stopped_at;
37
38
39 static void
40 start_timer (void)
41 {
42   struct tms tmp;
43
44   times (&tmp);
45   started_at = stopped_at = tmp.tms_utime;
46 }
47
48 static void
49 stop_timer (void)
50 {
51   struct tms tmp;
52
53   times (&tmp);
54   stopped_at = tmp.tms_utime;
55 }
56
57 static const char *
58 elapsed_time (void)
59 {
60   static char buf[50];
61
62   sprintf (buf, "%5.0fms",
63            (((double) (stopped_at - started_at))/CLOCKS_PER_SEC)*10000000);
64   return buf;
65 }
66
67
68 static void
69 random_bench (void)
70 {
71   char buf[128];
72   int i;
73
74   printf ("%-10s", "random");
75
76   start_timer ();
77   for (i=0; i < 100; i++)
78     gcry_randomize (buf, sizeof buf, GCRY_STRONG_RANDOM);
79   stop_timer ();
80   printf (" %s", elapsed_time ());
81
82   start_timer ();
83   for (i=0; i < 100; i++)
84     gcry_randomize (buf, 8, GCRY_STRONG_RANDOM);
85   stop_timer ();
86   printf (" %s", elapsed_time ());
87
88   putchar ('\n');
89 }
90
91
92
93 static void
94 md_bench ( const char *algoname )
95 {
96   int algo = gcry_md_map_name (algoname);
97   gcry_md_hd_t hd;
98   int i;
99   char buf[1000];
100   gcry_error_t err = GPG_ERR_NO_ERROR;
101
102   if (!algo)
103     {
104       fprintf (stderr, PGM ": invalid hash algorithm `%s'\n", algoname);
105       exit (1);
106     }
107
108   err = gcry_md_open (&hd, algo, 0);
109   if (err)
110     {
111       fprintf (stderr, PGM ": error opeing hash algorithm `%s'/n", algoname);
112       exit (1);
113     }
114
115   for (i=0; i < sizeof buf; i++)
116     buf[i] = i;
117
118   printf ("%-10s", gcry_md_algo_name (algo));
119
120   start_timer ();
121   for (i=0; i < 1000; i++)
122     gcry_md_write (hd, buf, sizeof buf);
123   gcry_md_final (hd);
124   stop_timer ();
125   printf (" %s", elapsed_time ());
126
127   gcry_md_reset (hd);
128   start_timer ();
129   for (i=0; i < 10000; i++)
130     gcry_md_write (hd, buf, sizeof buf/10);
131   gcry_md_final (hd);
132   stop_timer ();
133   printf (" %s", elapsed_time ());
134
135   gcry_md_reset (hd);
136   start_timer ();
137   for (i=0; i < 1000000; i++)
138     gcry_md_write (hd, "", 1);
139   gcry_md_final (hd);
140   stop_timer ();
141   printf (" %s", elapsed_time ());
142
143   gcry_md_close (hd);
144   putchar ('\n');
145 }
146
147 static void
148 cipher_bench ( const char *algoname )
149 {
150   static int header_printed;
151   int algo = gcry_cipher_map_name (algoname);
152   gcry_cipher_hd_t hd;
153   int i;
154   int keylen, blklen;
155   char key[128];
156   char outbuf[1000], buf[1000];
157   size_t buflen;
158   static struct { int mode; const char *name; int blocked; } modes[] = {
159     { GCRY_CIPHER_MODE_ECB, "ECB", 1 },
160     { GCRY_CIPHER_MODE_CBC, "CBC", 1 },
161     { GCRY_CIPHER_MODE_CFB, "CFB", 0 },
162     { GCRY_CIPHER_MODE_CTR, "CTR", 0 },
163     { GCRY_CIPHER_MODE_STREAM, "STREAM", 0 },
164     {0}
165   };
166   int modeidx;
167   gcry_error_t err = GPG_ERR_NO_ERROR;
168
169   if (!header_printed)
170     {
171       printf ("%-10s", "Algo");
172       for (modeidx=0; modes[modeidx].mode; modeidx++)
173         printf (" %-15s", modes[modeidx].name );
174       putchar ('\n');
175       printf ( "----------");
176       for (modeidx=0; modes[modeidx].mode; modeidx++)
177         printf (" ---------------" );
178       putchar ('\n');
179       header_printed = 1;
180     }
181
182   if (!algo)
183     {
184       fprintf (stderr, PGM ": invalid cipher algorithm `%s'\n", algoname);
185       exit (1);
186     }
187
188   keylen = gcry_cipher_get_algo_keylen (algo);
189   if (!keylen)
190     {
191       fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n",
192                algoname);
193       exit (1);
194     }
195   if ( keylen > sizeof key )
196     {
197         fprintf (stderr, PGM ": algo %d, keylength problem (%d)\n",
198                  algo, keylen );
199         exit (1);
200     }
201   for (i=0; i < keylen; i++)
202     key[i] = i + (clock () & 0xff);
203
204   blklen = gcry_cipher_get_algo_blklen (algo);
205   if (!blklen)
206     {
207       fprintf (stderr, PGM ": failed to get block length for algorithm `%s'\n",
208                algoname);
209       exit (1);
210     }
211
212   printf ("%-10s", gcry_cipher_algo_name (algo));
213   fflush (stdout);
214
215   for (modeidx=0; modes[modeidx].mode; modeidx++)
216     {
217       if ((blklen > 1 && modes[modeidx].mode == GCRY_CIPHER_MODE_STREAM)
218           | (blklen == 1 && modes[modeidx].mode != GCRY_CIPHER_MODE_STREAM))
219         {
220           printf ("                " );
221           continue;
222         }
223
224       for (i=0; i < sizeof buf; i++)
225         buf[i] = i;
226
227       err = gcry_cipher_open (&hd, algo, modes[modeidx].mode, 0);
228       if (err)
229         {
230           fprintf (stderr, PGM ": error opening cipher `%s'\n", algoname);
231           exit (1);
232         }
233       
234       err = gcry_cipher_setkey (hd, key, keylen);
235       if (err)
236       { 
237           fprintf (stderr, "gcry_cipher_setkey failed: %s\n",
238                    gpg_strerror (err));
239           gcry_cipher_close (hd);
240           exit (1);
241         }
242
243       buflen = sizeof buf;
244       if (modes[modeidx].blocked)
245         buflen = (buflen / blklen) * blklen;
246
247       start_timer ();
248       for (i=err=0; !err && i < 1000; i++)
249         err = gcry_cipher_encrypt ( hd, outbuf, buflen, buf, buflen);
250       stop_timer ();
251       printf (" %s", elapsed_time ());
252       fflush (stdout);
253       gcry_cipher_close (hd);
254       if (err)
255         { 
256           fprintf (stderr, "gcry_cipher_encrypt failed: %s\n",
257                    gpg_strerror (err) );
258           exit (1);
259         }
260
261       err = gcry_cipher_open (&hd, algo, modes[modeidx].mode, 0);
262       if (err)
263         {
264           fprintf (stderr, PGM ": error opening cipher `%s'/n", algoname);
265           exit (1);
266         }
267       
268       err = gcry_cipher_setkey (hd, key, keylen);
269       if (err)
270         { 
271           fprintf (stderr, "gcry_cipher_setkey failed: %s\n",
272                    gpg_strerror (err));
273           gcry_cipher_close (hd);
274           exit (1);
275         }
276
277       start_timer ();
278       for (i=err=0; !err && i < 1000; i++)
279         err = gcry_cipher_decrypt ( hd, outbuf, buflen,  buf, buflen);
280       stop_timer ();
281       printf (" %s", elapsed_time ());
282       fflush (stdout);
283       gcry_cipher_close (hd);
284       if (err)
285         { 
286           fprintf (stderr, "gcry_cipher_decrypt failed: %s\n",
287                    gpg_strerror (err) );
288           exit (1);
289         }
290     }
291
292   putchar ('\n');
293 }
294
295
296 static void
297 do_powm ( const char *n_str, const char *e_str, const char *m_str)
298 {
299   gcry_mpi_t e, n, msg, cip;
300   gcry_error_t err;
301   int i;
302
303   err = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX, n_str, 0, 0);
304   if (err) BUG ();
305   err = gcry_mpi_scan (&e, GCRYMPI_FMT_HEX, e_str, 0, 0);
306   if (err) BUG ();
307   err = gcry_mpi_scan (&msg, GCRYMPI_FMT_HEX, m_str, 0, 0);
308   if (err) BUG ();
309
310   cip = gcry_mpi_new (0);
311
312   start_timer ();
313   for (i=0; i < 1000; i++)
314     gcry_mpi_powm (cip, msg, e, n);
315   stop_timer ();
316   printf (" %s", elapsed_time ()); fflush (stdout);
317 /*    { */
318 /*      char *buf; */
319
320 /*      if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, (void**)&buf, NULL, cip)) */
321 /*        BUG (); */
322 /*      printf ("result: %s\n", buf); */
323 /*      gcry_free (buf); */
324 /*    } */
325   gcry_mpi_release (cip);
326   gcry_mpi_release (msg);
327   gcry_mpi_release (n);
328   gcry_mpi_release (e);
329 }
330
331
332 static void
333 mpi_bench (void)
334 {
335   printf ("%-10s", "powm"); fflush (stdout);
336
337   do_powm (
338 "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E4",
339            "29", 
340 "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8"
341            );
342   do_powm (
343            "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA40716",
344            "29", 
345            "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847"
346            );
347   do_powm (
348            "20A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA4071620A94417D4D5EF2B2DA99165C7DC87DADB3979B72961AF90D09D59BA24CB9A10166FDCCC9C659F2B9626EC23F3FA425F564A072BA941B03FA81767CC289E41071F0246879A442658FBD18C1771571E7073EEEB2160BA0CBFB3404D627069A6CFBD53867AD2D9D40231648000787B5C84176B4336144644AE71A403CA40716",
349            "29", 
350            "B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847B870187A323F1ECD5B8A0B4249507335A1C4CE8394F38FD76B08C78A42C58F6EA136ACF90DFE8603697B1694A3D81114D6117AC1811979C51C4DD013D52F8FC4EE4BB446B83E48ABED7DB81CBF5E81DE4759E8D68AC985846D999F96B0D8A80E5C69D272C766AB8A23B40D50A4FA889FBC2BD2624222D8EB297F4BAEF8593847"
351            );
352
353   putchar ('\n');
354
355
356 }
357
358
359 int
360 main( int argc, char **argv )
361 {
362   if (argc < 2 )
363     {
364       fprintf (stderr, "usage: benchmark md|cipher|random|mpi [algonames]\n");
365       return 1;
366     }
367   argc--; argv++;
368   
369   if ( !strcmp (*argv, "random"))
370     {
371       random_bench ();
372     }
373   else if ( !strcmp (*argv, "md"))
374     {
375       for (argc--, argv++; argc; argc--, argv++)
376         md_bench ( *argv );
377     }
378   else if ( !strcmp (*argv, "cipher"))
379     {
380       for (argc--, argv++; argc; argc--, argv++)
381         cipher_bench ( *argv );
382     }
383   else if ( !strcmp (*argv, "mpi"))
384     {
385         mpi_bench ();
386     }
387   else
388     {
389       fprintf (stderr, PGM ": bad arguments\n");
390       return 1;
391     }
392   
393   return 0;
394 }
395
396