line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
/* rhash_timing.c - functions to benchmark hash algorithms, |
2
|
|
|
|
|
|
|
* |
3
|
|
|
|
|
|
|
* Copyright: 2010-2012 Aleksey Kravchenko |
4
|
|
|
|
|
|
|
* |
5
|
|
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a |
6
|
|
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"), |
7
|
|
|
|
|
|
|
* to deal in the Software without restriction, including without limitation |
8
|
|
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
9
|
|
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the |
10
|
|
|
|
|
|
|
* Software is furnished to do so. |
11
|
|
|
|
|
|
|
* |
12
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful, but |
13
|
|
|
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
14
|
|
|
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! |
15
|
|
|
|
|
|
|
*/ |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
/* modifier for Windows dll */ |
18
|
|
|
|
|
|
|
#if defined(_WIN32) && defined(RHASH_EXPORTS) |
19
|
|
|
|
|
|
|
# define RHASH_API __declspec(dllexport) |
20
|
|
|
|
|
|
|
#endif |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
#include "byte_order.h" |
23
|
|
|
|
|
|
|
#include "rhash.h" |
24
|
|
|
|
|
|
|
#include "rhash_timing.h" |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
/* DEFINE read_tsc() if possible */ |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
#if (defined(CPU_IA32)) || defined(CPU_X64) |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
#if defined( _MSC_VER ) /* if MS VC */ |
31
|
|
|
|
|
|
|
# include |
32
|
|
|
|
|
|
|
# pragma intrinsic( __rdtsc ) |
33
|
|
|
|
|
|
|
# define read_tsc() __rdtsc() |
34
|
|
|
|
|
|
|
# define HAVE_TSC |
35
|
|
|
|
|
|
|
#elif defined( __GNUC__ ) /* if GCC */ |
36
|
0
|
|
|
|
|
|
static uint64_t read_tsc(void) { |
37
|
|
|
|
|
|
|
unsigned long lo, hi; |
38
|
0
|
|
|
|
|
|
__asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); |
39
|
0
|
|
|
|
|
|
return (((uint64_t)hi) << 32) + lo; |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
# define HAVE_TSC |
42
|
|
|
|
|
|
|
#endif /* _MSC_VER, __GNUC__ */ |
43
|
|
|
|
|
|
|
#endif /* CPU_IA32, CPU_X64 */ |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
/* TIMER FUNCTIONS */ |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
#ifdef _WIN32 |
49
|
|
|
|
|
|
|
#include |
50
|
|
|
|
|
|
|
#define get_timedelta(delta) QueryPerformanceCounter((LARGE_INTEGER*)delta) |
51
|
|
|
|
|
|
|
#else |
52
|
|
|
|
|
|
|
#define get_timedelta(delta) gettimeofday(delta, NULL) |
53
|
|
|
|
|
|
|
#endif |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
/** |
56
|
|
|
|
|
|
|
* Return real-value representing number of seconds |
57
|
|
|
|
|
|
|
* stored in the given timeval structure. |
58
|
|
|
|
|
|
|
* The function is used with timers, when printing time statistics. |
59
|
|
|
|
|
|
|
* |
60
|
|
|
|
|
|
|
* @deprecated This function shall be removed soon. |
61
|
|
|
|
|
|
|
* |
62
|
|
|
|
|
|
|
* @param delta time delta to be converted |
63
|
|
|
|
|
|
|
* @return number of seconds |
64
|
|
|
|
|
|
|
*/ |
65
|
0
|
|
|
|
|
|
static double fsec(timedelta_t* timer) |
66
|
|
|
|
|
|
|
{ |
67
|
|
|
|
|
|
|
#ifdef _WIN32 |
68
|
|
|
|
|
|
|
LARGE_INTEGER freq; |
69
|
|
|
|
|
|
|
QueryPerformanceFrequency(&freq); |
70
|
|
|
|
|
|
|
return (double)*timer / freq.QuadPart; |
71
|
|
|
|
|
|
|
#else |
72
|
0
|
|
|
|
|
|
return ((double)timer->tv_usec / 1000000.0) + timer->tv_sec; |
73
|
|
|
|
|
|
|
#endif |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
/** |
77
|
|
|
|
|
|
|
* Start a timer. |
78
|
|
|
|
|
|
|
* |
79
|
|
|
|
|
|
|
* @deprecated This function shall be removed soon, since |
80
|
|
|
|
|
|
|
* it is not related to the hashing library main functionality. |
81
|
|
|
|
|
|
|
* |
82
|
|
|
|
|
|
|
* @param timer timer to start |
83
|
|
|
|
|
|
|
*/ |
84
|
0
|
|
|
|
|
|
void rhash_timer_start(timedelta_t* timer) |
85
|
|
|
|
|
|
|
{ |
86
|
0
|
|
|
|
|
|
get_timedelta(timer); |
87
|
0
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
/** |
90
|
|
|
|
|
|
|
* Stop given timer. |
91
|
|
|
|
|
|
|
* |
92
|
|
|
|
|
|
|
* @deprecated This function shall be removed soon, since |
93
|
|
|
|
|
|
|
* it is not related to the hashing library main functionality. |
94
|
|
|
|
|
|
|
* |
95
|
|
|
|
|
|
|
* @param timer the timer to stop |
96
|
|
|
|
|
|
|
* @return number of seconds timed |
97
|
|
|
|
|
|
|
*/ |
98
|
0
|
|
|
|
|
|
double rhash_timer_stop(timedelta_t* timer) |
99
|
|
|
|
|
|
|
{ |
100
|
|
|
|
|
|
|
timedelta_t end; |
101
|
0
|
|
|
|
|
|
get_timedelta(&end); |
102
|
|
|
|
|
|
|
#ifdef _WIN32 |
103
|
|
|
|
|
|
|
*timer = end - *timer; |
104
|
|
|
|
|
|
|
#else |
105
|
0
|
|
|
|
|
|
timer->tv_sec = end.tv_sec - timer->tv_sec - (end.tv_usec >= timer->tv_usec ? 0 : 1); |
106
|
0
|
0
|
|
|
|
|
timer->tv_usec = end.tv_usec + (end.tv_usec >= timer->tv_usec ? 0 : 1000000 ) - timer->tv_usec; |
107
|
|
|
|
|
|
|
#endif |
108
|
0
|
|
|
|
|
|
return fsec(timer); |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
#ifdef _WIN32 |
112
|
|
|
|
|
|
|
/** |
113
|
|
|
|
|
|
|
* Set process priority and affinity to use all cpu's but the first one. |
114
|
|
|
|
|
|
|
* This improves benchmark results on a multi-cpu systems. |
115
|
|
|
|
|
|
|
* |
116
|
|
|
|
|
|
|
* @deprecated This function shall be removed soon. |
117
|
|
|
|
|
|
|
*/ |
118
|
|
|
|
|
|
|
static void benchmark_cpu_init(void) |
119
|
|
|
|
|
|
|
{ |
120
|
|
|
|
|
|
|
DWORD_PTR dwProcessMask, dwSysMask, dwDesired; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); |
123
|
|
|
|
|
|
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
if ( GetProcessAffinityMask(GetCurrentProcess(), &dwProcessMask, &dwSysMask) ) { |
126
|
|
|
|
|
|
|
dwDesired = dwSysMask & (dwProcessMask & ~1); /* remove the first processor */ |
127
|
|
|
|
|
|
|
dwDesired = (dwDesired ? dwDesired : dwSysMask & ~1); |
128
|
|
|
|
|
|
|
if (dwDesired != 0) { |
129
|
|
|
|
|
|
|
SetProcessAffinityMask(GetCurrentProcess(), dwDesired); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
#endif |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
/** |
136
|
|
|
|
|
|
|
* Hash a repeated message chunk by specified hash function. |
137
|
|
|
|
|
|
|
* |
138
|
|
|
|
|
|
|
* @deprecated This function shall be removed soon. |
139
|
|
|
|
|
|
|
* |
140
|
|
|
|
|
|
|
* @param hash_id hash function identifier |
141
|
|
|
|
|
|
|
* @param message a message chunk to hash |
142
|
|
|
|
|
|
|
* @param msg_size message chunk size |
143
|
|
|
|
|
|
|
* @param count number of chunks |
144
|
|
|
|
|
|
|
* @param out computed hash |
145
|
|
|
|
|
|
|
* @return 1 on success, 0 on error |
146
|
|
|
|
|
|
|
*/ |
147
|
0
|
|
|
|
|
|
static int hash_in_loop(unsigned hash_id, const unsigned char* message, size_t msg_size, int count, unsigned char* out) |
148
|
|
|
|
|
|
|
{ |
149
|
|
|
|
|
|
|
int i; |
150
|
0
|
|
|
|
|
|
struct rhash_context *context = rhash_init(hash_id); |
151
|
0
|
0
|
|
|
|
|
if (!context) return 0; |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
/* process the repeated message buffer */ |
154
|
0
|
0
|
|
|
|
|
for (i = 0; i < count; i++) rhash_update(context, message, msg_size); |
155
|
0
|
|
|
|
|
|
rhash_final(context, out); |
156
|
0
|
|
|
|
|
|
rhash_free(context); |
157
|
0
|
|
|
|
|
|
return 1; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
/** |
161
|
|
|
|
|
|
|
* Benchmark a hash algorithm. |
162
|
|
|
|
|
|
|
* |
163
|
|
|
|
|
|
|
* @deprecated This function shall be removed soon, since |
164
|
|
|
|
|
|
|
* it is not related to the hashing library main functionality. |
165
|
|
|
|
|
|
|
* |
166
|
|
|
|
|
|
|
* @param hash_id hash algorithm identifier |
167
|
|
|
|
|
|
|
* @param flags benchmark flags, can be RHASH_BENCHMARK_QUIET and RHASH_BENCHMARK_CPB |
168
|
|
|
|
|
|
|
* @param output the stream to print results |
169
|
|
|
|
|
|
|
*/ |
170
|
0
|
|
|
|
|
|
void rhash_run_benchmark(unsigned hash_id, unsigned flags, FILE* output) |
171
|
|
|
|
|
|
|
{ |
172
|
|
|
|
|
|
|
unsigned char ALIGN_ATTR(16) message[8192]; /* 8 KiB */ |
173
|
|
|
|
|
|
|
timedelta_t timer; |
174
|
|
|
|
|
|
|
int i, j; |
175
|
|
|
|
|
|
|
size_t sz_mb, msg_size; |
176
|
0
|
|
|
|
|
|
double time, total_time = 0; |
177
|
0
|
|
|
|
|
|
const int rounds = 4; |
178
|
|
|
|
|
|
|
const char* hash_name; |
179
|
|
|
|
|
|
|
unsigned char out[130]; |
180
|
|
|
|
|
|
|
#ifdef HAVE_TSC |
181
|
0
|
|
|
|
|
|
double cpb = 0; |
182
|
|
|
|
|
|
|
#endif /* HAVE_TSC */ |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
#ifdef _WIN32 |
185
|
|
|
|
|
|
|
benchmark_cpu_init(); /* set cpu affinity to improve test results */ |
186
|
|
|
|
|
|
|
#endif |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
/* set message size for fast and slow hash functions */ |
189
|
0
|
|
|
|
|
|
msg_size = 1073741824 / 2; |
190
|
0
|
0
|
|
|
|
|
if (hash_id & (RHASH_WHIRLPOOL | RHASH_SNEFRU128 | RHASH_SNEFRU256 | RHASH_SHA3_224 | RHASH_SHA3_256 | RHASH_SHA3_384 | RHASH_SHA3_512)) { |
191
|
0
|
|
|
|
|
|
msg_size /= 8; |
192
|
0
|
0
|
|
|
|
|
} else if (hash_id & (RHASH_GOST | RHASH_GOST_CRYPTOPRO | RHASH_SHA384 | RHASH_SHA512)) { |
193
|
0
|
|
|
|
|
|
msg_size /= 2; |
194
|
|
|
|
|
|
|
} |
195
|
0
|
|
|
|
|
|
sz_mb = msg_size / (1 << 20); /* size in MiB */ |
196
|
0
|
|
|
|
|
|
hash_name = rhash_get_name(hash_id); |
197
|
0
|
0
|
|
|
|
|
if (!hash_name) hash_name = ""; /* benchmarking several hashes*/ |
198
|
|
|
|
|
|
|
|
199
|
0
|
0
|
|
|
|
|
for (i = 0; i < (int)sizeof(message); i++) message[i] = i & 0xff; |
200
|
|
|
|
|
|
|
|
201
|
0
|
0
|
|
|
|
|
for (j = 0; j < rounds; j++) { |
202
|
0
|
|
|
|
|
|
rhash_timer_start(&timer); |
203
|
0
|
|
|
|
|
|
hash_in_loop(hash_id, message, sizeof(message), (int)(msg_size / sizeof(message)), out); |
204
|
|
|
|
|
|
|
|
205
|
0
|
|
|
|
|
|
time = rhash_timer_stop(&timer); |
206
|
0
|
|
|
|
|
|
total_time += time; |
207
|
|
|
|
|
|
|
|
208
|
0
|
0
|
|
|
|
|
if ((flags & (RHASH_BENCHMARK_QUIET | RHASH_BENCHMARK_RAW)) == 0) { |
209
|
0
|
|
|
|
|
|
fprintf(output, "%s %u MiB calculated in %.3f sec, %.3f MBps\n", hash_name, (unsigned)sz_mb, time, (double)sz_mb / time); |
210
|
0
|
|
|
|
|
|
fflush(output); |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
#if defined(HAVE_TSC) |
215
|
|
|
|
|
|
|
/* measure the CPU "clocks per byte" speed */ |
216
|
0
|
0
|
|
|
|
|
if (flags & RHASH_BENCHMARK_CPB) { |
217
|
0
|
|
|
|
|
|
unsigned int c1 = -1, c2 = -1; |
218
|
|
|
|
|
|
|
unsigned volatile long long cy0, cy1, cy2; |
219
|
0
|
|
|
|
|
|
int msg_size = 128 * 1024; |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
/* make 200 tries */ |
222
|
0
|
0
|
|
|
|
|
for (i = 0; i < 200; i++) { |
223
|
0
|
|
|
|
|
|
cy0 = read_tsc(); |
224
|
0
|
|
|
|
|
|
hash_in_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out); |
225
|
0
|
|
|
|
|
|
cy1 = read_tsc(); |
226
|
0
|
|
|
|
|
|
hash_in_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out); |
227
|
0
|
|
|
|
|
|
hash_in_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out); |
228
|
0
|
|
|
|
|
|
cy2 = read_tsc(); |
229
|
|
|
|
|
|
|
|
230
|
0
|
|
|
|
|
|
cy2 -= cy1; |
231
|
0
|
|
|
|
|
|
cy1 -= cy0; |
232
|
0
|
0
|
|
|
|
|
c1 = (unsigned int)(c1 > cy1 ? cy1 : c1); |
233
|
0
|
0
|
|
|
|
|
c2 = (unsigned int)(c2 > cy2 ? cy2 : c2); |
234
|
|
|
|
|
|
|
} |
235
|
0
|
|
|
|
|
|
cpb = ((c2 - c1) + 1) / (double)msg_size; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
#endif /* HAVE_TSC */ |
238
|
|
|
|
|
|
|
|
239
|
0
|
0
|
|
|
|
|
if (flags & RHASH_BENCHMARK_RAW) { |
240
|
|
|
|
|
|
|
/* output result in a "raw" machine-readable format */ |
241
|
0
|
|
|
|
|
|
fprintf(output, "%s\t%u\t%.3f\t%.3f", hash_name, ((unsigned)sz_mb * rounds), total_time, (double)(sz_mb * rounds) / total_time); |
242
|
|
|
|
|
|
|
#if defined(HAVE_TSC) |
243
|
0
|
0
|
|
|
|
|
if (flags & RHASH_BENCHMARK_CPB) fprintf(output, "\t%.2f", cpb); |
244
|
|
|
|
|
|
|
#endif /* HAVE_TSC */ |
245
|
0
|
|
|
|
|
|
fprintf(output, "\n"); |
246
|
|
|
|
|
|
|
} else { |
247
|
0
|
|
|
|
|
|
fprintf(output, "%s %u MiB total in %.3f sec, %.3f MBps", hash_name, ((unsigned)sz_mb * rounds), total_time, (double)(sz_mb * rounds) / total_time); |
248
|
|
|
|
|
|
|
#if defined(HAVE_TSC) |
249
|
0
|
0
|
|
|
|
|
if (flags & RHASH_BENCHMARK_CPB) fprintf(output, ", CPB=%.2f", cpb); |
250
|
|
|
|
|
|
|
#endif /* HAVE_TSC */ |
251
|
0
|
|
|
|
|
|
fprintf(output, "\n"); |
252
|
|
|
|
|
|
|
} |
253
|
0
|
|
|
|
|
|
} |