Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/naniya/mty/mty.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 244 - (show annotations) (download) (as text)
Tue Mar 16 13:54:51 2010 UTC (14 years, 2 months ago) by chapuni
File MIME type: text/x-csrc
File size: 14304 byte(s)
ヒット判定 hit.c, ログ出力 log.c を mty.c から分離。
1 /***********************************************************************
2 *
3 * file: mty.c
4 *
5 * まあ、待て屋。
6 *
7 * $Id$
8 *
9 */
10
11 #include <assert.h>
12 #include <stddef.h>
13 #include <stdio.h>
14 #include <time.h>
15 #include <sys/timeb.h>
16
17 #if defined(WIN32)
18
19 #include <windows.h>
20 #include <process.h>
21
22 #elif defined(__GNUC__)
23
24 #include <sys/time.h>
25
26 #endif
27
28 #include "desconst.h"
29 #include "expr_parse.h"
30 #include "hit.h"
31 #include "key.h"
32 #include "log.h"
33 #include "scoreboard.h"
34 #include "synth.h"
35 #include "util.h"
36
37 static HANDLE mutex_key;
38
39 /* CRYPT64 記述子 */
40 static
41 struct CRYPT64_DESC const *const crypt64_descs[] =
42 {
43 &crypt64_desc,
44 };
45
46 /* 速度評価用 */
47 static int n_cpus;
48 static uint64_t loop_cpu[1024];
49
50 #define USEC_SEC 1000 /* 1秒 */
51
52 static
53 uint64_t
54 usec(void)
55 {
56 uint32_t sec, msec;
57
58 #if !defined(WIN32)
59 struct timeval tv;
60 gettimeofday(&tv, NULL);
61 sec = tv.tv_sec;
62 msec = tv.tv_usec / (1000000 / USEC_SEC);
63 #else
64 struct timeb tm;
65 ftime(&tm);
66 sec = tm.time;
67 msec = tm.millitm / (1000 / USEC_SEC);
68 #endif
69
70 return (uint64_t)USEC_SEC * sec + msec;
71 }
72
73 /***************************************************************
74 *
75 * CPU capabilities を取得
76 * [XXX] あまりにも古いプロセッサのことは考えない。
77 *
78 * a[4] = {EAX,EBX,ECX,EDX}
79 *
80 */
81
82 #if defined(__GNUC__)
83
84 #define cpuid(n,a,b,c,d) \
85 asm("cpuid" \
86 : "=a"(a), "=b"(b), "=c"(c), "=d"(d) \
87 : "a"(n))
88
89 #elif defined(WIN32)
90
91 #define cpuid(n,a,b,c,d) \
92 do {int r[4]; __cpuid(r,n); \
93 (a) = r[0]; (b) = r[1]; (c) = r[2]; (d) = r[3];} while (0)
94
95 #endif
96
97 static
98 unsigned
99 cpuid_getfflags(void)
100 {
101 unsigned a, b, c, d;
102 cpuid(1, a, b, c, d);
103 return d;
104 }
105
106 static
107 int
108 cpuid_issupported(void)
109 {
110 unsigned m = REQUIRED_CAPS;
111 return !((cpuid_getfflags() ^ m) & m);
112 }
113
114 /***************************************************************
115 *
116 * バッチ処理用パケット
117 *
118 */
119
120 static
121 struct PACKET_CRYPT64 *
122 packet_create(int n, /* パケット数 */
123 int tn, /* 末尾要素にて必要なワーク数 */
124 uint8_t const *ini_key)
125 {
126 int i;
127 int siz;
128 void *p;
129 intptr_t a = 128;
130 struct PACKET_CRYPT64 *pkts;
131 assert(IS_POWER2(sizeof(struct PACKET_CRYPT64)));
132 assert(n >= 1);
133
134 siz = (a - 1
135 + (n - 1) * sizeof(struct PACKET_CRYPT64)
136 + offsetof(struct PACKET_CRYPT64, param64.hit[tn]));
137 p = calloc(siz, 1);
138 /* バンダリあわせ */
139 pkts = (struct PACKET_CRYPT64 *)(((intptr_t)p
140 + a - 1)
141 & -a);
142 #if DEBUG>=1
143 fprintf(stderr,
144 "packet(n=%d,tn=%d) %d allocated; %p aligned to %p\n",
145 n, tn,
146 siz, p, pkts);
147 #endif
148
149 /* 内部の初期化
150 コピーして回るのは、厳密には
151 最終要素のケツを破ってしまうことになるので
152 どうせ速度も要求されないしベタコード */
153 for (i = 0; i < n; i++)
154 {
155 int j, k;
156
157 /* t[16] は、内部演算で使用する、all 1 が入っている */
158 memset(&pkts[i].param64.t[T_INV], -1, sizeof(SLICE));
159
160 /* 固定キーの生成 */
161 key_init_sk(&pkts[i].key64);
162
163 /* キースケジュールをここに押し込めておく
164 従来は crypt64.S 内で完結するように引いていた */
165 for (j = 0; j < 28; j++)
166 for (k = 0; k < N_ALU; k++)
167 pkts[i].key64.ks[j].a[k] = sizeof(WS_T) * ks_ls[j];
168
169 /* 念のため、鍵をここで落ち着けておく(不要?) */
170 for (j = 0; j < 8; j++)
171 key_set64(&pkts[i].key64, j, pkts[i].uk.key[j] = ini_key[j], 0, 0x7F);
172 }
173
174 return pkts;
175 }
176
177 /***************************************************************
178 *
179 * thread
180 *
181 */
182
183 #if defined(__GNUC__)
184
185 typedef int32_t ATOMWORD_T;
186
187 #define LOCK_INC(p) \
188 asm volatile ("lock incl %0" \
189 : "=m"(*(p)) \
190 : /*nil*/ \
191 : "memory")
192
193 #define LOCK_DEC(p) \
194 asm volatile ("lock decl %0" \
195 : "=m"(*(p)) \
196 : /*nil*/ \
197 : "memory")
198
199 #define LOCK_CAS(pd,s,r) \
200 ({ ATOMWORD_T a; \
201 asm volatile ("lock cmpxchg %2,%1" \
202 : "=a"(a) \
203 : "m"(*(pd)), "r"(s), "0"(r) \
204 : "memory");a;})
205
206 #define LOCK_CASP(pd,s,r) \
207 ({ void *a; \
208 asm volatile ("lock cmpxchg %2,%1" \
209 : "=a"(a) \
210 : "m"(*(pd)), "r"(s), "0"(r) \
211 : "memory");a;})
212
213 #elif defined(WIN32)
214
215 typedef LONG ATOMWORD_T;
216
217 #define LOCK_INC(p) InterlockedIncrement((LONG *)(p))
218 #define LOCK_DEC(p) InterlockedDecrement((LONG *)(p))
219 #define LOCK_CAS(pd,s,r) InterlockedCompareExchange((LONG *)(pd), s, r)
220 #define LOCK_CASP(pd,s,r) InterlockedCompareExchangePointer((PVOID *)(pd), (PVOID)(s), (PVOID)r)
221
222 #else
223 #error "configuration not implemented"
224 #endif
225
226 #if defined(WIN32)
227
228 typedef DWORD THREAD_TIMEOUT_T;
229
230 #define THREAD_INFINITE INFINITE
231
232 typedef HANDLE THREAD_TH_T;
233
234 #define thread_sleep(n) Sleep(n)
235 #define thread_create(th, proc, arg) {(th) = (HANDLE)_beginthread(proc, 8192, arg);}
236 #define thread_get_tid() GetCurrentThread()
237 #define thread_set_priority(tid,n) SetThreadPriority(tid, n)
238 #define thread_set_affinity(tid,m) SetThreadAffinityMask(tid, (DWORD_PTR)1 << (m))
239
240 #elif defined(_POSIX_SOURCE)
241
242 #include <pthread.h>
243 #include <unistd.h>
244
245 typedef int THREAD_TIMEOUT_T;
246
247 #define THREAD_INFINITE INT_MAX
248
249 #if defined(THREAD_PRIORITY_BELOW_NOROMAL) || defined(THREAD_PRIORITY_IDLE)
250 #error "unsupported implementation"
251 #endif
252
253 #define THREAD_PRIORITY_NORMAL 14
254 #define THREAD_PRIORITY_BELOW_NORMAL 15
255 #define THREAD_PRIORITY_IDLE 16
256
257 typedef pthread_t THREAD_TH_T;
258
259 #define thread_sleep(n) (usleep(1000 * (n)) != EINVAL || sleep((n) / 1000))
260 #define thread_create(th, proc, arg) thread_create_p(&(th), proc, arg)
261
262 static
263 void
264 thread_create_p(pthread_t *th, NORETURN (*proc)(void *), void *param)
265 {
266 pthread_create(th, NULL, (void *(*)(void *))proc, param);
267 }
268
269 #if defined(__linux__)
270
271 /* デフォルトスケジューリングポリシーでは
272 優先度設定したりアイドルスレッド起こしても
273 おもしろくないので、そのへんは今後の研究課題。 */
274
275 #include <linux/unistd.h>
276 _syscall0(pid_t,gettid)
277
278 #define thread_get_tid() gettid()
279
280 static
281 int thread_set_affinity(pid_t tid, int i)
282 {
283 cpu_set_t m;
284 CPU_ZERO(&m);
285 CPU_SET(i, &m);
286 return sched_setaffinity(tid, sizeof(m), &m);
287 }
288
289 #else
290
291 /* POSIX では、スレッド単位のスケジューリングに介入できない。 */
292
293 #endif
294
295 #else
296 #error "configuration not supported"
297 #endif
298
299 struct THREAD_PARAM
300 {
301 /* 以下は共通情報のコピー */
302 CODE_T *code;
303 off_t code_cmp;
304 unsigned seed;
305
306 /* 以下はスレッド固有 */
307 #ifdef thread_set_priority
308 int pri;
309 #endif
310 };
311
312 static
313 uint64_t
314 thread_avail(void)
315 {
316 #if !USE_MT
317
318 return 0x1U;
319
320 #elif defined(WIN32) /* Win32 API */
321 DWORD_PTR mask, mask_s;
322 if (!GetProcessAffinityMask(GetCurrentProcess(),
323 &mask,
324 &mask_s)
325 || !mask
326 || !mask_s)
327 return 0x1U;
328 #if DEBUG>=1
329 fprintf(stderr,
330 "m=%08X s=%08X\n",
331 (unsigned)mask,
332 (unsigned)mask_s);
333 #endif
334 if (popcnt64(mask_s) == 1)
335 /* 何も言うまい */;
336 else if (mask == mask_s)
337 fprintf(stderr,
338 "通常の%d倍とはよく言ったものです。\n",
339 popcnt64(mask));
340 else
341 fprintf(stderr,
342 "最高速力の%g倍の力でてきとうにがんばるよ。\n",
343 (double)popcnt64(mask) / popcnt64(mask_s));
344 return mask;
345
346 #elif defined(__linux__) /* sched.h 拡張 */
347
348 int i;
349 uint64_t m = 0;
350 cpu_set_t am;
351 if (sched_getaffinity(getpid(), sizeof(am), &am) < 0)
352 return 0x1U;
353
354 for (i = 0; i < 64 && i < CPU_SETSIZE; i++)
355 if (CPU_ISSET(i, &am))
356 m |= 1ULL << i;
357
358 return m;
359 #else
360
361 /* XXX プロセッサ数を調べ上げてください */
362 return 0x01U;
363
364 #endif
365 }
366
367 static
368 NORETURN
369 thread_crypt64_new(void *a_param)
370 {
371 struct THREAD_PARAM *param = a_param;
372 CODE_T *code = param->code;
373 CODE_T *cmp = code + param->code_cmp;
374 struct KS_KEY key;
375 struct PACKET_CRYPT64 *pkt = packet_create(16, 1024, key.key);
376 uint64_t *ploop;
377 THREAD_TH_T th = thread_get_tid();
378
379 WaitForSingleObject(mutex_key, INFINITE);
380
381 ploop = &loop_cpu[n_cpus++];
382
383 srand(usec() ^ param->seed ^ (unsigned)th);
384 key_init(&key);
385 ReleaseMutex(mutex_key);
386
387 #ifdef thread_set_priority
388 thread_set_priority(th, param->pri);
389 #endif
390
391 for (;;)
392 {
393 do
394 {
395 int j;
396 for (j = 0; j < 8; j++)
397 {
398 key_set64(&pkt->key64, j, key.key[j], key.key[j] ^ pkt->uk.key[j], 0);
399 pkt->uk.key[j] = key.key[j];
400 }
401 CALL_CRYPT64(code,
402 &pkt->key64,
403 &pkt->param64);
404 CALL_CMP64(cmp,
405 pkt->param64.hit,
406 pkt->param64.lr);
407 check_hit(pkt, pkt->param64.hit);
408 *ploop += N_ALU * ALU_BITS;
409 }
410 while (key_inc(&key, 6, 8) || key_inc(&key, KEY_SHUFFLE_POS, 8));
411
412 WaitForSingleObject(mutex_key, INFINITE);
413 key_reset(&key, 0);
414 ReleaseMutex(mutex_key);
415 }
416
417 /* notreached */
418 }
419
420 /***************************************************************
421 *
422 * メインループとか
423 *
424 */
425
426 int
427 main(int argc, char *argv[])
428 {
429 int i;
430 int mincnt;
431 CODE_T *code = NULL;
432 off_t code_cmp;
433 FILE *sfp; /* scoreboard */
434 struct ITREE *root_expr;
435 uint64_t proc_mask;
436 struct THREAD_PARAM *threads = NULL;
437 int nthreads;
438 int tn;
439 int cr;
440
441 /* 鍵文字列 */
442 struct KS_KEY key;
443
444 #define UPDATE_INTERVAL 8 /* 速度表示の間隔 秒 */
445 struct status {
446 uint64_t startTime; /* 開始時刻 ミリ秒 */
447 uint64_t lastTime; /* 最後に表示した時刻 ミリ秒 */
448 uint64_t loop; /* 総検索個数 */
449 uint64_t lastloop; /* 最後に表示した時の loop */
450 } status;
451 uint64_t curTime;
452 uint32_t upd_int = 0;
453 /*
454 平均速度 (trips/s) * UPDATE_INTERVAL が UINT32_MAX を超えると発狂する。
455 UINT32_MAX = 4294967295, 平均速度 = 100Mtrips/s なら、
456 4294967295 / (100 * 1000 * 1000) = 42.949 秒まで。(和良
457 LOOP_FACTOR が平均速度より十分小さければ、ほぼ指定間隔になる。
458 LOOP_FACTOR * UINT32_MAX + LOOP_FACOTR 個検索するとオーバーフローする。w
459 */
460
461 if (!cpuid_issupported())
462 {
463 fprintf(stderr, "この環境で走らせることが想定されていません。\n");
464 exit(1);
465 }
466
467 assert((1 << N_STRIDE) == N_ALU * ALU_BITS);
468
469 mutex_key = CreateMutex(NULL, FALSE, NULL);
470
471 /* タゲ読み込み */
472 root_expr = expr_parse("target.txt");
473
474 /* コードを生成・展開
475 起動予定スレッド数に応じて
476 生成するコードを変える */
477 sfp = scoreboard_open();
478 fwrite(crypt64_descs[0]->pro, 1, crypt64_descs[0]->cmp_pro - crypt64_descs[0]->pro, sfp); /* prologue & コアループ */
479 proc_mask = thread_avail();
480
481 #if 0
482 if (0&&proc_mask == 1U)
483 {
484 /* single */
485 code_cmp = 0;
486 }
487 else
488 #endif
489 {
490 /* multi */
491 fwrite(crypt64_descs[0]->ep, 1, crypt64_descs[0]->ep_end - crypt64_descs[0]->ep, sfp); /* epilogue */
492
493 /* 比較器のみを生成(前半) */
494 code_cmp = ftell(sfp);
495 fseek(sfp, (-code_cmp) & 63, SEEK_CUR);
496 code_cmp = ftell(sfp);
497 fwrite(crypt64_descs[0]->pro, 1, crypt64_descs[0]->crypt - crypt64_descs[0]->pro, sfp); /* prologue */
498 }
499
500 /* 比較部を生成 */
501 fwrite(crypt64_descs[0]->cmp_pro, 1, crypt64_descs[0]->cmp_ep - crypt64_descs[0]->cmp_pro, sfp); /* 比較器準備 */
502 tn = synth_synthesize(sfp, root_expr);
503 fwrite(crypt64_descs[0]->cmp_ep, 1, crypt64_descs[0]->ep_end - crypt64_descs[0]->cmp_ep, sfp); /* epilogue */
504
505 /* コードをメモリに貼り付ける */
506 code = scoreboard_map(sfp);
507
508 /* キーの初期化 */
509 WaitForSingleObject(mutex_key, INFINITE);
510 srand(usec());
511 key_init(&key);
512 ReleaseMutex(mutex_key);
513 set_salt(code, crypt64_descs[0], key.key);
514
515 if (log_open("log.txt") != 0) return 1;
516
517 WaitForSingleObject(mutex_key, INFINITE);
518
519 /* 働くおじさんを量産 */
520 nthreads = 0;
521 if (code_cmp)
522 {
523 THREAD_TH_T h;
524 int ots = -1;
525 threads = calloc(2 * popcnt64(proc_mask), sizeof(*threads));
526 for (i = 0; i < 64; i++)
527 if (proc_mask & (1ULL << i))
528 {
529 if (0&&ots < 0)
530 {
531 /* 自分自身のスケジューリング
532 こーゆー系のアプリは低めに設定するのが吉(かも) */
533 #ifdef WIN32
534 h = GetCurrentProcess();
535 SetPriorityClass(h, BELOW_NORMAL_PRIORITY_CLASS);
536 #endif
537 #if defined(thread_set_priority)
538 /* 心の隙間お埋めします */
539 threads[nthreads].code = code;
540 threads[nthreads].code_cmp = code_cmp;
541 threads[nthreads].seed = rand();
542 threads[nthreads].pri = THREAD_PRIORITY_IDLE;
543 thread_create(h, thread_crypt64_new, &threads[nthreads]);
544 nthreads++;
545 #endif
546 if (!code_cmp)
547 break;
548
549 /* 自分自身の残りの設定を、あとでやる */
550 ots = i;
551 }
552 else
553 {
554 /* 他スレッドは、やや低めの優先度で。 */
555 threads[nthreads].code = code;
556 threads[nthreads].code_cmp = code_cmp;
557 threads[nthreads].seed = rand();
558 #ifdef thread_set_priority
559 //threads[nthreads].pri = THREAD_PRIORITY_BELOW_NORMAL;
560 threads[nthreads].pri = THREAD_PRIORITY_LOWEST;
561 #endif
562 thread_create(h, thread_crypt64_new, &threads[nthreads]);
563 #ifdef thread_get_tid
564 thread_set_affinity(h, i);
565 #endif
566 nthreads++;
567 #if 1
568 /* IDLE */
569 threads[nthreads].code = code;
570 threads[nthreads].code_cmp = code_cmp;
571 threads[nthreads].seed = rand();
572 #ifdef thread_set_priority
573 threads[nthreads].pri = THREAD_PRIORITY_IDLE;
574 #endif
575 thread_create(h, thread_crypt64_new, &threads[nthreads]);
576 #ifdef thread_get_tid
577 SetThreadAffinityMask(h, proc_mask);
578 #endif
579 nthreads++;
580 #endif
581 }
582 }
583 #ifdef thread_get_tid
584 if (ots)
585 thread_set_affinity(thread_get_tid(), ots);
586 #endif
587 }
588
589 fprintf(stderr, "検索開始!\n");
590 ReleaseMutex(mutex_key);
591
592 mincnt = 0x7FFFFFFF;
593
594 cr = 0;
595 memset( &status, 0, sizeof( struct status ) );
596 status.startTime = status.lastTime = usec();
597
598 /* 探索ループだぞっと */
599 for (;;)
600 {
601 Sleep(5000);
602
603 /* 速度計測 */
604 status.loop = 0;
605 for (i = 0; i < n_cpus; i++) status.loop += loop_cpu[i];
606
607 if (status.loop >= status.lastloop + upd_int
608 && (curTime = usec()) != status.lastTime)
609 {
610 uint64_t diffTime;
611 int a, b, c;
612 /* 通算(単位 ktrips/sec) */
613 diffTime = curTime - status.startTime;
614 a = status.loop / ((1000 / USEC_SEC) * diffTime);
615
616 /* 区間(単位 trips/sec) */
617 diffTime = curTime - status.lastTime;
618 b = USEC_SEC * (status.loop - status.lastloop) / diffTime;
619
620 /* 予測 */
621 c = UPDATE_INTERVAL * b;
622
623 /* 立ち上がりなど、誤差があり upd_int が小さすぎたときは
624 いきなり全補正せず 1 秒(==b)づつ収斂させる。 */
625 upd_int = (upd_int + b < c
626 ? upd_int + b
627 : c);
628
629 status.lastTime = curTime;
630 status.lastloop = status.loop;
631 #if DEBUG>=1
632 fprintf(stderr,
633 "%5d/%5d(%3d%%)",
634 nblk_hit, nblk_total, 100 * nblk_hit / nblk_total);
635 nblk_hit = nblk_total = 0;
636 if (nap_total)
637 fprintf(stderr,
638 " %5d/%5d(%3d%%)",
639 nap_hit, nap_total, 100 * nap_hit / nap_total);
640 else
641 fprintf(stderr,
642 " -----/-----(---%%)");
643 nap_hit = nap_total = 0;
644 #endif
645 fprintf(stderr,
646 "%4d.%03dMtrips/s [%4d.%06dMtrips/s]\r",
647 a / 1000, a % 1000,
648 b / 1000000, b % 1000000);
649 cr++;
650 }
651 }
652
653 return 0;
654 }
655
656 /*
657 * Local Variables:
658 * tab-width: 4
659 * End:
660 *
661 * EOF */

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Rev URL

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26