PageRenderTime 40ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/bench.c

https://github.com/earthquake/GI-John
C | 403 lines | 326 code | 62 blank | 15 comment | 74 complexity | 20fb8b3a1cc361133f8ccbedc8693510 MD5 | raw file
  1. /*
  2. * This file is part of John the Ripper password cracker,
  3. * Copyright (c) 1996-2001,2003,2004,2006,2008-2010 by Solar Designer
  4. *
  5. * ...with changes in the jumbo patch, by JimF
  6. */
  7. #if defined (__MINGW32__) || defined (_MSC_VER)
  8. #define SIGALRM SIGFPE
  9. #endif
  10. #define _XOPEN_SOURCE /* for setitimer(2) */
  11. #ifdef __ultrix__
  12. #define __POSIX
  13. #define _POSIX_SOURCE
  14. #endif
  15. #ifdef _SCO_C_DIALECT
  16. #include <limits.h>
  17. #endif
  18. #include <stdio.h>
  19. #if !defined (_MSC_VER)
  20. #include <unistd.h>
  21. #endif
  22. #include <string.h>
  23. #include <signal.h>
  24. #include <time.h>
  25. #if !defined (_MSC_VER)
  26. #include <sys/time.h>
  27. #endif
  28. #if !defined (__MINGW32__) && !defined (_MSC_VER)
  29. #include <sys/times.h>
  30. #endif
  31. #include "times.h"
  32. #include "arch.h"
  33. #include "misc.h"
  34. #include "math.h"
  35. #include "params.h"
  36. #include "memory.h"
  37. #include "signals.h"
  38. #include "formats.h"
  39. #include "bench.h"
  40. #ifndef _JOHN_BENCH_TMP
  41. #include "options.h"
  42. #include "md5_gen.h"
  43. #endif
  44. long clk_tck = 0;
  45. void clk_tck_init(void)
  46. {
  47. if (clk_tck) return;
  48. #if defined(_SC_CLK_TCK) || !defined(CLK_TCK)
  49. clk_tck = sysconf(_SC_CLK_TCK);
  50. #else
  51. clk_tck = CLK_TCK;
  52. #endif
  53. }
  54. unsigned int benchmark_time = BENCHMARK_TIME;
  55. static volatile int bench_running;
  56. static void bench_handle_timer(int signum)
  57. {
  58. bench_running = 0;
  59. }
  60. static void bench_set_keys(struct fmt_main *format,
  61. struct fmt_tests *current, int cond)
  62. {
  63. char *plaintext;
  64. int index, length;
  65. format->methods.clear_keys();
  66. length = format->params.benchmark_length;
  67. for (index = 0; index < format->params.max_keys_per_crypt; index++) {
  68. do {
  69. if (!current->ciphertext)
  70. current = format->params.tests;
  71. plaintext = current->plaintext;
  72. current++;
  73. if (cond > 0) {
  74. if ((int)strlen(plaintext) > length) break;
  75. } else
  76. if (cond < 0) {
  77. if ((int)strlen(plaintext) <= length) break;
  78. } else
  79. break;
  80. } while (1);
  81. format->methods.set_key(plaintext, index);
  82. }
  83. }
  84. char *benchmark_format(struct fmt_main *format, int salts,
  85. struct bench_results *results)
  86. {
  87. static void *binary = NULL;
  88. static int binary_size = 0;
  89. static char s_error[64];
  90. char *where;
  91. struct fmt_tests *current;
  92. int cond;
  93. #if OS_TIMER
  94. struct itimerval it;
  95. #endif
  96. clock_t start_real, end_real;
  97. #if !defined (__MINGW32__) && !defined (_MSC_VER)
  98. clock_t start_virtual, end_virtual;
  99. struct tms buf;
  100. #endif
  101. unsigned ARCH_WORD count;
  102. char *ciphertext;
  103. void *salt, *two_salts[2];
  104. int index, max;
  105. clk_tck_init();
  106. if (!(current = format->params.tests)) return "FAILED (no data)";
  107. if ((where = fmt_self_test(format))) {
  108. sprintf(s_error, "FAILED (%s)", where);
  109. return s_error;
  110. }
  111. // NOTE the format 'may' have changed upon the call to fmt_self_test() above
  112. // thus, before being fully initiallized, some formats list a salt, but after
  113. // they have NO salt. We HAVE to account for that, and clear the 'salts'
  114. // value (exmple is md5-gen which has salted and unsalted types).
  115. if (salts > 1 && format->params.salt_size == 0) salts = 1;
  116. if (format->params.binary_size > binary_size) {
  117. binary_size = format->params.binary_size;
  118. binary = mem_alloc_tiny(binary_size, MEM_ALIGN_WORD);
  119. memset(binary, 0x55, binary_size);
  120. }
  121. for (index = 0; index < 2; index++) {
  122. two_salts[index] = mem_alloc(format->params.salt_size);
  123. if ((ciphertext = format->params.tests[index].ciphertext))
  124. salt = format->methods.salt(ciphertext);
  125. else
  126. salt = two_salts[0];
  127. memcpy(two_salts[index], salt, format->params.salt_size);
  128. }
  129. if (format->params.benchmark_length > 0) {
  130. cond = (salts == 1) ? 1 : -1;
  131. salts = 1;
  132. } else
  133. cond = 0;
  134. bench_set_keys(format, current, cond);
  135. #if OS_TIMER
  136. memset(&it, 0, sizeof(it));
  137. if (setitimer(ITIMER_REAL, &it, NULL)) pexit("setitimer");
  138. #endif
  139. bench_running = 1;
  140. signal(SIGALRM, bench_handle_timer);
  141. /* Cap it at a sane value to hopefully avoid integer overflows below */
  142. if (benchmark_time > 3600)
  143. benchmark_time = 3600;
  144. /* In the future, "zero time" may mean self-tests without benchmarks */
  145. if (!benchmark_time)
  146. benchmark_time = 1;
  147. #if OS_TIMER
  148. it.it_value.tv_sec = benchmark_time;
  149. if (setitimer(ITIMER_REAL, &it, NULL)) pexit("setitimer");
  150. #else
  151. sig_timer_emu_init(benchmark_time * clk_tck);
  152. #endif
  153. #if defined (__MINGW32__) || defined (_MSC_VER)
  154. start_real = clock();
  155. #else
  156. start_real = times(&buf);
  157. start_virtual = buf.tms_utime + buf.tms_stime;
  158. start_virtual += buf.tms_cutime + buf.tms_cstime;
  159. #endif
  160. count = 0;
  161. index = salts;
  162. max = format->params.max_keys_per_crypt;
  163. do {
  164. if (!--index) {
  165. index = salts;
  166. if (!(++current)->ciphertext)
  167. current = format->params.tests;
  168. bench_set_keys(format, current, cond);
  169. }
  170. if (salts > 1) format->methods.set_salt(two_salts[index & 1]);
  171. format->methods.crypt_all(max);
  172. format->methods.cmp_all(binary, max);
  173. count++;
  174. #if !OS_TIMER
  175. sig_timer_emu_tick();
  176. #endif
  177. } while (bench_running && !event_abort);
  178. #if defined (__MINGW32__) || defined (_MSC_VER)
  179. end_real = clock();
  180. #else
  181. end_real = times(&buf);
  182. end_virtual = buf.tms_utime + buf.tms_stime;
  183. end_virtual += buf.tms_cutime + buf.tms_cstime;
  184. if (end_virtual == start_virtual) end_virtual++;
  185. results->virtual = end_virtual - start_virtual;
  186. #endif
  187. results->real = end_real - start_real;
  188. results->count = count * max;
  189. for (index = 0; index < 2; index++)
  190. MEM_FREE(two_salts[index]);
  191. return event_abort ? "" : NULL;
  192. }
  193. void benchmark_cps(unsigned ARCH_WORD count, clock_t time, char *buffer)
  194. {
  195. unsigned int cps_hi, cps_lo;
  196. int64 tmp;
  197. tmp.lo = count; tmp.hi = 0;
  198. mul64by32(&tmp, clk_tck);
  199. cps_hi = div64by32lo(&tmp, time);
  200. if (cps_hi >= 1000000)
  201. sprintf(buffer, "%uK", cps_hi / 1000);
  202. else
  203. if (cps_hi >= 100)
  204. sprintf(buffer, "%u", cps_hi);
  205. else {
  206. mul64by32(&tmp, 10);
  207. cps_lo = div64by32lo(&tmp, time) % 10;
  208. sprintf(buffer, "%u.%u", cps_hi, cps_lo);
  209. }
  210. }
  211. int benchmark_all(void)
  212. {
  213. struct fmt_main *format;
  214. char *result, *msg_1, *msg_m;
  215. struct bench_results results_1, results_m;
  216. char s_real[64], s_virtual[64];
  217. unsigned int total, failed;
  218. #ifndef _JOHN_BENCH_TMP
  219. unsigned md5_gen_first=1, md5_gen_cur=0, md5_gen_now=0;
  220. #endif
  221. total = failed = 0;
  222. #ifndef _JOHN_BENCH_TMP
  223. options.field_sep_char = 31;
  224. #endif
  225. if ((format = fmt_list))
  226. do {
  227. #ifndef _JOHN_BENCH_TMP
  228. /* Silently skip DIGEST-MD5 (for which we have no tests), unless forced */
  229. if (!format->params.tests && format != fmt_list)
  230. continue;
  231. DoAgainWithoutNext:;
  232. if (!strcmp(format->params.label, "md5-gen"))
  233. {
  234. if (md5_gen_first)
  235. {
  236. // only get here once
  237. md5_gen_first = 0;
  238. // list we are doing md5-gen
  239. if (options.subformat == NULL)
  240. {
  241. md5_gen_now = 1;
  242. options.subformat = malloc(256);
  243. sprintf(options.subformat, "md5_gen(%d)", md5_gen_cur++);
  244. }
  245. md5_gen_RESET();
  246. format->methods.valid(NULL);
  247. }
  248. }
  249. #endif
  250. printf("Benchmarking: %s%s [%s]... ",
  251. format->params.format_name,
  252. format->params.benchmark_comment,
  253. format->params.algorithm_name);
  254. fflush(stdout);
  255. switch (format->params.benchmark_length) {
  256. case -1:
  257. msg_m = "Raw";
  258. msg_1 = NULL;
  259. break;
  260. case 0:
  261. msg_m = "Many salts";
  262. msg_1 = "Only one salt";
  263. break;
  264. default:
  265. msg_m = "Short";
  266. msg_1 = "Long";
  267. }
  268. total++;
  269. if ((result = benchmark_format(format,
  270. format->params.salt_size ? BENCHMARK_MANY : 1,
  271. &results_m))) {
  272. puts(result);
  273. failed++;
  274. continue;
  275. }
  276. if (msg_1)
  277. if ((result = benchmark_format(format, 1, &results_1))) {
  278. puts(result);
  279. failed++;
  280. continue;
  281. }
  282. puts("DONE");
  283. benchmark_cps(results_m.count, results_m.real, s_real);
  284. benchmark_cps(results_m.count, results_m.virtual, s_virtual);
  285. #if !defined(__DJGPP__) && !defined(__CYGWIN32__) && !defined(__BEOS__) && !defined(__MINGW32__) && !defined (_MSC_VER)
  286. printf("%s:\t%s c/s real, %s c/s virtual\n",
  287. msg_m, s_real, s_virtual);
  288. #else
  289. printf("%s:\t%s c/s\n",
  290. msg_m, s_real);
  291. #endif
  292. if (!msg_1) {
  293. putchar('\n');
  294. #ifndef _JOHN_BENCH_TMP
  295. if (md5_gen_now)
  296. {
  297. int valid = md5_gen_IS_VALID(md5_gen_cur);
  298. while (!valid)
  299. valid = md5_gen_IS_VALID(++md5_gen_cur);
  300. if (valid == 1)
  301. {
  302. sprintf(options.subformat, "md5_gen(%d)", md5_gen_cur++);
  303. md5_gen_RESET();
  304. format->methods.valid(NULL);
  305. goto DoAgainWithoutNext;
  306. }
  307. md5_gen_now = 0;
  308. }
  309. #endif
  310. continue;
  311. }
  312. benchmark_cps(results_1.count, results_1.real, s_real);
  313. benchmark_cps(results_1.count, results_1.virtual, s_virtual);
  314. #if !defined(__DJGPP__) && !defined(__CYGWIN32__) && !defined(__BEOS__) && !defined(__MINGW32__) && !defined (_MSC_VER)
  315. printf("%s:\t%s c/s real, %s c/s virtual\n\n",
  316. msg_1, s_real, s_virtual);
  317. #else
  318. printf("%s:\t%s c/s\n\n",
  319. msg_1, s_real);
  320. #endif
  321. #ifndef _JOHN_BENCH_TMP
  322. if (md5_gen_now)
  323. {
  324. int valid = md5_gen_IS_VALID(md5_gen_cur);
  325. while (!valid)
  326. valid = md5_gen_IS_VALID(++md5_gen_cur);
  327. if (valid == 1)
  328. {
  329. sprintf(options.subformat, "md5_gen(%d)", md5_gen_cur++);
  330. md5_gen_RESET();
  331. format->methods.valid(NULL);
  332. goto DoAgainWithoutNext;
  333. }
  334. md5_gen_now = 0;
  335. }
  336. #endif
  337. } while ((format = format->next) && !event_abort);
  338. if (failed && total > 1 && !event_abort)
  339. printf("%u out of %u tests have FAILED\n", failed, total);
  340. return failed || event_abort;
  341. }