Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

399 lines
14 KiB

  1. // bench.cpp - written and placed in the public domain by Wei Dai
  2. #include "cryptlib.h"
  3. #include "bench.h"
  4. #include "validate.h"
  5. #include "aes.h"
  6. #include "blumshub.h"
  7. #include "files.h"
  8. #include "filters.h"
  9. #include "hex.h"
  10. #include "modes.h"
  11. #include "factory.h"
  12. #include "smartptr.h"
  13. #include "cpu.h"
  14. #include <time.h>
  15. #include <math.h>
  16. #include <iostream>
  17. #include <sstream>
  18. #include <iomanip>
  19. // These are noisy enoguh due to test.cpp. Turn them off here.
  20. #if CRYPTOPP_GCC_DIAGNOSTIC_AVAILABLE
  21. # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
  22. #endif
  23. USING_NAMESPACE(CryptoPP)
  24. USING_NAMESPACE(std)
  25. #ifdef CLOCKS_PER_SEC
  26. const double CLOCK_TICKS_PER_SECOND = (double)CLOCKS_PER_SEC;
  27. #elif defined(CLK_TCK)
  28. const double CLOCK_TICKS_PER_SECOND = (double)CLK_TCK;
  29. #else
  30. const double CLOCK_TICKS_PER_SECOND = 1000000.0;
  31. #endif
  32. double logtotal = 0.0, g_allocatedTime = 0, g_hertz = 0;
  33. unsigned int logcount = 0;
  34. static const byte defaultKey[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  35. "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
  36. void OutputResultBytes(const char *name, double length, double timeTaken)
  37. {
  38. // Coverity finding (http://stackoverflow.com/a/30968371 does not squash the finding)
  39. std::ostringstream out;
  40. out.copyfmt(cout);
  41. // Coverity finding
  42. if (length < 0.0000000001f) length = 0.000001f;
  43. if (timeTaken < 0.0000000001f) timeTaken = 0.000001f;
  44. double mbs = length / timeTaken / (1024*1024);
  45. out << "\n<TR><TH>" << name;
  46. // out << "<TD>" << setprecision(3) << length / (1024*1024);
  47. out << setiosflags(ios::fixed);
  48. // out << "<TD>" << setprecision(3) << timeTaken;
  49. out << "<TD>" << setprecision(0) << setiosflags(ios::fixed) << mbs;
  50. if (g_hertz)
  51. out << "<TD>" << setprecision(1) << setiosflags(ios::fixed) << timeTaken * g_hertz / length;
  52. logtotal += log(mbs);
  53. logcount++;
  54. cout << out.str();
  55. }
  56. void OutputResultKeying(double iterations, double timeTaken)
  57. {
  58. // Coverity finding (http://stackoverflow.com/a/30968371 does not squash the finding)
  59. std::ostringstream out;
  60. out.copyfmt(cout);
  61. // Coverity finding
  62. if (iterations < 0.0000000001f) iterations = 0.000001f;
  63. if (timeTaken < 0.0000000001f) timeTaken = 0.000001f;
  64. out << "<TD>" << setprecision(3) << setiosflags(ios::fixed) << (1000*1000*timeTaken/iterations);
  65. if (g_hertz)
  66. out << "<TD>" << setprecision(0) << setiosflags(ios::fixed) << timeTaken * g_hertz / iterations;
  67. cout << out.str();
  68. }
  69. void OutputResultOperations(const char *name, const char *operation, bool pc, unsigned long iterations, double timeTaken)
  70. {
  71. // Coverity finding (http://stackoverflow.com/a/30968371 does not squash the finding)
  72. std::ostringstream out;
  73. out.copyfmt(cout);
  74. // Coverity finding
  75. if (!iterations) iterations++;
  76. if (timeTaken < 0.0000000001f) timeTaken = 0.000001f;
  77. out << "\n<TR><TH>" << name << " " << operation << (pc ? " with precomputation" : "");
  78. out << "<TD>" << setprecision(2) << setiosflags(ios::fixed) << (1000*timeTaken/iterations);
  79. if (g_hertz)
  80. out << "<TD>" << setprecision(2) << setiosflags(ios::fixed) << timeTaken * g_hertz / iterations / 1000000;
  81. logtotal += log(iterations/timeTaken);
  82. logcount++;
  83. cout << out.str();
  84. }
  85. /*
  86. void BenchMark(const char *name, BlockTransformation &cipher, double timeTotal)
  87. {
  88. const int BUF_SIZE = RoundUpToMultipleOf(2048U, cipher.OptimalNumberOfParallelBlocks() * cipher.BlockSize());
  89. AlignedSecByteBlock buf(BUF_SIZE);
  90. const int nBlocks = BUF_SIZE / cipher.BlockSize();
  91. clock_t start = clock();
  92. unsigned long i=0, blocks=1;
  93. double timeTaken;
  94. do
  95. {
  96. blocks *= 2;
  97. for (; i<blocks; i++)
  98. cipher.ProcessAndXorMultipleBlocks(buf, NULL, buf, nBlocks);
  99. timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
  100. }
  101. while (timeTaken < 2.0/3*timeTotal);
  102. OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
  103. }
  104. */
  105. void BenchMark(const char *name, StreamTransformation &cipher, double timeTotal)
  106. {
  107. const int BUF_SIZE=RoundUpToMultipleOf(2048U, cipher.OptimalBlockSize());
  108. AlignedSecByteBlock buf(BUF_SIZE);
  109. GlobalRNG().GenerateBlock(buf, BUF_SIZE);
  110. clock_t start = clock();
  111. unsigned long i=0, blocks=1;
  112. double timeTaken;
  113. do
  114. {
  115. blocks *= 2;
  116. for (; i<blocks; i++)
  117. cipher.ProcessString(buf, BUF_SIZE);
  118. timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
  119. }
  120. while (timeTaken < 2.0/3*timeTotal);
  121. OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
  122. }
  123. void BenchMark(const char *name, AuthenticatedSymmetricCipher &cipher, double timeTotal)
  124. {
  125. if (cipher.NeedsPrespecifiedDataLengths())
  126. cipher.SpecifyDataLengths(0, cipher.MaxMessageLength(), 0);
  127. BenchMark(name, static_cast<StreamTransformation &>(cipher), timeTotal);
  128. }
  129. void BenchMark(const char *name, HashTransformation &ht, double timeTotal)
  130. {
  131. const int BUF_SIZE=2048U;
  132. AlignedSecByteBlock buf(BUF_SIZE);
  133. GlobalRNG().GenerateBlock(buf, BUF_SIZE);
  134. clock_t start = clock();
  135. unsigned long i=0, blocks=1;
  136. double timeTaken;
  137. do
  138. {
  139. blocks *= 2;
  140. for (; i<blocks; i++)
  141. ht.Update(buf, BUF_SIZE);
  142. timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
  143. }
  144. while (timeTaken < 2.0/3*timeTotal);
  145. OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
  146. }
  147. void BenchMark(const char *name, BufferedTransformation &bt, double timeTotal)
  148. {
  149. const int BUF_SIZE=2048U;
  150. AlignedSecByteBlock buf(BUF_SIZE);
  151. GlobalRNG().GenerateBlock(buf, BUF_SIZE);
  152. clock_t start = clock();
  153. unsigned long i=0, blocks=1;
  154. double timeTaken;
  155. do
  156. {
  157. blocks *= 2;
  158. for (; i<blocks; i++)
  159. bt.Put(buf, BUF_SIZE);
  160. timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
  161. }
  162. while (timeTaken < 2.0/3*timeTotal);
  163. OutputResultBytes(name, double(blocks) * BUF_SIZE, timeTaken);
  164. }
  165. void BenchMarkKeying(SimpleKeyingInterface &c, size_t keyLength, const NameValuePairs &params)
  166. {
  167. unsigned long iterations = 0;
  168. clock_t start = clock();
  169. double timeTaken;
  170. do
  171. {
  172. for (unsigned int i=0; i<1024; i++)
  173. c.SetKey(defaultKey, keyLength, params);
  174. timeTaken = double(clock() - start) / CLOCK_TICKS_PER_SECOND;
  175. iterations += 1024;
  176. }
  177. while (timeTaken < g_allocatedTime);
  178. OutputResultKeying(iterations, timeTaken);
  179. }
  180. //VC60 workaround: compiler bug triggered without the extra dummy parameters
  181. // on VC60 also needs to be named differently from BenchMarkByName
  182. template <class T_FactoryOutput, class T_Interface>
  183. void BenchMarkByName2(const char *factoryName, size_t keyLength = 0, const char *displayName=NULL, const NameValuePairs &params = g_nullNameValuePairs, T_FactoryOutput *x=NULL, T_Interface *y=NULL)
  184. {
  185. CRYPTOPP_UNUSED(x), CRYPTOPP_UNUSED(y), CRYPTOPP_UNUSED(params);
  186. std::string name(factoryName ? factoryName : "");
  187. member_ptr<T_FactoryOutput> obj(ObjectFactoryRegistry<T_FactoryOutput>::Registry().CreateObject(name.c_str()));
  188. if (!keyLength)
  189. keyLength = obj->DefaultKeyLength();
  190. if (displayName)
  191. name = displayName;
  192. else if (keyLength)
  193. name += " (" + IntToString(keyLength * 8) + "-bit key)";
  194. obj->SetKey(defaultKey, keyLength, CombinedNameValuePairs(params, MakeParameters(Name::IV(), ConstByteArrayParameter(defaultKey, obj->IVSize()), false)));
  195. BenchMark(name.c_str(), *static_cast<T_Interface *>(obj.get()), g_allocatedTime);
  196. BenchMarkKeying(*obj, keyLength, CombinedNameValuePairs(params, MakeParameters(Name::IV(), ConstByteArrayParameter(defaultKey, obj->IVSize()), false)));
  197. }
  198. //VC60 workaround: compiler bug triggered without the extra dummy parameters
  199. template <class T_FactoryOutput>
  200. void BenchMarkByName(const char *factoryName, size_t keyLength = 0, const char *displayName=NULL, const NameValuePairs &params = g_nullNameValuePairs, T_FactoryOutput *x=NULL)
  201. {
  202. CRYPTOPP_UNUSED(x), CRYPTOPP_UNUSED(params);
  203. BenchMarkByName2<T_FactoryOutput, T_FactoryOutput>(factoryName, keyLength, displayName, params, x, x);
  204. }
  205. template <class T>
  206. void BenchMarkByNameKeyLess(const char *factoryName, const char *displayName=NULL, const NameValuePairs &params = g_nullNameValuePairs, T *x=NULL)
  207. {
  208. CRYPTOPP_UNUSED(x), CRYPTOPP_UNUSED(params);
  209. std::string name = factoryName;
  210. if (displayName)
  211. name = displayName;
  212. member_ptr<T> obj(ObjectFactoryRegistry<T>::Registry().CreateObject(factoryName));
  213. BenchMark(name.c_str(), *obj, g_allocatedTime);
  214. }
  215. void BenchmarkAll(double t, double hertz)
  216. {
  217. #if 1
  218. logtotal = 0;
  219. logcount = 0;
  220. g_allocatedTime = t;
  221. g_hertz = hertz;
  222. const char *cpb, *cpk;
  223. if (g_hertz)
  224. {
  225. cpb = "<TH>Cycles Per Byte";
  226. cpk = "<TH>Cycles to<br>Setup Key and IV";
  227. cout << "CPU frequency of the test platform is " << g_hertz << " Hz.\n";
  228. }
  229. else
  230. {
  231. cpb = cpk = "";
  232. cout << "CPU frequency of the test platform was not provided.\n";
  233. }
  234. cout << "<TABLE border=1><COLGROUP><COL align=left><COL align=right><COL align=right><COL align=right><COL align=right>" << endl;
  235. cout << "<THEAD><TR><TH>Algorithm<TH>MiB/Second" << cpb << "<TH>Microseconds to<br>Setup Key and IV" << cpk << endl;
  236. cout << "\n<TBODY style=\"background: yellow\">";
  237. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  238. if (HasCLMUL())
  239. BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM");
  240. else
  241. #endif
  242. {
  243. BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM (2K tables)", MakeParameters(Name::TableSize(), 2048));
  244. BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/GCM", 0, "AES/GCM (64K tables)", MakeParameters(Name::TableSize(), 64*1024));
  245. }
  246. BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/CCM");
  247. BenchMarkByName2<AuthenticatedSymmetricCipher, AuthenticatedSymmetricCipher>("AES/EAX");
  248. cout << "\n<TBODY style=\"background: white\">";
  249. #if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
  250. if (HasCLMUL())
  251. BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES)");
  252. else
  253. #endif
  254. {
  255. BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES) (2K tables)", MakeParameters(Name::TableSize(), 2048));
  256. BenchMarkByName2<AuthenticatedSymmetricCipher, MessageAuthenticationCode>("AES/GCM", 0, "GMAC(AES) (64K tables)", MakeParameters(Name::TableSize(), 64*1024));
  257. }
  258. BenchMarkByName<MessageAuthenticationCode>("VMAC(AES)-64");
  259. BenchMarkByName<MessageAuthenticationCode>("VMAC(AES)-128");
  260. BenchMarkByName<MessageAuthenticationCode>("HMAC(SHA-1)");
  261. BenchMarkByName<MessageAuthenticationCode>("Two-Track-MAC");
  262. BenchMarkByName<MessageAuthenticationCode>("CMAC(AES)");
  263. BenchMarkByName<MessageAuthenticationCode>("DMAC(AES)");
  264. cout << "\n<TBODY style=\"background: yellow\">";
  265. BenchMarkByNameKeyLess<HashTransformation>("CRC32");
  266. BenchMarkByNameKeyLess<HashTransformation>("Adler32");
  267. BenchMarkByNameKeyLess<HashTransformation>("MD5");
  268. BenchMarkByNameKeyLess<HashTransformation>("SHA-1");
  269. BenchMarkByNameKeyLess<HashTransformation>("SHA-256");
  270. BenchMarkByNameKeyLess<HashTransformation>("SHA-512");
  271. BenchMarkByNameKeyLess<HashTransformation>("SHA-3-224");
  272. BenchMarkByNameKeyLess<HashTransformation>("SHA-3-256");
  273. BenchMarkByNameKeyLess<HashTransformation>("SHA-3-384");
  274. BenchMarkByNameKeyLess<HashTransformation>("SHA-3-512");
  275. BenchMarkByNameKeyLess<HashTransformation>("Tiger");
  276. BenchMarkByNameKeyLess<HashTransformation>("Whirlpool");
  277. BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-160");
  278. BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-320");
  279. BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-128");
  280. BenchMarkByNameKeyLess<HashTransformation>("RIPEMD-256");
  281. cout << "\n<TBODY style=\"background: white\">";
  282. BenchMarkByName<SymmetricCipher>("Panama-LE");
  283. BenchMarkByName<SymmetricCipher>("Panama-BE");
  284. BenchMarkByName<SymmetricCipher>("Salsa20");
  285. BenchMarkByName<SymmetricCipher>("Salsa20", 0, "Salsa20/12", MakeParameters(Name::Rounds(), 12));
  286. BenchMarkByName<SymmetricCipher>("Salsa20", 0, "Salsa20/8", MakeParameters(Name::Rounds(), 8));
  287. BenchMarkByName<SymmetricCipher>("Sosemanuk");
  288. BenchMarkByName<SymmetricCipher>("MARC4");
  289. BenchMarkByName<SymmetricCipher>("SEAL-3.0-LE");
  290. BenchMarkByName<SymmetricCipher>("WAKE-OFB-LE");
  291. cout << "\n<TBODY style=\"background: yellow\">";
  292. BenchMarkByName<SymmetricCipher>("AES/CTR", 16);
  293. BenchMarkByName<SymmetricCipher>("AES/CTR", 24);
  294. BenchMarkByName<SymmetricCipher>("AES/CTR", 32);
  295. BenchMarkByName<SymmetricCipher>("AES/CBC", 16);
  296. BenchMarkByName<SymmetricCipher>("AES/CBC", 24);
  297. BenchMarkByName<SymmetricCipher>("AES/CBC", 32);
  298. BenchMarkByName<SymmetricCipher>("AES/OFB", 16);
  299. BenchMarkByName<SymmetricCipher>("AES/CFB", 16);
  300. BenchMarkByName<SymmetricCipher>("AES/ECB", 16);
  301. BenchMarkByName<SymmetricCipher>("Camellia/CTR", 16);
  302. BenchMarkByName<SymmetricCipher>("Camellia/CTR", 32);
  303. BenchMarkByName<SymmetricCipher>("Twofish/CTR");
  304. BenchMarkByName<SymmetricCipher>("Serpent/CTR");
  305. BenchMarkByName<SymmetricCipher>("CAST-256/CTR");
  306. BenchMarkByName<SymmetricCipher>("RC6/CTR");
  307. BenchMarkByName<SymmetricCipher>("MARS/CTR");
  308. BenchMarkByName<SymmetricCipher>("SHACAL-2/CTR", 16);
  309. BenchMarkByName<SymmetricCipher>("SHACAL-2/CTR", 64);
  310. BenchMarkByName<SymmetricCipher>("DES/CTR");
  311. BenchMarkByName<SymmetricCipher>("DES-XEX3/CTR");
  312. BenchMarkByName<SymmetricCipher>("DES-EDE3/CTR");
  313. BenchMarkByName<SymmetricCipher>("IDEA/CTR");
  314. BenchMarkByName<SymmetricCipher>("RC5/CTR", 0, "RC5 (r=16)");
  315. BenchMarkByName<SymmetricCipher>("Blowfish/CTR");
  316. BenchMarkByName<SymmetricCipher>("TEA/CTR");
  317. BenchMarkByName<SymmetricCipher>("XTEA/CTR");
  318. BenchMarkByName<SymmetricCipher>("CAST-128/CTR");
  319. BenchMarkByName<SymmetricCipher>("SKIPJACK/CTR");
  320. BenchMarkByName<SymmetricCipher>("SEED/CTR", 0, "SEED/CTR (1/2 K table)");
  321. cout << "</TABLE>" << endl;
  322. BenchmarkAll2(t, hertz);
  323. cout << "Throughput Geometric Average: " << setiosflags(ios::fixed) << exp(logtotal/(logcount ? logcount : 1)) << endl;
  324. // Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55
  325. #if (CRYPTOPP_MSC_VERSION >= 1400)
  326. tm localTime = {};
  327. char timeBuf[64];
  328. errno_t err;
  329. const time_t endTime = time(NULL);
  330. err = localtime_s(&localTime, &endTime);
  331. assert(err == 0);
  332. err = asctime_s(timeBuf, sizeof(timeBuf), &localTime);
  333. assert(err == 0);
  334. cout << "\nTest ended at " << timeBuf;
  335. #else
  336. const time_t endTime = time(NULL);
  337. cout << "\nTest ended at " << asctime(localtime(&endTime));
  338. #endif
  339. #endif
  340. }