| 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(__CYGWIN__)) && 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
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(__CYGWIN__) |
|
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
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(__CYGWIN__) |
|
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
|
0
|
|
|
|
|
|
void rhash_timer_start(timedelta_t* timer) |
|
77
|
|
|
|
|
|
|
{ |
|
78
|
0
|
|
|
|
|
|
get_timedelta(timer); |
|
79
|
0
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
0
|
|
|
|
|
|
double rhash_timer_stop(timedelta_t* timer) |
|
82
|
|
|
|
|
|
|
{ |
|
83
|
|
|
|
|
|
|
timedelta_t end; |
|
84
|
0
|
|
|
|
|
|
get_timedelta(&end); |
|
85
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(__CYGWIN__) |
|
86
|
|
|
|
|
|
|
*timer = end - *timer; |
|
87
|
|
|
|
|
|
|
#else |
|
88
|
0
|
|
|
|
|
|
timer->tv_sec = end.tv_sec - timer->tv_sec - (end.tv_usec >= timer->tv_usec ? 0 : 1); |
|
89
|
0
|
0
|
|
|
|
|
timer->tv_usec = end.tv_usec + (end.tv_usec >= timer->tv_usec ? 0 : 1000000 ) - timer->tv_usec; |
|
90
|
|
|
|
|
|
|
#endif |
|
91
|
0
|
|
|
|
|
|
return fsec(timer); |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(__CYGWIN__) |
|
95
|
|
|
|
|
|
|
/** |
|
96
|
|
|
|
|
|
|
* Set process priority and affinity to use all cpu's but the first one. |
|
97
|
|
|
|
|
|
|
* This improves benchmark results on a multi-cpu systems. |
|
98
|
|
|
|
|
|
|
* |
|
99
|
|
|
|
|
|
|
* @deprecated This function shall be removed soon. |
|
100
|
|
|
|
|
|
|
*/ |
|
101
|
|
|
|
|
|
|
static void benchmark_cpu_init(void) |
|
102
|
|
|
|
|
|
|
{ |
|
103
|
|
|
|
|
|
|
DWORD_PTR dwProcessMask, dwSysMask, dwDesired; |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); |
|
106
|
|
|
|
|
|
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
if ( GetProcessAffinityMask(GetCurrentProcess(), &dwProcessMask, &dwSysMask) ) { |
|
109
|
|
|
|
|
|
|
dwDesired = dwSysMask & (dwProcessMask & ~1); /* remove the first processor */ |
|
110
|
|
|
|
|
|
|
dwDesired = (dwDesired ? dwDesired : dwSysMask & ~1); |
|
111
|
|
|
|
|
|
|
if (dwDesired != 0) { |
|
112
|
|
|
|
|
|
|
SetProcessAffinityMask(GetCurrentProcess(), dwDesired); |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
#endif |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
/** |
|
119
|
|
|
|
|
|
|
* Hash a repeated message chunk by specified hash function. |
|
120
|
|
|
|
|
|
|
* |
|
121
|
|
|
|
|
|
|
* @deprecated This function shall be removed soon. |
|
122
|
|
|
|
|
|
|
* |
|
123
|
|
|
|
|
|
|
* @param hash_id hash function identifier |
|
124
|
|
|
|
|
|
|
* @param message a message chunk to hash |
|
125
|
|
|
|
|
|
|
* @param msg_size message chunk size |
|
126
|
|
|
|
|
|
|
* @param count number of chunks |
|
127
|
|
|
|
|
|
|
* @param out computed hash |
|
128
|
|
|
|
|
|
|
* @return 1 on success, 0 on error |
|
129
|
|
|
|
|
|
|
*/ |
|
130
|
0
|
|
|
|
|
|
static int hash_in_loop(unsigned hash_id, const unsigned char* message, size_t msg_size, int count, unsigned char* out) |
|
131
|
|
|
|
|
|
|
{ |
|
132
|
|
|
|
|
|
|
int i; |
|
133
|
0
|
|
|
|
|
|
struct rhash_context *context = rhash_init(hash_id); |
|
134
|
0
|
0
|
|
|
|
|
if (!context) return 0; |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
/* process the repeated message buffer */ |
|
137
|
0
|
0
|
|
|
|
|
for (i = 0; i < count; i++) rhash_update(context, message, msg_size); |
|
138
|
0
|
|
|
|
|
|
rhash_final(context, out); |
|
139
|
0
|
|
|
|
|
|
rhash_free(context); |
|
140
|
0
|
|
|
|
|
|
return 1; |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
|
|
143
|
0
|
|
|
|
|
|
void rhash_run_benchmark(unsigned hash_id, unsigned flags, FILE* output) |
|
144
|
|
|
|
|
|
|
{ |
|
145
|
|
|
|
|
|
|
unsigned char ALIGN_ATTR(64) message[8192]; /* 8 KiB */ |
|
146
|
|
|
|
|
|
|
timedelta_t timer; |
|
147
|
|
|
|
|
|
|
int i, j; |
|
148
|
|
|
|
|
|
|
size_t sz_mb, msg_size; |
|
149
|
0
|
|
|
|
|
|
double time, total_time = 0; |
|
150
|
0
|
|
|
|
|
|
const int rounds = 4; |
|
151
|
|
|
|
|
|
|
const char* hash_name; |
|
152
|
|
|
|
|
|
|
unsigned char out[130]; |
|
153
|
|
|
|
|
|
|
#ifdef HAVE_TSC |
|
154
|
0
|
|
|
|
|
|
double cpb = 0; |
|
155
|
|
|
|
|
|
|
#endif /* HAVE_TSC */ |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(__CYGWIN__) |
|
158
|
|
|
|
|
|
|
benchmark_cpu_init(); /* set cpu affinity to improve test results */ |
|
159
|
|
|
|
|
|
|
#endif |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
/* set message size for fast and slow hash functions */ |
|
162
|
0
|
|
|
|
|
|
msg_size = 1073741824 / 2; |
|
163
|
0
|
0
|
|
|
|
|
if (hash_id & (RHASH_WHIRLPOOL | RHASH_SNEFRU128 | RHASH_SNEFRU256 | RHASH_SHA3_224 | RHASH_SHA3_256 | RHASH_SHA3_384 | RHASH_SHA3_512)) { |
|
164
|
0
|
|
|
|
|
|
msg_size /= 8; |
|
165
|
0
|
0
|
|
|
|
|
} else if (hash_id & (RHASH_GOST | RHASH_GOST_CRYPTOPRO | RHASH_SHA384 | RHASH_SHA512)) { |
|
166
|
0
|
|
|
|
|
|
msg_size /= 2; |
|
167
|
|
|
|
|
|
|
} |
|
168
|
0
|
|
|
|
|
|
sz_mb = msg_size / (1 << 20); /* size in MiB */ |
|
169
|
0
|
|
|
|
|
|
hash_name = rhash_get_name(hash_id); |
|
170
|
0
|
0
|
|
|
|
|
if (!hash_name) hash_name = ""; /* benchmarking several hashes*/ |
|
171
|
|
|
|
|
|
|
|
|
172
|
0
|
0
|
|
|
|
|
for (i = 0; i < (int)sizeof(message); i++) message[i] = i & 0xff; |
|
173
|
|
|
|
|
|
|
|
|
174
|
0
|
0
|
|
|
|
|
for (j = 0; j < rounds; j++) { |
|
175
|
0
|
|
|
|
|
|
rhash_timer_start(&timer); |
|
176
|
0
|
|
|
|
|
|
hash_in_loop(hash_id, message, sizeof(message), (int)(msg_size / sizeof(message)), out); |
|
177
|
|
|
|
|
|
|
|
|
178
|
0
|
|
|
|
|
|
time = rhash_timer_stop(&timer); |
|
179
|
0
|
|
|
|
|
|
total_time += time; |
|
180
|
|
|
|
|
|
|
|
|
181
|
0
|
0
|
|
|
|
|
if ((flags & (RHASH_BENCHMARK_QUIET | RHASH_BENCHMARK_RAW)) == 0) { |
|
182
|
0
|
|
|
|
|
|
fprintf(output, "%s %u MiB calculated in %.3f sec, %.3f MBps\n", hash_name, (unsigned)sz_mb, time, (double)sz_mb / time); |
|
183
|
0
|
|
|
|
|
|
fflush(output); |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
} |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
#if defined(HAVE_TSC) |
|
188
|
|
|
|
|
|
|
/* measure the CPU "clocks per byte" speed */ |
|
189
|
0
|
0
|
|
|
|
|
if (flags & RHASH_BENCHMARK_CPB) { |
|
190
|
0
|
|
|
|
|
|
unsigned int c1 = -1, c2 = -1; |
|
191
|
|
|
|
|
|
|
unsigned volatile long long cy0, cy1, cy2; |
|
192
|
0
|
|
|
|
|
|
int msg_size = 128 * 1024; |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
/* make 200 tries */ |
|
195
|
0
|
0
|
|
|
|
|
for (i = 0; i < 200; i++) { |
|
196
|
0
|
|
|
|
|
|
cy0 = read_tsc(); |
|
197
|
0
|
|
|
|
|
|
hash_in_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out); |
|
198
|
0
|
|
|
|
|
|
cy1 = read_tsc(); |
|
199
|
0
|
|
|
|
|
|
hash_in_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out); |
|
200
|
0
|
|
|
|
|
|
hash_in_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out); |
|
201
|
0
|
|
|
|
|
|
cy2 = read_tsc(); |
|
202
|
|
|
|
|
|
|
|
|
203
|
0
|
|
|
|
|
|
cy2 -= cy1; |
|
204
|
0
|
|
|
|
|
|
cy1 -= cy0; |
|
205
|
0
|
0
|
|
|
|
|
c1 = (unsigned int)(c1 > cy1 ? cy1 : c1); |
|
206
|
0
|
0
|
|
|
|
|
c2 = (unsigned int)(c2 > cy2 ? cy2 : c2); |
|
207
|
|
|
|
|
|
|
} |
|
208
|
0
|
|
|
|
|
|
cpb = ((c2 - c1) + 1) / (double)msg_size; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
#endif /* HAVE_TSC */ |
|
211
|
|
|
|
|
|
|
|
|
212
|
0
|
0
|
|
|
|
|
if (flags & RHASH_BENCHMARK_RAW) { |
|
213
|
|
|
|
|
|
|
/* output result in a "raw" machine-readable format */ |
|
214
|
0
|
|
|
|
|
|
fprintf(output, "%s\t%u\t%.3f\t%.3f", hash_name, ((unsigned)sz_mb * rounds), total_time, (double)(sz_mb * rounds) / total_time); |
|
215
|
|
|
|
|
|
|
#if defined(HAVE_TSC) |
|
216
|
0
|
0
|
|
|
|
|
if (flags & RHASH_BENCHMARK_CPB) fprintf(output, "\t%.2f", cpb); |
|
217
|
|
|
|
|
|
|
#endif /* HAVE_TSC */ |
|
218
|
0
|
|
|
|
|
|
fprintf(output, "\n"); |
|
219
|
|
|
|
|
|
|
} else { |
|
220
|
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); |
|
221
|
|
|
|
|
|
|
#if defined(HAVE_TSC) |
|
222
|
0
|
0
|
|
|
|
|
if (flags & RHASH_BENCHMARK_CPB) fprintf(output, ", CPB=%.2f", cpb); |
|
223
|
|
|
|
|
|
|
#endif /* HAVE_TSC */ |
|
224
|
0
|
|
|
|
|
|
fprintf(output, "\n"); |
|
225
|
|
|
|
|
|
|
} |
|
226
|
0
|
|
|
|
|
|
} |