为什么 Crypto++ 中的 AES 代码会给出不同的性能结果?

Why AES code in Crypto++ gives different performance results?

我正在尝试测试 AES 加密的性能。但是每当我 运行 它给出不同的代码时 results.Why? 这是使用 Crypto++ 的 C++ 代码:

 int main(int argc, char* argv[]){
AutoSeededRandomPool prng;

byte key[AES::DEFAULT_KEYLENGTH];
prng.GenerateBlock(key, sizeof(key));

byte iv[AES::BLOCKSIZE];
prng.GenerateBlock(iv, sizeof(iv));

CBC_Mode< AES >::Encryption e;
e.SetKeyWithIV(key, sizeof(key), iv);

CBC_Mode< AES >::Decryption d;
d.SetKeyWithIV(key, sizeof(key), iv);

时间测试在这里:

  clock_t startTime, finishTime;    
std::string plain = "AES CBC Test";   
std::string cipher, encoded, recovered;   
startTime = clock();    
try
{

    // The StreamTransformationFilter removes
    //  padding as required.
    StringSource s(plain, true, 
        new StreamTransformationFilter(e,
            new StringSink(cipher)
        ) // StreamTransformationFilter
    ); // StringSource

}
catch(const CryptoPP::Exception& e)
{
    cerr << e.what() << endl;
    exit(1);
}    
    // save current time just after finishing the encryption loop
finishTime = clock();

我的测试结果在这里:

enter code heredouble executionTimeInSec = double( finishTime - startTime ) / CLOCK_TICKS_PER_SECOND;    

std::cout << "Encryption loop execution time: " << executionTimeInSec * 1000.0 << " microseconds." << std::endl;

std::cout << "Plain text size: " << plain.size() << " bytes." << std::endl;

double data_rate_MiBps = ((double)plain.size() / 1048576) / ((double)executionTimeInSec) ;

std::cout << "Encryption/decryption loop execution time MB/S: " << data_rate_MiBps << " MB/S." << std::endl; 
return 0;}

计时未优化的调试版本。 编译结果1:

加密循环执行时间:0.041 微秒。

编译结果2:

加密循环执行时间:0.057 微秒。

0.041 微秒对于测试来说太短了。要获得可靠的度量,您需要执行多次测试迭代,然后将总时间除以迭代次数。

在如此短的时间范围内进行衡量时,许多因素可能会打乱您的时间安排:

  1. 您系统上的时钟分辨率可能不够高,导致您的测量值相对较大。
  2. 您的计时仅衡量经过的时间,而不是 运行 在 CPU 上花费的实际时间。 OS 将您的 CPU 分配给一项测试中的其他内容而不是另一项测试的影响在测量中引入了巨大的波动。当进行多次迭代时,您可以在多次迭代中消除这种随机影响,从而消除机会的影响。
  3. 等等

与 Crypto++ 基准测试相关,该库在 cryptest.exe 中提供了一个基准套件。你像下面这样调用它。 b表示基准3 表示 运行 测试 3 秒; 2.4 表示 cpu 频率为 2.4 GHz。

./cryptest.exe b 3 2.4

下面的命令produces output similar to

您可以在 bench1.cpp and bench2.cpp 找到源代码。对于 AES,您要检查 bench2.cpp。这是负责生成数字的代码:

void BenchMark(const char *name, StreamTransformation &cipher, double timeTotal)
{
    const int BUF_SIZE=RoundUpToMultipleOf(2048U, cipher.OptimalBlockSize());
    AlignedSecByteBlock buf(BUF_SIZE);
    Test::GlobalRNG().GenerateBlock(buf, BUF_SIZE);

    unsigned long i=0, blocks=1;
    double timeTaken;

    clock_t start = ::clock();
    do
    {
        blocks *= 2;
        for (; i<blocks; i++)
            cipher.ProcessString(buf, BUF_SIZE);
        timeTaken = double(::clock() - start) / CLOCK_TICKS_PER_SECOND;
    }
    while (timeTaken < 2.0/3*timeTotal);

    OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
}

在使用 StreamTransformation 调用 BenchMark 之前,工厂方法创建了一个 AES 对象并将其键入以进行测试。


最近更改了一些基准测试代码,但主要是装饰性的。最大的变化是添加了随机数生成器来测试它们的性能。另请参阅用户列表中的 RNG Benchmarks and rework of RDRAND/RDSEED


进行基准测试时,您还应该注意 Turbo Boost 和其他相关技术的影响。如果您的 CPU 运行s 在 3.5 GHz 但在 3.8 GHz 时爆发,那么它将影响预期的吞吐量。有时,它使基准成为一个移动的目标,有时它可以解释为什么你超过了理论最大值。

突发只是内部超频。英特尔多年来一直这样做。他们曾经在旧的 P5 Pentium 中称其为 NetBurst。通过使用支持超频的主板和处理器,硬件专家和游戏玩家一直在这样做。