-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbenchmark.cpp
More file actions
454 lines (369 loc) · 17.1 KB
/
Copy pathbenchmark.cpp
File metadata and controls
454 lines (369 loc) · 17.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
//----------------------------------------------------------------------------------------
//
// benchmark.cpp — RandX.hpp 全引擎性能基准测试
//
// 编译:g++ -std=c++23 -O2 benchmark.cpp -o benchmark.exe
//
// 测试项目:
// 1. 原始吞吐量(Mops/s, MB/s)
// 2. jump() 跳跃开销(仅支持 jump 的引擎)
// 3. RandInt(0, 999999) 便捷 API 吞吐量
// 4. RandFill 容器填充吞吐量
// 5. RandVector 生成新 vector 吞吐量(含分配开销)
//
//----------------------------------------------------------------------------------------
#include "RandX.hpp"
#include <chrono>
#include <cstdio>
#include <list>
#include <type_traits>
#include <vector>
// 迭代次数
static constexpr int N = 100'000'000;
// jump 基准测试的迭代次数(jump 本身开销较大,减少次数)
static constexpr int JumpN = 1'000'000;
// 防止编译器优化掉生成结果
template <class T>
static void DoNotOptimize(T value)
{
static volatile T sink;
sink = value;
}
//----------------------------------------------------------------------------------------
//
// 原始吞吐量基准测试
//
//----------------------------------------------------------------------------------------
// 测量引擎原始吞吐量,输出 Mops/s 和 MB/s
template <class Engine>
static double BenchmarkRaw(const char* name)
{
Engine rng{ 42 };
const auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < N; ++i)
DoNotOptimize(rng());
const auto end = std::chrono::high_resolution_clock::now();
const double ms = std::chrono::duration<double, std::milli>(end - start).count();
const double mops = N / ms / 1000.0;
const double mbs = mops * sizeof(typename Engine::result_type);
std::printf(" %-24s %8.1f Mops/s %8.1f MB/s (%6.1f ms)\n", name, mops, mbs, ms);
return mops;
}
//----------------------------------------------------------------------------------------
//
// jump() 跳跃开销基准测试
//
//----------------------------------------------------------------------------------------
// 测量 jump() 调用开销(仅对支持 jump 的引擎有效)
template <class Engine>
static double BenchmarkJump(const char* name)
{
Engine rng{ 42 };
const auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < JumpN; ++i)
rng.jump();
const auto end = std::chrono::high_resolution_clock::now();
const double ms = std::chrono::duration<double, std::milli>(end - start).count();
const double jumpsPerSec = JumpN / ms * 1000.0;
// 防止引擎状态被优化掉
DoNotOptimize(rng());
std::printf(" %-24s %12.0f jumps/s (%6.1f ms / %d jumps)\n", name, jumpsPerSec, ms, JumpN);
return jumpsPerSec;
}
//----------------------------------------------------------------------------------------
//
// RandInt 便捷 API 吞吐量基准测试
//
//----------------------------------------------------------------------------------------
// 测量 RandInt(engine, 0, 999999) 的吞吐量
template <class Engine>
static double BenchmarkRandInt(const char* name)
{
Engine rng{ 42 };
const auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < N; ++i)
DoNotOptimize(RandX::RandInt(rng, 0, 999999));
const auto end = std::chrono::high_resolution_clock::now();
const double ms = std::chrono::duration<double, std::milli>(end - start).count();
const double mops = N / ms / 1000.0;
std::printf(" %-24s %8.1f Mops/s (%6.1f ms)\n", name, mops, ms);
return mops;
}
//----------------------------------------------------------------------------------------
//
// RandFill 容器填充吞吐量基准测试
//
//----------------------------------------------------------------------------------------
// RandFill 基准测试的单次填充元素数(1M,循环 N/FillN 次凑够 N)
static constexpr int FillN = 1'000'000;
// 测量 RandFill(engine, first, last, 0, 999999) 填充预分配容器的吞吐量
template <class Engine>
static double BenchmarkRandFill(const char* name)
{
Engine rng{ 42 };
std::vector<int> buf(static_cast<std::size_t>(FillN));
const auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < N / FillN; ++i)
RandX::RandFill(rng, buf.begin(), buf.end(), 0, 999999);
const auto end = std::chrono::high_resolution_clock::now();
DoNotOptimize(buf[0]);
const double ms = std::chrono::duration<double, std::milli>(end - start).count();
const double mops = N / ms / 1000.0;
std::printf(" %-24s %8.1f Mops/s (%6.1f ms)\n", name, mops, ms);
return mops;
}
//----------------------------------------------------------------------------------------
//
// RandVector 生成新 vector 吞吐量基准测试
//
//----------------------------------------------------------------------------------------
// 测量 RandVector(engine, 0, 999999, VecN) 生成新 vector 的吞吐量(含分配开销)
template <class Engine>
static double BenchmarkRandVector(const char* name)
{
Engine rng{ 42 };
const auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < N / FillN; ++i)
{
auto v = RandX::RandVector(rng, 0, 999999, FillN);
DoNotOptimize(v[0]);
}
const auto end = std::chrono::high_resolution_clock::now();
const double ms = std::chrono::duration<double, std::milli>(end - start).count();
const double mops = N / ms / 1000.0;
std::printf(" %-24s %8.1f Mops/s (%6.1f ms)\n", name, mops, ms);
return mops;
}
//----------------------------------------------------------------------------------------
//
// RandSample 迭代器版性能基准测试(v1.2 新增)
//
//----------------------------------------------------------------------------------------
// RandSample 基准测试的容器大小(大 N 小 n 场景)
static constexpr int SampleSize = 1'000'000;
// 抽样数量(n·64 < size,强制走 hash-set 分支)
static constexpr int SampleN_HashSet = 100;
// 抽样数量(n·64 >= size,走索引数组分支)
static constexpr int SampleN_Index = 20000;
// 测试轮数
static constexpr int SampleTrials = 100;
// 测量 RandSample 容器版(复制整个容器到 pool)
static double BenchmarkRandSampleContainer(const char* name)
{
std::vector<int> data(static_cast<std::size_t>(SampleSize));
for (int i = 0; i < SampleSize; ++i) data[static_cast<std::size_t>(i)] = i;
const auto start = std::chrono::high_resolution_clock::now();
for (int t = 0; t < SampleTrials; ++t)
{
auto s = RandX::RandSample(data, static_cast<std::size_t>(SampleN_HashSet));
DoNotOptimize(s[0]);
}
const auto end = std::chrono::high_resolution_clock::now();
const double ms = std::chrono::duration<double, std::milli>(end - start).count();
const double opsPerSec = SampleTrials / ms * 1000.0;
std::printf(" %-40s %10.1f ops/s (%6.1f ms / %d trials)\n",
name, opsPerSec, ms, SampleTrials);
return opsPerSec;
}
// 测量 RandSample 迭代器版(hash-set 分支:n·64 < size)
static double BenchmarkRandSampleHashSet(const char* name)
{
std::vector<int> data(static_cast<std::size_t>(SampleSize));
for (int i = 0; i < SampleSize; ++i) data[static_cast<std::size_t>(i)] = i;
const auto start = std::chrono::high_resolution_clock::now();
for (int t = 0; t < SampleTrials; ++t)
{
auto s = RandX::RandSample(data.begin(), data.end(), SampleN_HashSet);
DoNotOptimize(s[0]);
}
const auto end = std::chrono::high_resolution_clock::now();
const double ms = std::chrono::duration<double, std::milli>(end - start).count();
const double opsPerSec = SampleTrials / ms * 1000.0;
std::printf(" %-40s %10.1f ops/s (%6.1f ms / %d trials)\n",
name, opsPerSec, ms, SampleTrials);
return opsPerSec;
}
// 测量 RandSample 迭代器版(索引数组分支:n·64 >= size)
static double BenchmarkRandSampleIndex(const char* name)
{
std::vector<int> data(static_cast<std::size_t>(SampleSize));
for (int i = 0; i < SampleSize; ++i) data[static_cast<std::size_t>(i)] = i;
const auto start = std::chrono::high_resolution_clock::now();
for (int t = 0; t < SampleTrials; ++t)
{
auto s = RandX::RandSample(data.begin(), data.end(), SampleN_Index);
DoNotOptimize(s[0]);
}
const auto end = std::chrono::high_resolution_clock::now();
const double ms = std::chrono::duration<double, std::milli>(end - start).count();
const double opsPerSec = SampleTrials / ms * 1000.0;
std::printf(" %-40s %10.1f ops/s (%6.1f ms / %d trials)\n",
name, opsPerSec, ms, SampleTrials);
return opsPerSec;
}
// 测量 RandSample 迭代器版(reservoir:std::list 输入迭代器)
static double BenchmarkRandSampleReservoir(const char* name)
{
std::list<int> data;
for (int i = 0; i < SampleSize; ++i) data.push_back(i);
const auto start = std::chrono::high_resolution_clock::now();
for (int t = 0; t < SampleTrials; ++t)
{
auto s = RandX::RandSample(data.begin(), data.end(), SampleN_HashSet);
DoNotOptimize(s[0]);
}
const auto end = std::chrono::high_resolution_clock::now();
const double ms = std::chrono::duration<double, std::milli>(end - start).count();
const double opsPerSec = SampleTrials / ms * 1000.0;
std::printf(" %-40s %10.1f ops/s (%6.1f ms / %d trials)\n",
name, opsPerSec, ms, SampleTrials);
return opsPerSec;
}
//----------------------------------------------------------------------------------------
//
// SecureRandomBytes 延迟与吞吐量基准测试(v1.3 新增)
//
//----------------------------------------------------------------------------------------
// SecureRandomBytes 延迟基准测试的迭代次数(OS 熵调用较慢,减少次数)
static constexpr int SecureIterN = 10000;
// SecureRandomBytes 缓冲区大小(1 KB)
static constexpr int SecureBufSize = 1024;
// 测量 SecureRandomBytes 单次调用延迟与吞吐量(填充 1 KB 缓冲区)
static double BenchmarkSecureRandomBytesLatency(const char* name)
{
std::vector<std::uint8_t> buf(static_cast<std::size_t>(SecureBufSize));
const auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < SecureIterN; ++i)
RandX::SecureRandomBytes(buf.data(), buf.size());
const auto end = std::chrono::high_resolution_clock::now();
DoNotOptimize(buf[0]);
const double ms = std::chrono::duration<double, std::milli>(end - start).count();
const double latencyUs = ms * 1000.0 / SecureIterN;
const double mbs = static_cast<double>(SecureBufSize) * SecureIterN / ms / 1000.0;
std::printf(" %-24s %8.2f us/call %8.1f MB/s (%6.1f ms / %d calls)\n",
name, latencyUs, mbs, ms, SecureIterN);
return latencyUs;
}
//----------------------------------------------------------------------------------------
//
// 主函数
//
//----------------------------------------------------------------------------------------
int main()
{
std::printf("================================================================\n");
std::printf(" RandX.hpp 性能基准测试 (N = %d)\n", N);
std::printf("================================================================\n\n");
//----------------------------------------------------------------
// 第一部分:原始吞吐量
//----------------------------------------------------------------
std::printf("[1] 原始吞吐量 (operator())\n");
std::printf("----------------------------------------------------------------\n");
// 64 位输出引擎
std::printf(" --- 64-bit 引擎 ---\n");
BenchmarkRaw<RandX::SplitMix64>("SplitMix64");
BenchmarkRaw<RandX::Xoshiro256StarStar>("Xoshiro256StarStar");
BenchmarkRaw<RandX::Xoroshiro128StarStar>("Xoroshiro128StarStar");
BenchmarkRaw<RandX::SFC64>("SFC64");
BenchmarkRaw<RandX::RomuDuoJr>("RomuDuoJr");
// 32 位输出引擎
std::printf(" --- 32-bit 引擎 ---\n");
BenchmarkRaw<RandX::Xoshiro128StarStar>("Xoshiro128StarStar");
BenchmarkRaw<RandX::Xoroshiro64StarStar>("Xoroshiro64StarStar");
// CSPRNG 引擎(v1.3 新增)
std::printf(" --- CSPRNG ---\n");
BenchmarkRaw<RandX::ChaCha20>("ChaCha20");
std::printf("\n");
//----------------------------------------------------------------
// 第二部分:jump() 跳跃开销
//----------------------------------------------------------------
std::printf("[2] jump() 跳跃开销 (JumpN = %d)\n", JumpN);
std::printf("----------------------------------------------------------------\n");
// Xoshiro256 系列(jump 等价于 2^128 步)
std::printf(" --- Xoshiro256 系列 (jump = 2^128 步) ---\n");
BenchmarkJump<RandX::Xoshiro256StarStar>("Xoshiro256StarStar");
// Xoroshiro128 系列(jump 等价于 2^64 步)
std::printf(" --- Xoroshiro128 系列 (jump = 2^64 步) ---\n");
BenchmarkJump<RandX::Xoroshiro128StarStar>("Xoroshiro128StarStar");
// Xoshiro128 系列(jump 等价于 2^64 步)
std::printf(" --- Xoshiro128 系列 (jump = 2^64 步) ---\n");
BenchmarkJump<RandX::Xoshiro128StarStar>("Xoshiro128StarStar");
std::printf("\n");
//----------------------------------------------------------------
// 第三部分:RandInt 便捷 API 吞吐量
//----------------------------------------------------------------
std::printf("[3] RandInt(engine, 0, 999999) 便捷 API 吞吐量\n");
std::printf("----------------------------------------------------------------\n");
// 64 位引擎
std::printf(" --- 64-bit 引擎 ---\n");
BenchmarkRandInt<RandX::SplitMix64>("SplitMix64");
BenchmarkRandInt<RandX::Xoshiro256StarStar>("Xoshiro256StarStar");
BenchmarkRandInt<RandX::Xoroshiro128StarStar>("Xoroshiro128StarStar");
BenchmarkRandInt<RandX::SFC64>("SFC64");
BenchmarkRandInt<RandX::RomuDuoJr>("RomuDuoJr");
// 32 位引擎
std::printf(" --- 32-bit 引擎 ---\n");
BenchmarkRandInt<RandX::Xoshiro128StarStar>("Xoshiro128StarStar");
BenchmarkRandInt<RandX::Xoroshiro64StarStar>("Xoroshiro64StarStar");
std::printf("\n");
//----------------------------------------------------------------
// 第四部分:RandFill 容器填充吞吐量
//----------------------------------------------------------------
std::printf("[4] RandFill(engine, first, last, 0, 999999) 容器填充吞吐量\n");
std::printf(" (预分配 %d 元素 vector,循环 %d 次)\n", FillN, N / FillN);
std::printf("----------------------------------------------------------------\n");
BenchmarkRandFill<RandX::SplitMix64>("SplitMix64");
BenchmarkRandFill<RandX::Xoshiro256StarStar>("Xoshiro256StarStar");
BenchmarkRandFill<RandX::SFC64>("SFC64");
std::printf("\n");
//----------------------------------------------------------------
// 第五部分:RandVector 生成新 vector 吞吐量
//----------------------------------------------------------------
std::printf("[5] RandVector(engine, 0, 999999, %d) 生成新 vector 吞吐量\n", FillN);
std::printf(" (含 vector 分配开销,循环 %d 次)\n", N / FillN);
std::printf("----------------------------------------------------------------\n");
BenchmarkRandVector<RandX::SplitMix64>("SplitMix64");
BenchmarkRandVector<RandX::Xoshiro256StarStar>("Xoshiro256StarStar");
BenchmarkRandVector<RandX::SFC64>("SFC64");
std::printf("\n");
//----------------------------------------------------------------
// 第六部分:RandSample 迭代器版性能对比(v1.2 新增)
//----------------------------------------------------------------
std::printf("[6] RandSample 迭代器版性能对比 (SampleSize=%d, trials=%d)\n", SampleSize, SampleTrials);
std::printf(" 大 N 小 n 场景:1M 元素中抽 %d(hash-set 分支)/ %d(索引分支)\n",
SampleN_HashSet, SampleN_Index);
std::printf(" 切换阈值:n·64 < size(v1.2.1 修订,原 n²<size)\n");
std::printf("----------------------------------------------------------------\n");
BenchmarkRandSampleContainer("RandSample(container, n=100)");
BenchmarkRandSampleHashSet("RandSample(iter, n=100, hash-set)");
BenchmarkRandSampleIndex("RandSample(iter, n=20000, index)");
BenchmarkRandSampleReservoir("RandSample(list, n=100, reservoir)");
std::printf("\n");
//----------------------------------------------------------------
// 第七部分:SecureRandomBytes 延迟与吞吐量(v1.3 新增)
//----------------------------------------------------------------
std::printf("[7] SecureRandomBytes 延迟与吞吐量 (buf=%d bytes, calls=%d)\n", SecureBufSize, SecureIterN);
std::printf("----------------------------------------------------------------\n");
BenchmarkSecureRandomBytesLatency("SecureRandomBytes");
std::printf("\n");
//----------------------------------------------------------------
// 第八部分:RandCanonical 浮点直通吞吐量对比(v1.3.5 新增)
//----------------------------------------------------------------
std::printf("[8] RandCanonical 浮点直通吞吐量对比 (%d 次迭代)\n", N);
std::printf("----------------------------------------------------------------\n");
{
RandX::Xoshiro256StarStar rng{ 42 };
const auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < N; ++i)
DoNotOptimize(RandX::RandCanonicalDouble());
const auto end = std::chrono::high_resolution_clock::now();
const double ms = std::chrono::duration<double, std::milli>(end - start).count();
const double mops = N / ms / 1000.0;
std::printf(" %-40s %8.1f Mops/s (%6.1f ms)\n", "RandCanonicalDouble", mops, ms);
}
std::printf("\n");
std::printf("================================================================\n");
std::printf(" 基准测试完成\n");
std::printf("================================================================\n");
return 0;
}