benchHash.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * Hash benchmark module
  3. * Part of the xxHash project
  4. * Copyright (C) 2019-2020 Yann Collet
  5. *
  6. * GPL v2 License
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. *
  22. * You can contact the author at:
  23. * - xxHash homepage: https://www.xxhash.com
  24. * - xxHash source repository: https://github.com/Cyan4973/xxHash
  25. */
  26. /* benchmark hash functions */
  27. #include <stdlib.h> // malloc
  28. #include <assert.h>
  29. #include "benchHash.h"
  30. static void initBuffer(void* buffer, size_t size)
  31. {
  32. const unsigned long long k1 = 11400714785074694791ULL; /* 0b1001111000110111011110011011000110000101111010111100101010000111 */
  33. const unsigned long long k2 = 14029467366897019727ULL; /* 0b1100001010110010101011100011110100100111110101001110101101001111 */
  34. unsigned long long acc = k2;
  35. unsigned char* const p = (unsigned char*)buffer;
  36. for (size_t s = 0; s < size; s++) {
  37. acc *= k1;
  38. p[s] = (unsigned char)(acc >> 56);
  39. }
  40. }
  41. #define MARGIN_FOR_LATENCY 1024
  42. #define START_MASK (MARGIN_FOR_LATENCY-1)
  43. typedef size_t (*sizeFunction_f)(size_t targetSize);
  44. /*
  45. * bench_hash_internal():
  46. * Benchmarks hashfn repeateadly over single input of size `size`
  47. * return: nb of hashes per second
  48. */
  49. static double
  50. bench_hash_internal(BMK_benchFn_t hashfn, void* payload,
  51. size_t nbBlocks, sizeFunction_f selectSize, size_t size,
  52. unsigned total_time_ms, unsigned iter_time_ms)
  53. {
  54. BMK_timedFnState_shell shell;
  55. BMK_timedFnState_t* const txf = BMK_initStatic_timedFnState(&shell, sizeof(shell), total_time_ms, iter_time_ms);
  56. assert(txf != NULL);
  57. size_t const srcSize = (size_t)size;
  58. size_t const srcBufferSize = srcSize + MARGIN_FOR_LATENCY;
  59. void* const srcBuffer = malloc(srcBufferSize);
  60. assert(srcBuffer != NULL);
  61. initBuffer(srcBuffer, srcBufferSize);
  62. #define FAKE_DSTSIZE 32
  63. size_t const dstSize = FAKE_DSTSIZE;
  64. char dstBuffer_static[FAKE_DSTSIZE] = {0};
  65. #define NB_BLOCKS_MAX 1024
  66. const void* srcBuffers[NB_BLOCKS_MAX];
  67. size_t srcSizes[NB_BLOCKS_MAX];
  68. void* dstBuffers[NB_BLOCKS_MAX];
  69. size_t dstCapacities[NB_BLOCKS_MAX];
  70. assert(nbBlocks < NB_BLOCKS_MAX);
  71. assert(size > 0);
  72. for (size_t n=0; n < nbBlocks; n++) {
  73. srcBuffers[n] = srcBuffer;
  74. srcSizes[n] = selectSize(size);
  75. dstBuffers[n] = dstBuffer_static;
  76. dstCapacities[n] = dstSize;
  77. }
  78. BMK_benchParams_t params = {
  79. .benchFn = hashfn,
  80. .benchPayload = payload,
  81. .initFn = NULL,
  82. .initPayload = NULL,
  83. .errorFn = NULL,
  84. .blockCount = nbBlocks,
  85. .srcBuffers = srcBuffers,
  86. .srcSizes = srcSizes,
  87. .dstBuffers = dstBuffers,
  88. .dstCapacities = dstCapacities,
  89. .blockResults = NULL
  90. };
  91. BMK_runOutcome_t result;
  92. while (!BMK_isCompleted_TimedFn(txf)) {
  93. result = BMK_benchTimedFn(txf, params);
  94. assert(BMK_isSuccessful_runOutcome(result));
  95. }
  96. BMK_runTime_t const runTime = BMK_extract_runTime(result);
  97. free(srcBuffer);
  98. assert(runTime.nanoSecPerRun != 0);
  99. return (1000000000U / runTime.nanoSecPerRun) * nbBlocks;
  100. }
  101. static size_t rand_1_N(size_t N) { return ((size_t)rand() % N) + 1; }
  102. static size_t identity(size_t s) { return s; }
  103. static size_t
  104. benchLatency(const void* src, size_t srcSize,
  105. void* dst, size_t dstCapacity,
  106. void* customPayload)
  107. {
  108. (void)dst; (void)dstCapacity;
  109. BMK_benchFn_t benchfn = (BMK_benchFn_t)customPayload;
  110. static size_t hash = 0;
  111. const void* const start = (const char*)src + (hash & START_MASK);
  112. return hash = benchfn(start, srcSize, dst, dstCapacity, NULL);
  113. }
  114. #ifndef SIZE_TO_HASH_PER_ROUND
  115. # define SIZE_TO_HASH_PER_ROUND 200000
  116. #endif
  117. #ifndef NB_HASH_ROUNDS_MAX
  118. # define NB_HASH_ROUNDS_MAX 1000
  119. #endif
  120. double bench_hash(BMK_benchFn_t hashfn,
  121. BMK_benchMode benchMode,
  122. size_t size, BMK_sizeMode sizeMode,
  123. unsigned total_time_ms, unsigned iter_time_ms)
  124. {
  125. sizeFunction_f const sizef = (sizeMode == BMK_fixedSize) ? identity : rand_1_N;
  126. BMK_benchFn_t const benchfn = (benchMode == BMK_throughput) ? hashfn : benchLatency;
  127. BMK_benchFn_t const payload = (benchMode == BMK_throughput) ? NULL : hashfn;
  128. size_t nbBlocks = (SIZE_TO_HASH_PER_ROUND / size) + 1;
  129. if (nbBlocks > NB_HASH_ROUNDS_MAX) nbBlocks = NB_HASH_ROUNDS_MAX;
  130. return bench_hash_internal(benchfn, payload,
  131. nbBlocks, sizef, size,
  132. total_time_ms, iter_time_ms);
  133. }