idlebox / 2008 / 0714-cryptography-speedtest-comparison / crypto-speedtest-0.1 / src / speedtest.h.html (Download File)
// $Id: speedtest.h 223 2008-04-07 16:56:58Z tb $
// Not really an include file, more a base file for the speed tests.

#include <assert.h>
#include <stdint.h>
#include <math.h>
#include <time.h>

#include <vector>
#include <map>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <numeric>
#include <cmath>
#include <algorithm>
#include <limits>

// *** Speedtest Parameters ***

// speed test different buffer sizes in this range
const unsigned int buffermin = 16;
const unsigned int buffermax = 16 * 65536;
const unsigned int baserepeatsize = 65536;
const unsigned int minrepeats = 4;
const unsigned int measureruns = 16;

#ifndef _MSC_VER
#include <sys/time.h>
#else
#include <windows.h>
#endif

/// Time is measured using gettimeofday() or GetTickCount()
inline double timestamp()
{
#ifndef _MSC_VER
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec + tv.tv_usec * 0.000001;
#else
    return timeGetTime() / 1000.0;
#endif
}

// *** Global Buffers and Settings for the Speedtest Functions ***

unsigned char   enckey[32];     /// 256 bit encryption key
unsigned char   enciv[16];      /// 16 byte initialization vector if needed.

unsigned char   buffer[buffermax];      /// encryption buffer
unsigned int    bufferlen;              /// currently tested buffer length

// *** run_test() ***

/**
 * This function will run a test routine multiple times with different buffer

 * sizes configured. It measures the time required to encrypt a number of
 * bytes. The average time and standard deviation are calculated and written to
 * a log file for gnuplot.
 */

template <void (*testfunc)()>
void run_test(const char* logfile)
{
    std::cout << "Speed testing for " << logfile << "\n";

    // Save the time required for each run.
    std::map<unsigned int, std::vector<double> > timelog;
       
    for(unsigned int fullrun = 0; fullrun < measureruns; ++fullrun)
    {
        unsigned int repeatsize = baserepeatsize;

        for(unsigned int bufflen = buffermin; bufflen <= buffermax; bufflen *= 2)
        {
REDO:
            // because small time measurements are inaccurate, repeat very fast
            // tests until the same amount of data is encrypted as in the large
            // tests.
            unsigned int repeat = repeatsize / bufflen;
            if (repeat < minrepeats) repeat = minrepeats;

            // std::cout << "Test: bufflen " << bufflen << " repeat " << repeat << "\n";

            bufferlen = bufflen;

            // fill buffer
            for(unsigned int i = 0; i < bufferlen; ++i)
                buffer[i] = (uint8_t)i;

            double ts1 = timestamp();

            for(unsigned int testrun = 0; testrun < repeat; ++testrun)
            {
                testfunc();
            }

            double ts2 = timestamp();

            double tsdelta = ts2 - ts1;

            // Adapt number of repetitions to the clock's accuracy.
            if (tsdelta < 0.5) {
                printf("Run %d bufferlen %d repeat %d took only %.2f sec. Increasing repetitons.\n",
                       fullrun, bufferlen, repeat, tsdelta);
                repeatsize *= 2;
                goto REDO;
            }
            else {
                printf("Run %d bufferlen %d repeat %d took %.2f sec.\n",
                       fullrun, bufferlen, repeat, tsdelta);
            }

            // check buffer status after repeated en/decryption
            for(unsigned int i = 0; i < bufferlen; ++i)
                assert(buffer[i] == (uint8_t)i);

            timelog[bufferlen].push_back( tsdelta / (double)repeat );
        }
    }

    // Calculate and output statistics.
    std::ofstream of (logfile);

    // First output time absolute measurements
    for(std::map<unsigned int, std::vector<double> >::const_iterator ti = timelog.begin();
        ti != timelog.end(); ++ti)
    {
        const std::vector<double>& timelist = ti->second;

        double average = std::accumulate(timelist.begin(), timelist.end(), 0.0) / timelist.size();

        double variance = 0.0;
        for(unsigned int i = 0; i < timelist.size(); ++i)
        {
            variance += (timelist[i] - average) * (timelist[i] - average);
        }
        variance = variance / (timelist.size() - 1);

        double stddev = std::sqrt(variance);

        if (timelist.size() == 1) { // only one run -> no variance or stddev
            variance = stddev = 0.0;
        }

        double vmin = *std::min_element(timelist.begin(), timelist.end());
        double vmax = *std::max_element(timelist.begin(), timelist.end());

        of << std::setprecision(16);
        of << ti->first << " " << average << " " << stddev << " " << vmin << " " << vmax << "\n";
    }
    of << "\n\n";

    // Second output speed measurements
    for(std::map<unsigned int, std::vector<double> >::const_iterator ti = timelog.begin();
        ti != timelog.end(); ++ti)
    {
        const std::vector<double>& timelist = ti->second;

        double average = 0.0;
        double vmin = std::numeric_limits<double>::infinity();
        double vmax = 0;

        for(unsigned int i = 0; i < timelist.size(); ++i)
        {
            average += (double)ti->first / timelist[i];
            vmin = std::min<double>(vmin, (double)ti->first / timelist[i]);
            vmax = std::max<double>(vmax, (double)ti->first / timelist[i]);
        }
        average /= timelist.size();

        double variance = 0.0;
        for(unsigned int i = 0; i < timelist.size(); ++i)
        {
            double delta = ((double)ti->first / timelist[i]) - average;
            variance += delta * delta;
        }
        variance = variance / (timelist.size() - 1);

        double stddev = std::sqrt(variance);

        if (timelist.size() == 1) { // only one run -> no variance or stddev
            variance = stddev = 0.0;
        }

        of << std::setprecision(16);
        of << ti->first << " " << average << " " << stddev << " " << vmin << " " << vmax << "\n";
    }
    of.close();
}
RSS 2.0 Weblog Feed Atom 1.0 Weblog Feed Valid XHTML 1.1 Valid CSS (2.1)