File Coverage

_test_utils.c
Criterion Covered Total %
statement 0 64 0.0
branch 0 32 0.0
condition n/a
subroutine n/a
pod n/a
total 0 96 0.0


line stmt bran cond sub pod time code
1             /* test_utils.c - functions to benchmark hash algorithms,
2             *
3             * Copyright (c) 2010, Aleksey Kravchenko
4             *
5             * Permission to use, copy, modify, and/or distribute this software for any
6             * purpose with or without fee is hereby granted.
7             *
8             * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9             * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10             * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11             * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12             * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13             * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14             * PERFORMANCE OF THIS SOFTWARE.
15             */
16              
17             #include "test_utils.h"
18              
19             #ifdef USE_RHASH_DLL
20             # define RHASH_API __declspec(dllimport)
21             #endif
22             #include "byte_order.h"
23             #include "rhash.h"
24              
25             #if defined(_WIN32) || defined(__CYGWIN__)
26             /**
27             * Platform-dependent time delta.
28             */
29             typedef unsigned long long timedelta_t;
30              
31             #else
32             # include /* for timeval */
33             /**
34             * Platform-dependent time delta.
35             */
36             typedef struct timeval timedelta_t;
37             #endif
38              
39             /* DEFINE read_tsc() if possible */
40              
41             #if (defined(CPU_IA32)) || defined(CPU_X64)
42              
43             #if defined( _MSC_VER ) /* if MS VC */
44             # include
45             # pragma intrinsic( __rdtsc )
46             # define read_tsc() __rdtsc()
47             # define HAVE_TSC
48             #elif defined( __GNUC__ ) /* if GCC */
49 0           static uint64_t read_tsc(void) {
50             unsigned long lo, hi;
51 0           __asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
52 0           return (((uint64_t)hi) << 32) + lo;
53             }
54             # define HAVE_TSC
55             #endif /* _MSC_VER, __GNUC__ */
56             #endif /* CPU_IA32, CPU_X64 */
57              
58              
59             /* TIMER FUNCTIONS */
60              
61             #if defined(_WIN32) || defined(__CYGWIN__)
62             #include
63             #define get_timedelta(delta) QueryPerformanceCounter((LARGE_INTEGER*)delta)
64             #else
65             #define get_timedelta(delta) gettimeofday(delta, NULL)
66             #endif
67              
68             /**
69             * Return real-value representing number of seconds
70             * stored in the given timeval structure.
71             * The function is used with timers, when printing time statistics.
72             *
73             * @deprecated This function shall be removed soon
74             *
75             * @param delta time delta to be converted
76             * @return number of seconds
77             */
78 0           static double fsec(timedelta_t* timer)
79             {
80             #if defined(_WIN32) || defined(__CYGWIN__)
81             LARGE_INTEGER freq;
82             QueryPerformanceFrequency(&freq);
83             return (double)*timer / freq.QuadPart;
84             #else
85 0           return ((double)timer->tv_usec / 1000000.0) + timer->tv_sec;
86             #endif
87             }
88              
89 0           static void rhash_timer_start(timedelta_t* timer)
90             {
91 0           get_timedelta(timer);
92 0           }
93              
94 0           static double rhash_timer_stop(timedelta_t* timer)
95             {
96             timedelta_t end;
97 0           get_timedelta(&end);
98             #if defined(_WIN32) || defined(__CYGWIN__)
99             *timer = end - *timer;
100             #else
101 0           timer->tv_sec = end.tv_sec - timer->tv_sec - (end.tv_usec >= timer->tv_usec ? 0 : 1);
102 0 0         timer->tv_usec = end.tv_usec + (end.tv_usec >= timer->tv_usec ? 0 : 1000000 ) - timer->tv_usec;
103             #endif
104 0           return fsec(timer);
105             }
106              
107             #if defined(_WIN32) || defined(__CYGWIN__)
108             /**
109             * Set process priority and affinity to use all cpu's but the first one.
110             * This improves benchmark results on a multi-cpu systems.
111             *
112             * @deprecated This function shall be removed soon
113             */
114             static void benchmark_cpu_init(void)
115             {
116             DWORD_PTR dwProcessMask, dwSysMask, dwDesired;
117              
118             SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
119             SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
120              
121             if ( GetProcessAffinityMask(GetCurrentProcess(), &dwProcessMask, &dwSysMask) ) {
122             dwDesired = dwSysMask & (dwProcessMask & ~1); /* remove the first processor */
123             dwDesired = (dwDesired ? dwDesired : dwSysMask & ~1);
124             if (dwDesired != 0) {
125             SetProcessAffinityMask(GetCurrentProcess(), dwDesired);
126             }
127             }
128             }
129             #endif
130              
131             /**
132             * Hash a repeated message chunk by specified hash function.
133             *
134             * @deprecated This function shall be removed soon
135             *
136             * @param hash_id hash function identifier
137             * @param message a message chunk to hash
138             * @param msg_size message chunk size
139             * @param count number of chunks
140             * @param out computed hash
141             * @return 1 on success, 0 on error
142             */
143 0           static int hash_in_loop(unsigned hash_id, const unsigned char* message, size_t msg_size, int count, unsigned char* out)
144             {
145             int i;
146 0           struct rhash_context* context = rhash_init(hash_id);
147 0 0         if (!context) return 0;
148              
149             /* process the repeated message buffer */
150 0 0         for (i = 0; i < count; i++) rhash_update(context, message, msg_size);
151 0           rhash_final(context, out);
152 0           rhash_free(context);
153 0           return 1;
154             }
155              
156 0           void test_run_benchmark(unsigned hash_id, unsigned flags, FILE* output)
157             {
158             unsigned char ALIGN_ATTR(64) message[8192]; /* 8 KiB */
159             timedelta_t timer;
160             int i, j;
161             size_t sz_mb, msg_size;
162 0           double time, total_time = 0;
163 0           const int rounds = 4;
164             const char* hash_name;
165             unsigned char out[130];
166             #ifdef HAVE_TSC
167 0           double cpb = 0;
168             #endif /* HAVE_TSC */
169              
170             #if defined(_WIN32) || defined(__CYGWIN__)
171             benchmark_cpu_init(); /* set cpu affinity to improve test results */
172             #endif
173              
174             /* set message size for fast and slow hash functions */
175 0           msg_size = 1073741824 / 2;
176 0 0         if (hash_id & (RHASH_WHIRLPOOL | RHASH_SNEFRU128 | RHASH_SNEFRU256 | RHASH_SHA3_224 | RHASH_SHA3_256 | RHASH_SHA3_384 | RHASH_SHA3_512)) {
177 0           msg_size /= 8;
178 0 0         } else if (hash_id & (RHASH_GOST94 | RHASH_GOST94_CRYPTOPRO | RHASH_SHA384 | RHASH_SHA512)) {
179 0           msg_size /= 2;
180             }
181 0           sz_mb = msg_size / (1 << 20); /* size in MiB */
182 0           hash_name = rhash_get_name(hash_id);
183 0 0         if (!hash_name) hash_name = ""; /* benchmarking several hashes*/
184              
185 0 0         for (i = 0; i < (int)sizeof(message); i++) message[i] = i & 0xff;
186              
187 0 0         for (j = 0; j < rounds; j++) {
188 0           rhash_timer_start(&timer);
189 0           hash_in_loop(hash_id, message, sizeof(message), (int)(msg_size / sizeof(message)), out);
190              
191 0           time = rhash_timer_stop(&timer);
192 0           total_time += time;
193              
194 0 0         if ((flags & (RHASH_BENCHMARK_QUIET | RHASH_BENCHMARK_RAW)) == 0) {
195 0           fprintf(output, "%s %u MiB calculated in %.3f sec, %.3f MBps\n", hash_name, (unsigned)sz_mb, time, (double)sz_mb / time);
196 0           fflush(output);
197             }
198             }
199              
200             #if defined(HAVE_TSC)
201             /* measure the CPU "clocks per byte" speed */
202 0 0         if (flags & RHASH_BENCHMARK_CPB) {
203 0           unsigned int c1 = -1, c2 = -1;
204             unsigned volatile long long cy0, cy1, cy2;
205 0           int msg_size = 128 * 1024;
206              
207             /* make 200 tries */
208 0 0         for (i = 0; i < 200; i++) {
209 0           cy0 = read_tsc();
210 0           hash_in_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out);
211 0           cy1 = read_tsc();
212 0           hash_in_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out);
213 0           hash_in_loop(hash_id, message, sizeof(message), msg_size / sizeof(message), out);
214 0           cy2 = read_tsc();
215              
216 0           cy2 -= cy1;
217 0           cy1 -= cy0;
218 0 0         c1 = (unsigned int)(c1 > cy1 ? cy1 : c1);
219 0 0         c2 = (unsigned int)(c2 > cy2 ? cy2 : c2);
220             }
221 0           cpb = ((c2 - c1) + 1) / (double)msg_size;
222             }
223             #endif /* HAVE_TSC */
224              
225 0 0         if (flags & RHASH_BENCHMARK_RAW) {
226             /* output result in a "raw" machine-readable format */
227 0           fprintf(output, "%s\t%u\t%.3f\t%.3f", hash_name, ((unsigned)sz_mb * rounds), total_time, (double)(sz_mb * rounds) / total_time);
228             #if defined(HAVE_TSC)
229 0 0         if (flags & RHASH_BENCHMARK_CPB) fprintf(output, "\t%.2f", cpb);
230             #endif /* HAVE_TSC */
231 0           fprintf(output, "\n");
232             } else {
233 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);
234             #if defined(HAVE_TSC)
235 0 0         if (flags & RHASH_BENCHMARK_CPB) fprintf(output, ", CPB=%.2f", cpb);
236             #endif /* HAVE_TSC */
237 0           fprintf(output, "\n");
238             }
239 0           }