Merge in DES changed from 0.9.7-stable.
[openssl.git] / apps / speed.c
index 5c05e11d67028a81c8147a025bc158e962c26c70..fea0ffe2cfae09c9af8f4a9d4c3b125be31148c6 100644 (file)
@@ -1,4 +1,4 @@
-/* apps/speed.c */
+/* apps/speed.c -*- mode:C; c-file-style: "eay" -*- */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
 #include <openssl/crypto.h>
 #include <openssl/rand.h>
 #include <openssl/err.h>
-#include <openssl/engine.h>
 #include <openssl/evp.h>
 #include <openssl/objects.h>
+#if !defined(OPENSSL_SYS_MSDOS)
+#include OPENSSL_UNISTD
+#endif
 
 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(OPENSSL_SYS_MACOSX)
 # define USE_TOD
-#elif !defined(OPENSSL_SYS_MSDOS) && (!defined(OPENSSL_SYS_VMS) || defined(__DECC))
+#elif !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_VXWORKS) && (!defined(OPENSSL_SYS_VMS) || defined(__DECC))
 # define TIMES
 #endif
-#if !defined(_UNICOS) && !defined(__OpenBSD__) && !defined(sgi) && !defined(__FreeBSD__) && !(defined(__bsdi) || defined(__bsdi__)) && !defined(_AIX) && !defined(OPENSSL_SYS_MPE) && !defined(__NetBSD__) /* FIXME */
+#if !defined(_UNICOS) && !defined(__OpenBSD__) && !defined(sgi) && !defined(__FreeBSD__) && !(defined(__bsdi) || defined(__bsdi__)) && !defined(_AIX) && !defined(OPENSSL_SYS_MPE) && !defined(__NetBSD__) && !defined(OPENSSL_SYS_VXWORKS) /* FIXME */
 # define TIMEB
 #endif
 
 #include <sys/timeb.h>
 #endif
 
-#if !defined(TIMES) && !defined(TIMEB) && !defined(USE_TOD)
+#if !defined(TIMES) && !defined(TIMEB) && !defined(USE_TOD) && !defined(OPENSSL_SYS_VXWORKS)
 #error "It seems neither struct tms nor struct timeb is supported in this platform!"
 #endif
 
 #ifndef OPENSSL_NO_DES
 #include <openssl/des.h>
 #endif
+#ifndef OPENSSL_NO_AES
+#include <openssl/aes.h>
+#endif
 #ifndef OPENSSL_NO_MD2
 #include <openssl/md2.h>
 #endif
 
 /* The following if from times(3) man page.  It may need to be changed */
 #ifndef HZ
-# ifndef CLK_TCK
-#  ifndef _BSD_CLK_TCK_ /* FreeBSD hack */
-#   define HZ  100.0
-#  else /* _BSD_CLK_TCK_ */
-#   define HZ ((double)_BSD_CLK_TCK_)
+# ifdef _SC_CLK_TCK
+#  define HZ ((double)sysconf(_SC_CLK_TCK))
+# else
+#  ifndef CLK_TCK
+#   ifndef _BSD_CLK_TCK_ /* FreeBSD hack */
+#    define HZ 100.0
+#   else /* _BSD_CLK_TCK_ */
+#    define HZ ((double)_BSD_CLK_TCK_)
+#   endif
+#  else /* CLK_TCK */
+#   define HZ ((double)CLK_TCK)
 #  endif
-# else /* CLK_TCK */
-#  define HZ ((double)CLK_TCK)
 # endif
 #endif
 
+#if !defined(OPENSSL_SYS_VMS) && !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MACINTOSH_CLASSIC) && !defined(OPENSSL_SYS_OS2)
+# define HAVE_FORK 1
+#endif
+
 #undef BUFSIZE
 #define BUFSIZE        ((long)1024*8+1)
 int run=0;
 
-static double Time_F(int s, int usertime);
+static char ftime_used = 0, times_used = 0, gettimeofday_used = 0, getrusage_used = 0;
+static int mr=0;
+static int usertime=1;
+
+static double Time_F(int s);
 static void print_message(const char *s,long num,int length);
 static void pkey_print_message(char *str,char *str2,long num,int bits,int sec);
+static void print_result(int alg,int run_no,int count,double time_used);
+#ifdef HAVE_FORK
+static int do_multi(int multi);
+#endif
+
+#define ALGOR_NUM      19
+#define SIZE_NUM       5
+#define RSA_NUM                4
+#define DSA_NUM                3
+static const char *names[ALGOR_NUM]={
+  "md2","mdc2","md4","md5","hmac(md5)","sha1","rmd160","rc4",
+  "des cbc","des ede3","idea cbc",
+  "rc2 cbc","rc5-32/12 cbc","blowfish cbc","cast cbc",
+  "aes-128 cbc","aes-192 cbc","aes-256 cbc"};
+static double results[ALGOR_NUM][SIZE_NUM];
+static int lengths[SIZE_NUM]={16,64,256,1024,8*1024};
+static double rsa_results[RSA_NUM][2];
+static double dsa_results[DSA_NUM][2];
+
 #ifdef SIGALRM
 #if defined(__STDC__) || defined(sgi) || defined(_AIX)
 #define SIGRETTYPE void
@@ -221,7 +257,7 @@ static SIGRETTYPE sig_done(int sig)
 #define START  0
 #define STOP   1
 
-static double Time_F(int s, int usertime)
+static double Time_F(int s)
        {
        double ret;
 
@@ -230,6 +266,7 @@ static double Time_F(int s, int usertime)
            {
                static struct rusage tstart,tend;
 
+               getrusage_used = 1;
                if (s == START)
                        {
                        getrusage(RUSAGE_SELF,&tstart);
@@ -251,6 +288,7 @@ static double Time_F(int s, int usertime)
                static struct timeval tstart,tend;
                long i;
 
+               gettimeofday_used = 1;
                if (s == START)
                        {
                        gettimeofday(&tstart,NULL);
@@ -271,6 +309,7 @@ static double Time_F(int s, int usertime)
                {
                static struct tms tstart,tend;
 
+               times_used = 1;
                if (s == START)
                        {
                        times(&tstart);
@@ -287,11 +326,28 @@ static double Time_F(int s, int usertime)
 # if defined(TIMES) && defined(TIMEB)
        else
 # endif
-# ifdef TIMEB
+# ifdef OPENSSL_SYS_VXWORKS
+                {
+               static unsigned long tick_start, tick_end;
+
+               if( s == START )
+                       {
+                       tick_start = tickGet();
+                       return 0;
+                       }
+               else
+                       {
+                       tick_end = tickGet();
+                       ret = (double)(tick_end - tick_start) / (double)sysClkRateGet();
+                       return((ret < 0.001)?0.001:ret);
+                       }
+                }
+# elif defined(TIMEB)
                {
                static struct timeb tstart,tend;
                long i;
 
+               ftime_used = 1;
                if (s == START)
                        {
                        ftime(&tstart);
@@ -313,18 +369,18 @@ int MAIN(int, char **);
 
 int MAIN(int argc, char **argv)
        {
-       ENGINE *e;
+       ENGINE *e = NULL;
        unsigned char *buf=NULL,*buf2=NULL;
        int mret=1;
-#define ALGOR_NUM      16
-#define SIZE_NUM       5
-#define RSA_NUM                4
-#define DSA_NUM                3
-       long count,rsa_count,save_count=0;
+       long count=0,save_count=0;
        int i,j,k;
+#if !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_DSA)
+       long rsa_count;
+#endif
 #ifndef OPENSSL_NO_RSA
        unsigned rsa_num;
 #endif
+       unsigned char md[EVP_MAX_MD_SIZE];
 #ifndef OPENSSL_NO_MD2
        unsigned char md2[MD2_DIGEST_LENGTH];
 #endif
@@ -362,16 +418,36 @@ int MAIN(int argc, char **argv)
 #ifndef OPENSSL_NO_CAST
        CAST_KEY cast_ks;
 #endif
-       static unsigned char key16[16]=
+       static const unsigned char key16[16]=
                {0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,
                 0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12};
-       unsigned char iv[8];
+       static const unsigned char key24[24]=
+               {0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,
+                0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,
+                0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34};
+       static const unsigned char key32[32]=
+               {0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,
+                0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,
+                0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34,
+                0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34,0x56};
+#ifndef OPENSSL_NO_AES
+#define MAX_BLOCK_SIZE 128
+#else
+#define MAX_BLOCK_SIZE 64
+#endif
+       unsigned char DES_iv[8];
+       unsigned char iv[MAX_BLOCK_SIZE/8];
 #ifndef OPENSSL_NO_DES
-       des_cblock *buf_as_des_cblock = NULL;
-       static des_cblock key ={0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0};
-       static des_cblock key2={0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12};
-       static des_cblock key3={0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34};
-       des_key_schedule sch,sch2,sch3;
+       DES_cblock *buf_as_des_cblock = NULL;
+       static DES_cblock key ={0x12,0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0};
+       static DES_cblock key2={0x34,0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12};
+       static DES_cblock key3={0x56,0x78,0x9a,0xbc,0xde,0xf0,0x12,0x34};
+       DES_key_schedule sch;
+       DES_key_schedule sch2;
+       DES_key_schedule sch3;
+#endif
+#ifndef OPENSSL_NO_AES
+       AES_KEY aes_ks1, aes_ks2, aes_ks3;
 #endif
 #define        D_MD2           0
 #define        D_MDC2          1
@@ -388,14 +464,12 @@ int MAIN(int argc, char **argv)
 #define        D_CBC_RC5       12
 #define        D_CBC_BF        13
 #define        D_CBC_CAST      14
-#define D_EVP          15
-       double d,results[ALGOR_NUM][SIZE_NUM];
-       static int lengths[SIZE_NUM]={8,64,256,1024,8*1024};
+#define D_CBC_128_AES  15
+#define D_CBC_192_AES  16
+#define D_CBC_256_AES  17
+#define D_EVP          18
+       double d=0.0;
        long c[ALGOR_NUM][SIZE_NUM];
-       static const char *names[ALGOR_NUM]={
-               "md2","mdc2","md4","md5","hmac(md5)","sha1","rmd160","rc4",
-               "des cbc","des ede3","idea cbc",
-               "rc2 cbc","rc5-32/12 cbc","blowfish cbc","cast cbc"};
 #define        R_DSA_512       0
 #define        R_DSA_1024      1
 #define        R_DSA_2048      2
@@ -406,7 +480,6 @@ int MAIN(int argc, char **argv)
 #ifndef OPENSSL_NO_RSA
        RSA *rsa_key[RSA_NUM];
        long rsa_c[RSA_NUM][2];
-       double rsa_results[RSA_NUM][2];
        static unsigned int rsa_bits[RSA_NUM]={512,1024,2048,4096};
        static unsigned char *rsa_data[RSA_NUM]=
                {test512,test1024,test2048,test4096};
@@ -417,16 +490,18 @@ int MAIN(int argc, char **argv)
 #ifndef OPENSSL_NO_DSA
        DSA *dsa_key[DSA_NUM];
        long dsa_c[DSA_NUM][2];
-       double dsa_results[DSA_NUM][2];
        static unsigned int dsa_bits[DSA_NUM]={512,1024,2048};
 #endif
        int rsa_doit[RSA_NUM];
        int dsa_doit[DSA_NUM];
        int doit[ALGOR_NUM];
        int pr_header=0;
-       int usertime=1;
-       const EVP_CIPHER *evp=NULL;
+       const EVP_CIPHER *evp_cipher=NULL;
+       const EVP_MD *evp_md=NULL;
        int decrypt=0;
+#ifdef HAVE_FORK
+       int multi=0;
+#endif
 
 #ifndef TIMES
        usertime=-1;
@@ -442,6 +517,9 @@ int MAIN(int argc, char **argv)
                if ((bio_err=BIO_new(BIO_s_file())) != NULL)
                        BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
 
+       if (!load_config(bio_err, NULL))
+               goto end;
+
 #ifndef OPENSSL_NO_RSA
        memset(rsa_key,0,sizeof(rsa_key));
        for (i=0; i<RSA_NUM; i++)
@@ -454,7 +532,7 @@ int MAIN(int argc, char **argv)
                goto end;
                }
 #ifndef OPENSSL_NO_DES
-       buf_as_des_cblock = (des_cblock *)buf;
+       buf_as_des_cblock = (DES_cblock *)buf;
 #endif
        if ((buf2=(unsigned char *)OPENSSL_malloc((int)BUFSIZE)) == NULL)
                {
@@ -463,6 +541,7 @@ int MAIN(int argc, char **argv)
                }
 
        memset(c,0,sizeof(c));
+       memset(DES_iv,0,sizeof(DES_iv));
        memset(iv,0,sizeof(iv));
 
        for (i=0; i<ALGOR_NUM; i++)
@@ -478,7 +557,11 @@ int MAIN(int argc, char **argv)
        while (argc)
                {
                if      ((argc > 0) && (strcmp(*argv,"-elapsed") == 0))
+                       {
                        usertime = 0;
+                       j--;    /* Otherwise, -elapsed gets confused with
+                                  an algorithm. */
+                       }
                else if ((argc > 0) && (strcmp(*argv,"-evp") == 0))
                        {
                        argc--;
@@ -488,18 +571,25 @@ int MAIN(int argc, char **argv)
                                BIO_printf(bio_err,"no EVP given\n");
                                goto end;
                                }
-                       evp=EVP_get_cipherbyname(*argv);
-                       if(!evp)
+                       evp_cipher=EVP_get_cipherbyname(*argv);
+                       if(!evp_cipher)
                                {
-                               BIO_printf(bio_err,"%s is an unknown cipher\n",*argv);
+                               evp_md=EVP_get_digestbyname(*argv);
+                               }
+                       if(!evp_cipher && !evp_md)
+                               {
+                               BIO_printf(bio_err,"%s is an unknown cipher or digest\n",*argv);
                                goto end;
                                }
                        doit[D_EVP]=1;
                        }
-               else if(argc > 0 && !strcmp(*argv,"-decrypt"))
+               else if (argc > 0 && !strcmp(*argv,"-decrypt"))
+                       {
                        decrypt=1;
-               else
-               if      ((argc > 0) && (strcmp(*argv,"-engine") == 0))
+                       j--;    /* Otherwise, -elapsed gets confused with
+                                  an algorithm. */
+                       }
+               else if ((argc > 0) && (strcmp(*argv,"-engine") == 0))
                        {
                        argc--;
                        argv++;
@@ -515,6 +605,32 @@ int MAIN(int argc, char **argv)
                           means all of them should be run) */
                        j--;
                        }
+#ifdef HAVE_FORK
+               else if ((argc > 0) && (strcmp(*argv,"-multi") == 0))
+                       {
+                       argc--;
+                       argv++;
+                       if(argc == 0)
+                               {
+                               BIO_printf(bio_err,"no multi count given\n");
+                               goto end;
+                               }
+                       multi=atoi(argv[0]);
+                       if(multi <= 0)
+                           {
+                               BIO_printf(bio_err,"bad multi count\n");
+                               goto end;
+                               }                               
+                       j--;    /* Otherwise, -mr gets confused with
+                                  an algorithm. */
+                       }
+#endif
+               else if (argc > 0 && !strcmp(*argv,"-mr"))
+                       {
+                       mr=1;
+                       j--;    /* Otherwise, -mr gets confused with
+                                  an algorithm. */
+                       }
                else
 #ifndef OPENSSL_NO_MD2
                if      (strcmp(*argv,"md2") == 0) doit[D_MD2]=1;
@@ -559,6 +675,12 @@ int MAIN(int argc, char **argv)
                else    if (strcmp(*argv,"des-ede3") == 0) doit[D_EDE3_DES]=1;
                else
 #endif
+#ifndef OPENSSL_NO_AES
+                       if (strcmp(*argv,"aes-128-cbc") == 0) doit[D_CBC_128_AES]=1;
+               else    if (strcmp(*argv,"aes-192-cbc") == 0) doit[D_CBC_192_AES]=1;
+               else    if (strcmp(*argv,"aes-256-cbc") == 0) doit[D_CBC_256_AES]=1;
+               else
+#endif
 #ifndef OPENSSL_NO_RSA
 #if 0 /* was: #ifdef RSAref */
                        if (strcmp(*argv,"rsaref") == 0) 
@@ -571,7 +693,7 @@ int MAIN(int argc, char **argv)
 #ifndef RSA_NULL
                        if (strcmp(*argv,"openssl") == 0) 
                        {
-                       RSA_set_default_openssl_method(RSA_PKCS1_SSLeay());
+                       RSA_set_default_method(RSA_PKCS1_SSLeay());
                        j--;
                        }
                else
@@ -620,6 +742,15 @@ int MAIN(int argc, char **argv)
                        }
                else
 #endif
+#ifndef OPENSSL_NO_AES
+                       if (strcmp(*argv,"aes") == 0)
+                       {
+                       doit[D_CBC_128_AES]=1;
+                       doit[D_CBC_192_AES]=1;
+                       doit[D_CBC_256_AES]=1;
+                       }
+               else
+#endif
 #ifndef OPENSSL_NO_RSA
                        if (strcmp(*argv,"rsa") == 0)
                        {
@@ -685,8 +816,12 @@ int MAIN(int argc, char **argv)
     !defined(OPENSSL_NO_BF) || !defined(OPENSSL_NO_RC5)
                        BIO_printf(bio_err,"\n");
 #endif
-
+#ifndef OPENSSL_NO_DES
                        BIO_printf(bio_err,"des-cbc  des-ede3 ");
+#endif
+#ifndef OPENSSL_NO_AES
+                       BIO_printf(bio_err,"aes-128-cbc aes-192-cbc aes-256-cbc ");
+#endif
 #ifndef OPENSSL_NO_RC4
                        BIO_printf(bio_err,"rc4");
 #endif
@@ -709,6 +844,9 @@ int MAIN(int argc, char **argv)
 #ifndef OPENSSL_NO_DES
                        BIO_printf(bio_err,"des      ");
 #endif
+#ifndef OPENSSL_NO_AES
+                       BIO_printf(bio_err,"aes      ");
+#endif
 #ifndef OPENSSL_NO_RSA
                        BIO_printf(bio_err,"rsa      ");
 #endif
@@ -717,7 +855,7 @@ int MAIN(int argc, char **argv)
 #endif
 #if !defined(OPENSSL_NO_IDEA) || !defined(OPENSSL_NO_RC2) || \
     !defined(OPENSSL_NO_DES) || !defined(OPENSSL_NO_RSA) || \
-    !defined(OPENSSL_NO_BF)
+    !defined(OPENSSL_NO_BF) || !defined(OPENSSL_NO_AES)
                        BIO_printf(bio_err,"\n");
 #endif
 
@@ -727,6 +865,12 @@ int MAIN(int argc, char **argv)
                        BIO_printf(bio_err,"-elapsed        measure time in real time instead of CPU user time.\n");
 #endif
                        BIO_printf(bio_err,"-engine e       use engine e, possibly a hardware device.\n");
+                       BIO_printf(bio_err,"-evp e          use EVP e.\n");
+                       BIO_printf(bio_err,"-decrypt        time decryption instead of encryption (only EVP).\n");
+                       BIO_printf(bio_err,"-mr             produce machine readable output.\n");
+#ifdef HAVE_FORK
+                       BIO_printf(bio_err,"-multi n        run n benchmarks in parallel.\n");
+#endif
                        goto end;
                        }
                argc--;
@@ -734,6 +878,11 @@ int MAIN(int argc, char **argv)
                j++;
                }
 
+#ifdef HAVE_FORK
+       if(multi && do_multi(multi))
+               goto show_res;
+#endif
+
        if (j == 0)
                {
                for (i=0; i<ALGOR_NUM; i++)
@@ -749,9 +898,9 @@ int MAIN(int argc, char **argv)
        for (i=0; i<ALGOR_NUM; i++)
                if (doit[i]) pr_header++;
 
-       if (usertime == 0)
+       if (usertime == 0 && !mr)
                BIO_printf(bio_err,"You have chosen to measure elapsed time instead of user CPU time.\n");
-       if (usertime <= 0)
+       if (usertime <= 0 && !mr)
                {
                BIO_printf(bio_err,"To get the most accurate results, try to run this\n");
                BIO_printf(bio_err,"program when this computer is idle.\n");
@@ -772,7 +921,9 @@ int MAIN(int argc, char **argv)
 #if 0
                else
                        {
-                       BIO_printf(bio_err,"Loaded RSA key, %d bit modulus and e= 0x",BN_num_bits(rsa_key[i]->n));
+                       BIO_printf(bio_err,mr ? "+RK:%d:"
+                                  : "Loaded RSA key, %d bit modulus and e= 0x",
+                                  BN_num_bits(rsa_key[i]->n));
                        BN_print(bio_err,rsa_key[i]->e);
                        BIO_printf(bio_err,"\n");
                        }
@@ -787,9 +938,14 @@ int MAIN(int argc, char **argv)
 #endif
 
 #ifndef OPENSSL_NO_DES
-       des_set_key_unchecked(&key,&sch);
-       des_set_key_unchecked(&key2,&sch2);
-       des_set_key_unchecked(&key3,&sch3);
+       DES_set_key_unchecked(&key,&sch);
+       DES_set_key_unchecked(&key2,&sch2);
+       DES_set_key_unchecked(&key3,&sch3);
+#endif
+#ifndef OPENSSL_NO_AES
+       AES_set_encrypt_key(key16,128,&aes_ks1);
+       AES_set_encrypt_key(key24,192,&aes_ks2);
+       AES_set_encrypt_key(key32,256,&aes_ks3);
 #endif
 #ifndef OPENSSL_NO_IDEA
        idea_set_encrypt_key(key16,&idea_ks);
@@ -819,11 +975,11 @@ int MAIN(int argc, char **argv)
        do      {
                long i;
                count*=2;
-               Time_F(START,usertime);
+               Time_F(START);
                for (i=count; i; i--)
-                       des_ecb_encrypt(buf_as_des_cblock,buf_as_des_cblock,
-                               &(sch[0]),DES_ENCRYPT);
-               d=Time_F(STOP,usertime);
+                       DES_ecb_encrypt(buf_as_des_cblock,buf_as_des_cblock,
+                               &sch,DES_ENCRYPT);
+               d=Time_F(STOP);
                } while (d <3);
        save_count=count;
        c[D_MD2][0]=count/10;
@@ -925,13 +1081,11 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_MD2],c[D_MD2][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_MD2][j]); count++)
-                               EVP_Digest(buf,(unsigned long)lengths[j],&(md2[0]),NULL,EVP_md2());
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_MD2],d);
-                       results[D_MD2][j]=((double)count)/d*lengths[j];
+                               EVP_Digest(buf,(unsigned long)lengths[j],&(md2[0]),NULL,EVP_md2(),NULL);
+                       d=Time_F(STOP);
+                       print_result(D_MD2,j,count,d);
                        }
                }
 #endif
@@ -941,13 +1095,11 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_MDC2],c[D_MDC2][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_MDC2][j]); count++)
-                               EVP_Digest(buf,(unsigned long)lengths[j],&(mdc2[0]),NULL,EVP_mdc2());
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_MDC2],d);
-                       results[D_MDC2][j]=((double)count)/d*lengths[j];
+                               EVP_Digest(buf,(unsigned long)lengths[j],&(mdc2[0]),NULL,EVP_mdc2(),NULL);
+                       d=Time_F(STOP);
+                       print_result(D_MDC2,j,count,d);
                        }
                }
 #endif
@@ -958,13 +1110,11 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_MD4],c[D_MD4][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_MD4][j]); count++)
-                               EVP_Digest(&(buf[0]),(unsigned long)lengths[j],&(md4[0]),NULL,EVP_md4());
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_MD4],d);
-                       results[D_MD4][j]=((double)count)/d*lengths[j];
+                               EVP_Digest(&(buf[0]),(unsigned long)lengths[j],&(md4[0]),NULL,EVP_md4(),NULL);
+                       d=Time_F(STOP);
+                       print_result(D_MD4,j,count,d);
                        }
                }
 #endif
@@ -975,13 +1125,11 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_MD5],c[D_MD5][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_MD5][j]); count++)
-                               EVP_Digest(&(buf[0]),(unsigned long)lengths[j],&(md5[0]),NULL,EVP_get_digestbyname("md5"));
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_MD5],d);
-                       results[D_MD5][j]=((double)count)/d*lengths[j];
+                               EVP_Digest(&(buf[0]),(unsigned long)lengths[j],&(md5[0]),NULL,EVP_get_digestbyname("md5"),NULL);
+                       d=Time_F(STOP);
+                       print_result(D_MD5,j,count,d);
                        }
                }
 #endif
@@ -992,23 +1140,21 @@ int MAIN(int argc, char **argv)
                HMAC_CTX hctx;
 
                HMAC_CTX_init(&hctx);
-               HMAC_Init(&hctx,(unsigned char *)"This is a key...",
-                       16,EVP_md5());
+               HMAC_Init_ex(&hctx,(unsigned char *)"This is a key...",
+                       16,EVP_md5(), NULL);
 
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_HMAC],c[D_HMAC][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_HMAC][j]); count++)
                                {
-                               HMAC_Init(&hctx,NULL,0,NULL);
-                                HMAC_Update(&hctx,buf,lengths[j]);
-                                HMAC_Final(&hctx,&(hmac[0]),NULL);
+                               HMAC_Init_ex(&hctx,NULL,0,NULL,NULL);
+                               HMAC_Update(&hctx,buf,lengths[j]);
+                               HMAC_Final(&hctx,&(hmac[0]),NULL);
                                }
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_HMAC],d);
-                       results[D_HMAC][j]=((double)count)/d*lengths[j];
+                       d=Time_F(STOP);
+                       print_result(D_HMAC,j,count,d);
                        }
                HMAC_CTX_cleanup(&hctx);
                }
@@ -1019,13 +1165,11 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_SHA1],c[D_SHA1][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_SHA1][j]); count++)
-                               EVP_Digest(buf,(unsigned long)lengths[j],&(sha[0]),NULL,EVP_sha1());
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_SHA1],d);
-                       results[D_SHA1][j]=((double)count)/d*lengths[j];
+                               EVP_Digest(buf,(unsigned long)lengths[j],&(sha[0]),NULL,EVP_sha1(),NULL);
+                       d=Time_F(STOP);
+                       print_result(D_SHA1,j,count,d);
                        }
                }
 #endif
@@ -1035,13 +1179,11 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_RMD160],c[D_RMD160][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_RMD160][j]); count++)
-                               EVP_Digest(buf,(unsigned long)lengths[j],&(rmd160[0]),NULL,EVP_ripemd160());
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_RMD160],d);
-                       results[D_RMD160][j]=((double)count)/d*lengths[j];
+                               EVP_Digest(buf,(unsigned long)lengths[j],&(rmd160[0]),NULL,EVP_ripemd160(),NULL);
+                       d=Time_F(STOP);
+                       print_result(D_RMD160,j,count,d);
                        }
                }
 #endif
@@ -1051,14 +1193,12 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_RC4],c[D_RC4][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_RC4][j]); count++)
                                RC4(&rc4_ks,(unsigned int)lengths[j],
                                        buf,buf);
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_RC4],d);
-                       results[D_RC4][j]=((double)count)/d*lengths[j];
+                       d=Time_F(STOP);
+                       print_result(D_RC4,j,count,d);
                        }
                }
 #endif
@@ -1068,14 +1208,12 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_CBC_DES],c[D_CBC_DES][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_CBC_DES][j]); count++)
-                               des_ncbc_encrypt(buf,buf,lengths[j],&sch,
-                                                &iv,DES_ENCRYPT);
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                                  count,names[D_CBC_DES],d);
-                       results[D_CBC_DES][j]=((double)count)/d*lengths[j];
+                               DES_ncbc_encrypt(buf,buf,lengths[j],&sch,
+                                                &DES_iv,DES_ENCRYPT);
+                       d=Time_F(STOP);
+                       print_result(D_CBC_DES,j,count,d);
                        }
                }
 
@@ -1084,17 +1222,60 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_EDE3_DES],c[D_EDE3_DES][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_EDE3_DES][j]); count++)
-                               des_ede3_cbc_encrypt(buf,buf,lengths[j],
+                               DES_ede3_cbc_encrypt(buf,buf,lengths[j],
                                                     &sch,&sch2,&sch3,
-                                                    &iv,DES_ENCRYPT);
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_EDE3_DES],d);
-                       results[D_EDE3_DES][j]=((double)count)/d*lengths[j];
+                                                    &DES_iv,DES_ENCRYPT);
+                       d=Time_F(STOP);
+                       print_result(D_EDE3_DES,j,count,d);
+                       }
+               }
+#endif
+#ifndef OPENSSL_NO_AES
+       if (doit[D_CBC_128_AES])
+               {
+               for (j=0; j<SIZE_NUM; j++)
+                       {
+                       print_message(names[D_CBC_128_AES],c[D_CBC_128_AES][j],lengths[j]);
+                       Time_F(START);
+                       for (count=0,run=1; COND(c[D_CBC_128_AES][j]); count++)
+                               AES_cbc_encrypt(buf,buf,
+                                       (unsigned long)lengths[j],&aes_ks1,
+                                       iv,AES_ENCRYPT);
+                       d=Time_F(STOP);
+                       print_result(D_CBC_128_AES,j,count,d);
+                       }
+               }
+       if (doit[D_CBC_192_AES])
+               {
+               for (j=0; j<SIZE_NUM; j++)
+                       {
+                       print_message(names[D_CBC_192_AES],c[D_CBC_192_AES][j],lengths[j]);
+                       Time_F(START);
+                       for (count=0,run=1; COND(c[D_CBC_192_AES][j]); count++)
+                               AES_cbc_encrypt(buf,buf,
+                                       (unsigned long)lengths[j],&aes_ks2,
+                                       iv,AES_ENCRYPT);
+                       d=Time_F(STOP);
+                       print_result(D_CBC_192_AES,j,count,d);
+                       }
+               }
+       if (doit[D_CBC_256_AES])
+               {
+               for (j=0; j<SIZE_NUM; j++)
+                       {
+                       print_message(names[D_CBC_256_AES],c[D_CBC_256_AES][j],lengths[j]);
+                       Time_F(START);
+                       for (count=0,run=1; COND(c[D_CBC_256_AES][j]); count++)
+                               AES_cbc_encrypt(buf,buf,
+                                       (unsigned long)lengths[j],&aes_ks3,
+                                       iv,AES_ENCRYPT);
+                       d=Time_F(STOP);
+                       print_result(D_CBC_256_AES,j,count,d);
                        }
                }
+
 #endif
 #ifndef OPENSSL_NO_IDEA
        if (doit[D_CBC_IDEA])
@@ -1102,15 +1283,13 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_CBC_IDEA],c[D_CBC_IDEA][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_CBC_IDEA][j]); count++)
                                idea_cbc_encrypt(buf,buf,
                                        (unsigned long)lengths[j],&idea_ks,
                                        iv,IDEA_ENCRYPT);
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_CBC_IDEA],d);
-                       results[D_CBC_IDEA][j]=((double)count)/d*lengths[j];
+                       d=Time_F(STOP);
+                       print_result(D_CBC_IDEA,j,count,d);
                        }
                }
 #endif
@@ -1120,15 +1299,13 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_CBC_RC2],c[D_CBC_RC2][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_CBC_RC2][j]); count++)
                                RC2_cbc_encrypt(buf,buf,
                                        (unsigned long)lengths[j],&rc2_ks,
                                        iv,RC2_ENCRYPT);
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_CBC_RC2],d);
-                       results[D_CBC_RC2][j]=((double)count)/d*lengths[j];
+                       d=Time_F(STOP);
+                       print_result(D_CBC_RC2,j,count,d);
                        }
                }
 #endif
@@ -1138,15 +1315,13 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_CBC_RC5],c[D_CBC_RC5][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_CBC_RC5][j]); count++)
                                RC5_32_cbc_encrypt(buf,buf,
                                        (unsigned long)lengths[j],&rc5_ks,
                                        iv,RC5_ENCRYPT);
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_CBC_RC5],d);
-                       results[D_CBC_RC5][j]=((double)count)/d*lengths[j];
+                       d=Time_F(STOP);
+                       print_result(D_CBC_RC5,j,count,d);
                        }
                }
 #endif
@@ -1156,15 +1331,13 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_CBC_BF],c[D_CBC_BF][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_CBC_BF][j]); count++)
                                BF_cbc_encrypt(buf,buf,
                                        (unsigned long)lengths[j],&bf_ks,
                                        iv,BF_ENCRYPT);
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_CBC_BF],d);
-                       results[D_CBC_BF][j]=((double)count)/d*lengths[j];
+                       d=Time_F(STOP);
+                       print_result(D_CBC_BF,j,count,d);
                        }
                }
 #endif
@@ -1174,15 +1347,13 @@ int MAIN(int argc, char **argv)
                for (j=0; j<SIZE_NUM; j++)
                        {
                        print_message(names[D_CBC_CAST],c[D_CBC_CAST][j],lengths[j]);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(c[D_CBC_CAST][j]); count++)
                                CAST_cbc_encrypt(buf,buf,
                                        (unsigned long)lengths[j],&cast_ks,
                                        iv,CAST_ENCRYPT);
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                               count,names[D_CBC_CAST],d);
-                       results[D_CBC_CAST][j]=((double)count)/d*lengths[j];
+                       d=Time_F(STOP);
+                       print_result(D_CBC_CAST,j,count,d);
                        }
                }
 #endif
@@ -1191,32 +1362,50 @@ int MAIN(int argc, char **argv)
                {
                for (j=0; j<SIZE_NUM; j++)
                        {
-                       EVP_CIPHER_CTX ctx;
-                       int outl;
+                       if (evp_cipher)
+                               {
+                               EVP_CIPHER_CTX ctx;
+                               int outl;
+
+                               names[D_EVP]=OBJ_nid2ln(evp_cipher->nid);
+                               /* -O3 -fschedule-insns messes up an
+                                * optimization here!  names[D_EVP]
+                                * somehow becomes NULL */
+                               print_message(names[D_EVP],save_count,
+                                       lengths[j]);
+
+                               EVP_CIPHER_CTX_init(&ctx);
+                               if(decrypt)
+                                       EVP_DecryptInit_ex(&ctx,evp_cipher,NULL,key16,iv);
+                               else
+                                       EVP_EncryptInit_ex(&ctx,evp_cipher,NULL,key16,iv);
+
+                               Time_F(START);
+                               if(decrypt)
+                                       for (count=0,run=1; COND(save_count*4*lengths[0]/lengths[j]); count++)
+                                               EVP_DecryptUpdate(&ctx,buf,&outl,buf,lengths[j]);
+                               else
+                                       for (count=0,run=1; COND(save_count*4*lengths[0]/lengths[j]); count++)
+                                               EVP_EncryptUpdate(&ctx,buf,&outl,buf,lengths[j]);
+                               if(decrypt)
+                                       EVP_DecryptFinal_ex(&ctx,buf,&outl);
+                               else
+                                       EVP_EncryptFinal_ex(&ctx,buf,&outl);
+                               d=Time_F(STOP);
+                               }
+                       if (evp_md)
+                               {
+                               names[D_EVP]=OBJ_nid2ln(evp_md->type);
+                               print_message(names[D_EVP],save_count,
+                                       lengths[j]);
 
-                       names[D_EVP]=OBJ_nid2ln(evp->nid);
-                       print_message(names[D_EVP],save_count,
-                                                 lengths[j]);
-                       if(decrypt)
-                               EVP_DecryptInit(&ctx,evp,key16,iv);
-                       else
-                               EVP_EncryptInit(&ctx,evp,key16,iv);
-                               
-                       Time_F(START,usertime);
-                       if(decrypt)
-                               for (count=0,run=1; COND(save_count*4*lengths[0]/lengths[j]); count++)
-                                       EVP_DecryptUpdate(&ctx,buf,&outl,buf,lengths[j]);
-                       else
+                               Time_F(START);
                                for (count=0,run=1; COND(save_count*4*lengths[0]/lengths[j]); count++)
-                                       EVP_EncryptUpdate(&ctx,buf,&outl,buf,lengths[j]);
-                       if(decrypt)
-                               EVP_DecryptFinal(&ctx,buf,&outl);
-                       else
-                               EVP_EncryptFinal(&ctx,buf,&outl);
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %s's in %.2fs\n",
-                                          count,names[D_EVP],d);
-                       results[D_EVP][j]=((double)count)/d*lengths[j];
+                                       EVP_Digest(buf,lengths[j],&(md[0]),NULL,evp_md,NULL);
+
+                               d=Time_F(STOP);
+                               }
+                       print_result(D_EVP,j,count,d);
                        }
                }
 
@@ -1239,7 +1428,7 @@ int MAIN(int argc, char **argv)
                                rsa_c[j][0],rsa_bits[j],
                                RSA_SECONDS);
 /*                     RSA_blinding_on(rsa_key[j],NULL); */
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(rsa_c[j][0]); count++)
                                {
                                ret=RSA_sign(NID_md5_sha1, buf,36, buf2,
@@ -1253,10 +1442,10 @@ int MAIN(int argc, char **argv)
                                        break;
                                        }
                                }
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,
-                               "%ld %d bit private RSA's in %.2fs\n",
-                               count,rsa_bits[j],d);
+                       d=Time_F(STOP);
+                       BIO_printf(bio_err,mr ? "+R1:%ld:%d:%.2f\n"
+                                  : "%ld %d bit private RSA's in %.2fs\n",
+                                  count,rsa_bits[j],d);
                        rsa_results[j][0]=d/(double)count;
                        rsa_count=count;
                        }
@@ -1274,7 +1463,7 @@ int MAIN(int argc, char **argv)
                        pkey_print_message("public","rsa",
                                rsa_c[j][1],rsa_bits[j],
                                RSA_SECONDS);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(rsa_c[j][1]); count++)
                                {
                                ret=RSA_verify(NID_md5_sha1, buf,36, buf2,
@@ -1288,10 +1477,10 @@ int MAIN(int argc, char **argv)
                                        break;
                                        }
                                }
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,
-                               "%ld %d bit public RSA's in %.2fs\n",
-                               count,rsa_bits[j],d);
+                       d=Time_F(STOP);
+                       BIO_printf(bio_err,mr ? "+R2:%ld:%d:%.2f\n"
+                                  : "%ld %d bit public RSA's in %.2fs\n",
+                                  count,rsa_bits[j],d);
                        rsa_results[j][1]=d/(double)count;
                        }
 #endif
@@ -1333,7 +1522,7 @@ int MAIN(int argc, char **argv)
                        pkey_print_message("sign","dsa",
                                dsa_c[j][0],dsa_bits[j],
                                DSA_SECONDS);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(dsa_c[j][0]); count++)
                                {
                                ret=DSA_sign(EVP_PKEY_DSA,buf,20,buf2,
@@ -1347,9 +1536,10 @@ int MAIN(int argc, char **argv)
                                        break;
                                        }
                                }
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %d bit DSA signs in %.2fs\n",
-                               count,dsa_bits[j],d);
+                       d=Time_F(STOP);
+                       BIO_printf(bio_err,mr ? "+R3:%ld:%d:%.2f\n"
+                                  : "%ld %d bit DSA signs in %.2fs\n",
+                                  count,dsa_bits[j],d);
                        dsa_results[j][0]=d/(double)count;
                        rsa_count=count;
                        }
@@ -1367,7 +1557,7 @@ int MAIN(int argc, char **argv)
                        pkey_print_message("verify","dsa",
                                dsa_c[j][1],dsa_bits[j],
                                DSA_SECONDS);
-                       Time_F(START,usertime);
+                       Time_F(START);
                        for (count=0,run=1; COND(dsa_c[j][1]); count++)
                                {
                                ret=DSA_verify(EVP_PKEY_DSA,buf,20,buf2,
@@ -1381,9 +1571,10 @@ int MAIN(int argc, char **argv)
                                        break;
                                        }
                                }
-                       d=Time_F(STOP,usertime);
-                       BIO_printf(bio_err,"%ld %d bit DSA verify in %.2fs\n",
-                               count,dsa_bits[j],d);
+                       d=Time_F(STOP);
+                       BIO_printf(bio_err,mr ? "+R4:%ld:%d:%.2f\n"
+                                  : "%ld %d bit DSA verify in %.2fs\n",
+                                  count,dsa_bits[j],d);
                        dsa_results[j][1]=d/(double)count;
                        }
 
@@ -1396,47 +1587,89 @@ int MAIN(int argc, char **argv)
                }
        if (rnd_fake) RAND_cleanup();
 #endif
-
-       fprintf(stdout,"%s\n",SSLeay_version(SSLEAY_VERSION));
+#ifdef HAVE_FORK
+show_res:
+#endif
+       if(!mr)
+               {
+               fprintf(stdout,"%s\n",SSLeay_version(SSLEAY_VERSION));
         fprintf(stdout,"%s\n",SSLeay_version(SSLEAY_BUILT_ON));
-       printf("options:");
-       printf("%s ",BN_options());
+               printf("options:");
+               printf("%s ",BN_options());
 #ifndef OPENSSL_NO_MD2
-       printf("%s ",MD2_options());
+               printf("%s ",MD2_options());
 #endif
 #ifndef OPENSSL_NO_RC4
-       printf("%s ",RC4_options());
+               printf("%s ",RC4_options());
 #endif
 #ifndef OPENSSL_NO_DES
-       printf("%s ",des_options());
+               printf("%s ",DES_options());
+#endif
+#ifndef OPENSSL_NO_AES
+               printf("%s ",AES_options());
 #endif
 #ifndef OPENSSL_NO_IDEA
-       printf("%s ",idea_options());
+               printf("%s ",idea_options());
 #endif
 #ifndef OPENSSL_NO_BF
-       printf("%s ",BF_options());
+               printf("%s ",BF_options());
 #endif
-       fprintf(stdout,"\n%s\n",SSLeay_version(SSLEAY_CFLAGS));
+               fprintf(stdout,"\n%s\n",SSLeay_version(SSLEAY_CFLAGS));
+               printf("available timing options: ");
+#ifdef TIMES
+               printf("TIMES ");
+#endif
+#ifdef TIMEB
+               printf("TIMEB ");
+#endif
+#ifdef USE_TOD
+               printf("USE_TOD ");
+#endif
+#ifdef HZ
+#define as_string(s) (#s)
+               printf("HZ=%g", (double)HZ);
+# ifdef _SC_CLK_TCK
+               printf(" [sysconf value]");
+# endif
+#endif
+               printf("\n");
+               printf("timing function used: %s%s%s%s%s%s%s\n",
+                      (ftime_used ? "ftime" : ""),
+                      (ftime_used + times_used > 1 ? "," : ""),
+                      (times_used ? "times" : ""),
+                      (ftime_used + times_used + gettimeofday_used > 1 ? "," : ""),
+                      (gettimeofday_used ? "gettimeofday" : ""),
+                      (ftime_used + times_used + gettimeofday_used + getrusage_used > 1 ? "," : ""),
+                      (getrusage_used ? "getrusage" : ""));
+               }
 
        if (pr_header)
                {
-               fprintf(stdout,"The 'numbers' are in 1000s of bytes per second processed.\n"); 
-               fprintf(stdout,"type        ");
+               if(mr)
+                       fprintf(stdout,"+H");
+               else
+                       {
+                       fprintf(stdout,"The 'numbers' are in 1000s of bytes per second processed.\n"); 
+                       fprintf(stdout,"type        ");
+                       }
                for (j=0;  j<SIZE_NUM; j++)
-                       fprintf(stdout,"%7d bytes",lengths[j]);
+                       fprintf(stdout,mr ? ":%d" : "%7d bytes",lengths[j]);
                fprintf(stdout,"\n");
                }
 
        for (k=0; k<ALGOR_NUM; k++)
                {
                if (!doit[k]) continue;
-               fprintf(stdout,"%-13s",names[k]);
+               if(mr)
+                       fprintf(stdout,"+F:%d:%s",k,names[k]);
+               else
+                       fprintf(stdout,"%-13s",names[k]);
                for (j=0; j<SIZE_NUM; j++)
                        {
-                       if (results[k][j] > 10000)
+                       if (results[k][j] > 10000 && !mr)
                                fprintf(stdout," %11.2fk",results[k][j]/1e3);
                        else
-                               fprintf(stdout," %11.2f ",results[k][j]);
+                               fprintf(stdout,mr ? ":%.2f" : " %11.2f ",results[k][j]);
                        }
                fprintf(stdout,"\n");
                }
@@ -1445,15 +1678,19 @@ int MAIN(int argc, char **argv)
        for (k=0; k<RSA_NUM; k++)
                {
                if (!rsa_doit[k]) continue;
-               if (j)
+               if (j && !mr)
                        {
                        printf("%18ssign    verify    sign/s verify/s\n"," ");
                        j=0;
                        }
-               fprintf(stdout,"rsa %4u bits %8.4fs %8.4fs %8.1f %8.1f",
-                       rsa_bits[k],rsa_results[k][0],rsa_results[k][1],
-                       1.0/rsa_results[k][0],1.0/rsa_results[k][1]);
-               fprintf(stdout,"\n");
+               if(mr)
+                       fprintf(stdout,"+F2:%u:%u:%f:%f\n",
+                               k,rsa_bits[k],rsa_results[k][0],
+                               rsa_results[k][1]);
+               else
+                       fprintf(stdout,"rsa %4u bits %8.4fs %8.4fs %8.1f %8.1f\n",
+                               rsa_bits[k],rsa_results[k][0],rsa_results[k][1],
+                               1.0/rsa_results[k][0],1.0/rsa_results[k][1]);
                }
 #endif
 #ifndef OPENSSL_NO_DSA
@@ -1461,14 +1698,18 @@ int MAIN(int argc, char **argv)
        for (k=0; k<DSA_NUM; k++)
                {
                if (!dsa_doit[k]) continue;
-               if (j)  {
+               if (j && !mr)
+                       {
                        printf("%18ssign    verify    sign/s verify/s\n"," ");
                        j=0;
                        }
-               fprintf(stdout,"dsa %4u bits %8.4fs %8.4fs %8.1f %8.1f",
-                       dsa_bits[k],dsa_results[k][0],dsa_results[k][1],
-                       1.0/dsa_results[k][0],1.0/dsa_results[k][1]);
-               fprintf(stdout,"\n");
+               if(mr)
+                       fprintf(stdout,"+F3:%u:%u:%f:%f\n",
+                               k,dsa_bits[k],dsa_results[k][0],dsa_results[k][1]);
+               else
+                       fprintf(stdout,"dsa %4u bits %8.4fs %8.4fs %8.1f %8.1f\n",
+                               dsa_bits[k],dsa_results[k][0],dsa_results[k][1],
+                               1.0/dsa_results[k][0],1.0/dsa_results[k][1]);
                }
 #endif
        mret=0;
@@ -1493,11 +1734,13 @@ end:
 static void print_message(const char *s, long num, int length)
        {
 #ifdef SIGALRM
-       BIO_printf(bio_err,"Doing %s for %ds on %d size blocks: ",s,SECONDS,length);
+       BIO_printf(bio_err,mr ? "+DT:%s:%d:%d\n"
+                  : "Doing %s for %ds on %d size blocks: ",s,SECONDS,length);
        (void)BIO_flush(bio_err);
        alarm(SECONDS);
 #else
-       BIO_printf(bio_err,"Doing %s %ld times on %d size blocks: ",s,num,length);
+       BIO_printf(bio_err,mr ? "+DN:%s:%ld:%d\n"
+                  : "Doing %s %ld times on %d size blocks: ",s,num,length);
        (void)BIO_flush(bio_err);
 #endif
 #ifdef LINT
@@ -1509,11 +1752,13 @@ static void pkey_print_message(char *str, char *str2, long num, int bits,
             int tm)
        {
 #ifdef SIGALRM
-       BIO_printf(bio_err,"Doing %d bit %s %s's for %ds: ",bits,str,str2,tm);
+       BIO_printf(bio_err,mr ? "+DTP:%d:%s:%s:%d\n"
+                          : "Doing %d bit %s %s's for %ds: ",bits,str,str2,tm);
        (void)BIO_flush(bio_err);
        alarm(RSA_SECONDS);
 #else
-       BIO_printf(bio_err,"Doing %ld %d bit %s %s's: ",num,bits,str,str2);
+       BIO_printf(bio_err,mr ? "+DNP:%ld:%d:%s:%s\n"
+                          : "Doing %ld %d bit %s %s's: ",num,bits,str,str2);
        (void)BIO_flush(bio_err);
 #endif
 #ifdef LINT
@@ -1521,3 +1766,175 @@ static void pkey_print_message(char *str, char *str2, long num, int bits,
 #endif
        }
 
+static void print_result(int alg,int run_no,int count,double time_used)
+       {
+       BIO_printf(bio_err,mr ? "+R:%ld:%s:%f\n"
+                  : "%ld %s's in %.2fs\n",count,names[alg],time_used);
+       results[alg][run_no]=((double)count)/time_used*lengths[run_no];
+       }
+
+static char *sstrsep(char **string, const char *delim)
+    {
+    char isdelim[256];
+    char *token = *string;
+
+    if (**string == 0)
+        return NULL;
+
+    memset(isdelim, 0, 256);
+    isdelim[0] = 1;
+
+    while (*delim)
+        {
+        isdelim[(unsigned char)(*delim)] = 1;
+        delim++;
+        }
+
+    while (!isdelim[(unsigned char)(**string)])
+        {
+        (*string)++;
+        }
+
+    if (**string)
+        {
+        **string = 0;
+        (*string)++;
+        }
+
+    return token;
+    }
+
+#ifdef HAVE_FORK
+static int do_multi(int multi)
+       {
+       int n;
+       int fd[2];
+       int *fds;
+       static char sep[]=":";
+
+       fds=malloc(multi*sizeof *fds);
+       for(n=0 ; n < multi ; ++n)
+               {
+               pipe(fd);
+               if(fork())
+                       {
+                       close(fd[1]);
+                       fds[n]=fd[0];
+                       }
+               else
+                       {
+                       close(fd[0]);
+                       close(1);
+                       dup(fd[1]);
+                       close(fd[1]);
+                       mr=1;
+                       usertime=0;
+                       return 0;
+                       }
+               printf("Forked child %d\n",n);
+               }
+
+       /* for now, assume the pipe is long enough to take all the output */
+       for(n=0 ; n < multi ; ++n)
+               {
+               FILE *f;
+               char buf[1024];
+               char *p;
+
+               f=fdopen(fds[n],"r");
+               while(fgets(buf,sizeof buf,f))
+                       {
+                       p=strchr(buf,'\n');
+                       if(p)
+                               *p='\0';
+                       if(buf[0] != '+')
+                               {
+                               fprintf(stderr,"Don't understand line '%s' from child %d\n",
+                                               buf,n);
+                               continue;
+                               }
+                       printf("Got: %s from %d\n",buf,n);
+                       if(!strncmp(buf,"+F:",3))
+                               {
+                               int alg;
+                               int j;
+
+                               p=buf+3;
+                               alg=atoi(sstrsep(&p,sep));
+                               sstrsep(&p,sep);
+                               for(j=0 ; j < SIZE_NUM ; ++j)
+                                       results[alg][j]+=atof(sstrsep(&p,sep));
+                               }
+                       else if(!strncmp(buf,"+F2:",4))
+                               {
+                               int k;
+                               double d;
+                               
+                               p=buf+4;
+                               k=atoi(sstrsep(&p,sep));
+                               sstrsep(&p,sep);
+
+                               d=atof(sstrsep(&p,sep));
+                               if(n)
+                                       rsa_results[k][0]=1/(1/rsa_results[k][0]+1/d);
+                               else
+                                       rsa_results[k][0]=d;
+
+                               d=atof(sstrsep(&p,sep));
+                               if(n)
+                                       rsa_results[k][1]=1/(1/rsa_results[k][1]+1/d);
+                               else
+                                       rsa_results[k][1]=d;
+                               }
+                       else if(!strncmp(buf,"+F2:",4))
+                               {
+                               int k;
+                               double d;
+                               
+                               p=buf+4;
+                               k=atoi(sstrsep(&p,sep));
+                               sstrsep(&p,sep);
+
+                               d=atof(sstrsep(&p,sep));
+                               if(n)
+                                       rsa_results[k][0]=1/(1/rsa_results[k][0]+1/d);
+                               else
+                                       rsa_results[k][0]=d;
+
+                               d=atof(sstrsep(&p,sep));
+                               if(n)
+                                       rsa_results[k][1]=1/(1/rsa_results[k][1]+1/d);
+                               else
+                                       rsa_results[k][1]=d;
+                               }
+                       else if(!strncmp(buf,"+F3:",4))
+                               {
+                               int k;
+                               double d;
+                               
+                               p=buf+4;
+                               k=atoi(sstrsep(&p,sep));
+                               sstrsep(&p,sep);
+
+                               d=atof(sstrsep(&p,sep));
+                               if(n)
+                                       dsa_results[k][0]=1/(1/dsa_results[k][0]+1/d);
+                               else
+                                       dsa_results[k][0]=d;
+
+                               d=atof(sstrsep(&p,sep));
+                               if(n)
+                                       dsa_results[k][1]=1/(1/dsa_results[k][1]+1/d);
+                               else
+                                       dsa_results[k][1]=d;
+                               }
+                       else if(!strncmp(buf,"+H:",3))
+                               {
+                               }
+                       else
+                               fprintf(stderr,"Unknown type '%s' from child %d\n",buf,n);
+                       }
+               }
+       return 1;
+       }
+#endif