test_ds_cpp.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. #include <stdio.h>
  2. #ifdef DS_TEST
  3. #define STBDS_UNIT_TESTS
  4. #endif
  5. #ifdef DS_STATS
  6. #define STBDS_STATISTICS
  7. #endif
  8. #ifndef DS_PERF
  9. #define STBDS_ASSERT assert
  10. #include <assert.h>
  11. #endif
  12. //#define STBDS_SIPHASH_2_4
  13. #define STB_DS_IMPLEMENTATION
  14. #include "../stb_ds.h"
  15. size_t churn_inserts, churn_deletes;
  16. void churn(int a, int b, int count)
  17. {
  18. struct { int key,value; } *map=NULL;
  19. int i,j,n,k;
  20. for (i=0; i < a; ++i)
  21. hmput(map,i,i+1);
  22. for (n=0; n < count; ++n) {
  23. for (j=a; j < b; ++j,++i) {
  24. hmput(map,i,i+1);
  25. }
  26. assert(hmlen(map) == b);
  27. for (j=a; j < b; ++j) {
  28. k=i-j-1;
  29. k = hmdel(map,k);
  30. assert(k != 0);
  31. }
  32. assert(hmlen(map) == a);
  33. }
  34. hmfree(map);
  35. churn_inserts = i;
  36. churn_deletes = (b-a) * n;
  37. }
  38. #ifdef DS_TEST
  39. #include <stdio.h>
  40. int main(int argc, char **argv)
  41. {
  42. stbds_unit_tests();
  43. churn(0,100,1);
  44. churn(3,7,50000);
  45. churn(3,15,50000);
  46. churn(16, 48, 25000);
  47. churn(10, 15, 25000);
  48. churn(200,500, 5000);
  49. churn(2000,5000, 500);
  50. churn(20000,50000, 50);
  51. printf("Ok!");
  52. return 0;
  53. }
  54. #endif
  55. #ifdef DS_STATS
  56. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  57. size_t max_hit_probes, max_miss_probes, total_put_probes, total_miss_probes, churn_misses;
  58. void churn_stats(int a, int b, int count)
  59. {
  60. struct { int key,value; } *map=NULL;
  61. int i,j,n,k;
  62. churn_misses = 0;
  63. for (i=0; i < a; ++i) {
  64. hmput(map,i,i+1);
  65. max_hit_probes = MAX(max_hit_probes, stbds_hash_probes);
  66. total_put_probes += stbds_hash_probes;
  67. stbds_hash_probes = 0;
  68. }
  69. for (n=0; n < count; ++n) {
  70. for (j=a; j < b; ++j,++i) {
  71. hmput(map,i,i+1);
  72. max_hit_probes = MAX(max_hit_probes, stbds_hash_probes);
  73. total_put_probes += stbds_hash_probes;
  74. stbds_hash_probes = 0;
  75. }
  76. for (j=0; j < (b-a)*10; ++j) {
  77. k=i+j;
  78. (void) hmgeti(map,k); // miss
  79. max_miss_probes = MAX(max_miss_probes, stbds_hash_probes);
  80. total_miss_probes += stbds_hash_probes;
  81. stbds_hash_probes = 0;
  82. ++churn_misses;
  83. }
  84. assert(hmlen(map) == b);
  85. for (j=a; j < b; ++j) {
  86. k=i-j-1;
  87. k = hmdel(map,k);
  88. stbds_hash_probes = 0;
  89. assert(k);
  90. }
  91. assert(hmlen(map) == a);
  92. }
  93. hmfree(map);
  94. churn_inserts = i;
  95. churn_deletes = (b-a) * n;
  96. }
  97. void reset_stats(void)
  98. {
  99. stbds_array_grow=0,
  100. stbds_hash_grow=0;
  101. stbds_hash_shrink=0;
  102. stbds_hash_rebuild=0;
  103. stbds_hash_probes=0;
  104. stbds_hash_alloc=0;
  105. stbds_rehash_probes=0;
  106. stbds_rehash_items=0;
  107. max_hit_probes = 0;
  108. max_miss_probes = 0;
  109. total_put_probes = 0;
  110. total_miss_probes = 0;
  111. }
  112. void print_churn_probe_stats(char *str)
  113. {
  114. printf("Probes: %3d max hit, %3d max miss, %4.2f avg hit, %4.2f avg miss: %s\n",
  115. (int) max_hit_probes, (int) max_miss_probes, (float) total_put_probes / churn_inserts, (float) total_miss_probes / churn_misses, str);
  116. reset_stats();
  117. }
  118. int main(int arg, char **argv)
  119. {
  120. churn_stats(0,500000,1); print_churn_probe_stats("Inserting 500000 items");
  121. churn_stats(0,500000,1); print_churn_probe_stats("Inserting 500000 items");
  122. churn_stats(0,500000,1); print_churn_probe_stats("Inserting 500000 items");
  123. churn_stats(0,500000,1); print_churn_probe_stats("Inserting 500000 items");
  124. churn_stats(49000,50000,500); print_churn_probe_stats("Deleting/Inserting 500000 items");
  125. churn_stats(49000,50000,500); print_churn_probe_stats("Deleting/Inserting 500000 items");
  126. churn_stats(49000,50000,500); print_churn_probe_stats("Deleting/Inserting 500000 items");
  127. churn_stats(49000,50000,500); print_churn_probe_stats("Deleting/Inserting 500000 items");
  128. return 0;
  129. }
  130. #endif
  131. #ifdef DS_PERF
  132. #define WIN32_LEAN_AND_MEAN
  133. #include <windows.h>
  134. #define STB_DEFINE
  135. #define STB_NO_REGISTRY
  136. //#include "../stb.h"
  137. size_t t0, sum, mn,mx,count;
  138. void begin(void)
  139. {
  140. size_t t0;
  141. LARGE_INTEGER m;
  142. QueryPerformanceCounter(&m);
  143. t0 = m.QuadPart;
  144. sum = 0;
  145. count = 0;
  146. mx = 0;
  147. mn = ~(size_t) 0;
  148. }
  149. void measure(void)
  150. {
  151. size_t t1, t;
  152. LARGE_INTEGER m;
  153. QueryPerformanceCounter(&m);
  154. t1 = m.QuadPart;
  155. t = t1-t0;
  156. if (t1 < t0)
  157. printf("ALERT: QueryPerformanceCounter was unordered!\n");
  158. if (t < mn) mn = t;
  159. if (t > mx) mx = t;
  160. sum += t;
  161. ++count;
  162. t0 = t1;
  163. }
  164. void dont_measure(void)
  165. {
  166. size_t t1, t;
  167. LARGE_INTEGER m;
  168. QueryPerformanceCounter(&m);
  169. t0 = m.QuadPart;
  170. }
  171. double timer;
  172. void end(void)
  173. {
  174. LARGE_INTEGER m;
  175. QueryPerformanceFrequency(&m);
  176. if (count > 3) {
  177. // discard the highest and lowest
  178. sum -= mn;
  179. sum -= mx;
  180. count -= 2;
  181. }
  182. timer = (double) (sum) / count / m.QuadPart * 1000;
  183. }
  184. void build(int a, int b, int count, int step)
  185. {
  186. struct { int key,value; } *map=NULL;
  187. int i,j,n,k;
  188. for (i=0; i < a; ++i)
  189. hmput(map,i*step,i+1);
  190. measure();
  191. churn_inserts = i;
  192. hmfree(map);
  193. dont_measure();
  194. }
  195. #ifdef STB__INCLUDE_STB_H
  196. void build_stb(int a, int b, int count, int step)
  197. {
  198. stb_idict *d = stb_idict_new_size(8);
  199. struct { int key,value; } *map=NULL;
  200. int i,j,n,k;
  201. for (i=0; i < a; ++i)
  202. stb_idict_add(d, i*step, i+1);
  203. measure();
  204. churn_inserts = i;
  205. stb_idict_destroy(d);
  206. dont_measure();
  207. }
  208. #endif
  209. void churn_skip(unsigned int a, unsigned int b, int count)
  210. {
  211. struct { unsigned int key,value; } *map=NULL;
  212. unsigned int i,j,n,k;
  213. for (i=0; i < a; ++i)
  214. hmput(map,i,i+1);
  215. dont_measure();
  216. for (n=0; n < count; ++n) {
  217. for (j=a; j < b; ++j,++i) {
  218. hmput(map,i,i+1);
  219. }
  220. assert(hmlen(map) == b);
  221. for (j=a; j < b; ++j) {
  222. k=i-j-1;
  223. k = hmdel(map,k);
  224. assert(k != 0);
  225. }
  226. assert(hmlen(map) == a);
  227. }
  228. measure();
  229. churn_inserts = i;
  230. churn_deletes = (b-a) * n;
  231. hmfree(map);
  232. dont_measure();
  233. }
  234. typedef struct { int n[8]; } str32;
  235. void churn32(int a, int b, int count, int include_startup)
  236. {
  237. struct { str32 key; int value; } *map=NULL;
  238. int i,j,n;
  239. str32 key = { 0 };
  240. for (i=0; i < a; ++i) {
  241. key.n[0] = i;
  242. hmput(map,key,i+1);
  243. }
  244. if (!include_startup)
  245. dont_measure();
  246. for (n=0; n < count; ++n) {
  247. for (j=a; j < b; ++j,++i) {
  248. key.n[0] = i;
  249. hmput(map,key,i+1);
  250. }
  251. assert(hmlen(map) == b);
  252. for (j=a; j < b; ++j) {
  253. key.n[0] = i-j-1;
  254. hmdel(map,key);
  255. }
  256. assert(hmlen(map) == a);
  257. }
  258. measure();
  259. hmfree(map);
  260. churn_inserts = i;
  261. churn_deletes = (b-a) * n;
  262. dont_measure();
  263. }
  264. typedef struct { int n[32]; } str256;
  265. void churn256(int a, int b, int count, int include_startup)
  266. {
  267. struct { str256 key; int value; } *map=NULL;
  268. int i,j,n;
  269. str256 key = { 0 };
  270. for (i=0; i < a; ++i) {
  271. key.n[0] = i;
  272. hmput(map,key,i+1);
  273. }
  274. if (!include_startup)
  275. dont_measure();
  276. for (n=0; n < count; ++n) {
  277. for (j=a; j < b; ++j,++i) {
  278. key.n[0] = i;
  279. hmput(map,key,i+1);
  280. }
  281. assert(hmlen(map) == b);
  282. for (j=a; j < b; ++j) {
  283. key.n[0] = i-j-1;
  284. hmdel(map,key);
  285. }
  286. assert(hmlen(map) == a);
  287. }
  288. measure();
  289. hmfree(map);
  290. churn_inserts = i;
  291. churn_deletes = (b-a) * n;
  292. dont_measure();
  293. }
  294. void churn8(int a, int b, int count, int include_startup)
  295. {
  296. struct { size_t key,value; } *map=NULL;
  297. int i,j,n,k;
  298. for (i=0; i < a; ++i)
  299. hmput(map,i,i+1);
  300. if (!include_startup)
  301. dont_measure();
  302. for (n=0; n < count; ++n) {
  303. for (j=a; j < b; ++j,++i) {
  304. hmput(map,i,i+1);
  305. }
  306. assert(hmlen(map) == b);
  307. for (j=a; j < b; ++j) {
  308. k=i-j-1;
  309. k = hmdel(map,k);
  310. assert(k != 0);
  311. }
  312. assert(hmlen(map) == a);
  313. }
  314. measure();
  315. hmfree(map);
  316. churn_inserts = i;
  317. churn_deletes = (b-a) * n;
  318. dont_measure();
  319. }
  320. int main(int arg, char **argv)
  321. {
  322. int n,s,w;
  323. double worst = 0;
  324. #if 0
  325. begin(); for (n=0; n < 2000; ++n) { build_stb(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table\n", timer);
  326. begin(); for (n=0; n < 500; ++n) { build_stb(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table\n", timer);
  327. begin(); for (n=0; n < 100; ++n) { build_stb(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table\n", timer);
  328. begin(); for (n=0; n < 10; ++n) { build_stb(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table\n", timer);
  329. begin(); for (n=0; n < 5; ++n) { build_stb(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table\n", timer);
  330. #endif
  331. begin(); for (n=0; n < 2000; ++n) { churn8(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table w/ 8-byte key\n", timer);
  332. begin(); for (n=0; n < 500; ++n) { churn8(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table w/ 8-byte key\n", timer);
  333. begin(); for (n=0; n < 100; ++n) { churn8(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table w/ 8-byte key\n", timer);
  334. begin(); for (n=0; n < 10; ++n) { churn8(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table w/ 8-byte key\n", timer);
  335. begin(); for (n=0; n < 5; ++n) { churn8(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table w/ 8-byte key\n", timer);
  336. #if 0
  337. begin(); for (n=0; n < 2000; ++n) { churn32(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table w/ 32-byte key\n", timer);
  338. begin(); for (n=0; n < 500; ++n) { churn32(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table w/ 32-byte key\n", timer);
  339. begin(); for (n=0; n < 100; ++n) { churn32(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table w/ 32-byte key\n", timer);
  340. begin(); for (n=0; n < 10; ++n) { churn32(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table w/ 32-byte key\n", timer);
  341. begin(); for (n=0; n < 5; ++n) { churn32(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table w/ 32-byte key\n", timer);
  342. begin(); for (n=0; n < 2000; ++n) { churn256(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table w/ 256-byte key\n", timer);
  343. begin(); for (n=0; n < 500; ++n) { churn256(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table w/ 256-byte key\n", timer);
  344. begin(); for (n=0; n < 100; ++n) { churn256(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table w/ 256-byte key\n", timer);
  345. begin(); for (n=0; n < 10; ++n) { churn256(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table w/ 256-byte key\n", timer);
  346. begin(); for (n=0; n < 5; ++n) { churn256(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table w/ 256-byte key\n", timer);
  347. #endif
  348. begin(); for (n=0; n < 2000; ++n) { build(2000,0,0,1); } end(); printf(" // %7.2fms : 2,000 inserts creating 2K table w/ 4-byte key\n", timer);
  349. begin(); for (n=0; n < 500; ++n) { build(20000,0,0,1); } end(); printf(" // %7.2fms : 20,000 inserts creating 20K table w/ 4-byte key\n", timer);
  350. begin(); for (n=0; n < 100; ++n) { build(200000,0,0,1); } end(); printf(" // %7.2fms : 200,000 inserts creating 200K table w/ 4-byte key\n", timer);
  351. begin(); for (n=0; n < 10; ++n) { build(2000000,0,0,1); } end(); printf(" // %7.2fms : 2,000,000 inserts creating 2M table w/ 4-byte key\n", timer);
  352. begin(); for (n=0; n < 5; ++n) { build(20000000,0,0,1); } end(); printf(" // %7.2fms : 20,000,000 inserts creating 20M table w/ 4-byte key\n", timer);
  353. begin(); for (n=0; n < 60; ++n) { churn_skip(2000,2100,5000); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 2K table\n", timer);
  354. begin(); for (n=0; n < 30; ++n) { churn_skip(20000,21000,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 20K table\n", timer);
  355. begin(); for (n=0; n < 15; ++n) { churn_skip(200000,201000,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 200K table\n", timer);
  356. begin(); for (n=0; n < 8; ++n) { churn_skip(2000000,2001000,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 2M table\n", timer);
  357. begin(); for (n=0; n < 5; ++n) { churn_skip(20000000,20001000,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 20M table\n", timer);
  358. begin(); for (n=0; n < 1; ++n) { churn_skip(200000000u,200001000u,500); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 200M table\n", timer);
  359. // even though the above measures a roughly fixed amount of work, we still have to build the table n times, hence the fewer measurements each time
  360. begin(); for (n=0; n < 60; ++n) { churn_skip(1000,3000,250); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 2K table\n", timer);
  361. begin(); for (n=0; n < 15; ++n) { churn_skip(10000,30000,25); } end(); printf(" // %7.2fms : 500,000 inserts & deletes in 20K table\n", timer);
  362. begin(); for (n=0; n < 7; ++n) { churn_skip(100000,300000,10); } end(); printf(" // %7.2fms : 2,000,000 inserts & deletes in 200K table\n", timer);
  363. begin(); for (n=0; n < 2; ++n) { churn_skip(1000000,3000000,10); } end(); printf(" // %7.2fms : 20,000,000 inserts & deletes in 2M table\n", timer);
  364. // search for bad intervals.. in practice this just seems to measure execution variance
  365. for (s = 2; s < 64; ++s) {
  366. begin(); for (n=0; n < 50; ++n) { build(200000,0,0,s); } end();
  367. if (timer > worst) {
  368. worst = timer;
  369. w = s;
  370. }
  371. }
  372. for (; s <= 1024; s *= 2) {
  373. begin(); for (n=0; n < 50; ++n) { build(200000,0,0,s); } end();
  374. if (timer > worst) {
  375. worst = timer;
  376. w = s;
  377. }
  378. }
  379. printf(" // %7.2fms(%d) : Worst time from inserting 200,000 items with spacing %d.\n", worst, w, w);
  380. return 0;
  381. }
  382. #endif