Annotation of OpenXM_contrib/gmp/tune/tuneup.c, Revision 1.1.1.1
1.1 maekawa 1: /* Create tuned thresholds for various algorithms. */
2:
3: /*
4: Copyright (C) 1999, 2000 Free Software Foundation, Inc.
5:
6: This file is part of the GNU MP Library.
7:
8: The GNU MP Library is free software; you can redistribute it and/or modify
9: it under the terms of the GNU Lesser General Public License as published by
10: the Free Software Foundation; either version 2.1 of the License, or (at your
11: option) any later version.
12:
13: The GNU MP Library is distributed in the hope that it will be useful, but
14: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16: License for more details.
17:
18: You should have received a copy of the GNU Lesser General Public License
19: along with the GNU MP Library; see the file COPYING.LIB. If not, write to
20: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21: MA 02111-1307, USA.
22: */
23:
24: /* Usage: tune [-t] [-t] [-p precision]
25:
26: -t turns on some diagnostic traces, a second -t turns on more traces.
27:
28: The thresholds are determined as follows. A crossover may not be a
29: single size but rather a range where it oscillates between method A or
30: method B faster. If the threshold is set making B used where A is faster
31: (or vice versa) that's bad. Badness is the percentage time lost and
32: total badness is the sum of this over all sizes measured. The threshold
33: is set to minimize total badness.
34:
35: Suppose, as sizes increase, method B becomes faster than method A. The
36: effect of the rule is that, as you look at increasing sizes, isolated
37: points where B is faster are ignored, but when it's consistently faster,
38: or faster on balance, then the threshold is set there. The same result
39: is obtained thinking in the other direction of A becoming faster at
40: smaller sizes.
41:
42: In practice the thresholds tend to be chosen to bring on the next
43: algorithm fairly quickly.
44:
45: This rule is attractive because it's got a basis in reason and is fairly
46: easy to implement, but no work has been done to actually compare it in
47: absolute terms to other possibilities.
48:
49: Sometimes running the program twice produces slightly different results.
50: This is probably because there's so little separating algorithms near
51: their crossover, and on that basis it should make little or no difference
52: to the final speed of the relevant routines, but nothing has been done to
53: check that carefully.
54:
55: Limitations:
56:
57: The FFTs aren't subject to the same badness rule as the other thresholds,
58: so each k is probably being brought on a touch early. This isn't likely
59: to make a difference, and the simpler probing means fewer tests.
60:
61: */
62:
63: #define TUNE_PROGRAM_BUILD 1
64:
65: #include <math.h>
66: #include <stdio.h>
67: #include <stdlib.h>
68: #include <time.h>
69: #include <unistd.h>
70:
71: #include "gmp.h"
72: #include "gmp-impl.h"
73:
74: #include "speed.h"
75: #include "sqr_basecase.h"
76:
77: #if !HAVE_DECL_OPTARG
78: extern char *optarg;
79: extern int optind, opterr;
80: #endif
81:
82:
83: #define MAX_SIZE 1000 /* limbs */
84: #define STEP_FACTOR 0.01 /* how much to step sizes by (rounded down) */
85: #define MAX_TABLE 2 /* threshold entries */
86:
87:
88: #if WANT_FFT
89: mp_size_t option_fft_max_size = 50000; /* limbs */
90: #else
91: mp_size_t option_fft_max_size = 0;
92: #endif
93: int option_trace = 0;
94: int option_fft_trace = 0;
95: struct speed_params s;
96:
97: struct dat_t {
98: mp_size_t size;
99: double d;
100: } *dat = NULL;
101: int ndat = 0;
102: int allocdat = 0;
103:
104:
105: /* Each "_threshold" array must be 1 bigger than the number of thresholds
106: being tuned in a set, because one() stores an value in the entry above
107: the one it's determining. */
108:
109: mp_size_t mul_threshold[MAX_TABLE+1] = { MP_SIZE_T_MAX };
110: mp_size_t fft_modf_mul_threshold = MP_SIZE_T_MAX;
111: mp_size_t sqr_threshold[MAX_TABLE+1] = { MP_SIZE_T_MAX };
112: mp_size_t fft_modf_sqr_threshold = MP_SIZE_T_MAX;
113: mp_size_t bz_threshold[2] = { MP_SIZE_T_MAX };
114: mp_size_t fib_threshold[2] = { MP_SIZE_T_MAX };
115: mp_size_t powm_threshold[2] = { MP_SIZE_T_MAX };
116: mp_size_t gcd_accel_threshold[2] = { MP_SIZE_T_MAX };
117: mp_size_t gcdext_threshold[2] = { MP_SIZE_T_MAX };
118:
119:
120: #ifndef KARATSUBA_SQR_MAX
121: #define KARATSUBA_SQR_MAX 0 /* meaning no limit */
122: #endif
123:
124: struct param_t {
125: const char *name[MAX_TABLE];
126: int stop_since_change;
127: mp_size_t min_size;
128: mp_size_t max_size[MAX_TABLE];
129: };
130:
131:
132: /* Add an entry to the end of the dat[] array, reallocing to make it bigger
133: if necessary. */
134: void
135: add_dat (mp_size_t size, double d)
136: {
137: #define ALLOCDAT_STEP 500
138:
139: ASSERT_ALWAYS (ndat <= allocdat);
140:
141: if (ndat == allocdat)
142: {
143: dat = (struct dat_t *) _mp_allocate_or_reallocate
144: (dat, allocdat * sizeof(dat[0]),
145: (allocdat+ALLOCDAT_STEP) * sizeof(dat[0]));
146: allocdat += ALLOCDAT_STEP;
147: }
148:
149: dat[ndat].size = size;
150: dat[ndat].d = d;
151: ndat++;
152: }
153:
154:
155: /* Return the threshold size based on the data accumulated. */
156: mp_size_t
157: analyze_dat (int i, int final)
158: {
159: double x, min_x;
160: int j, min_j;
161:
162: /* If the threshold is set at dat[0].size, any positive values are bad. */
163: x = 0.0;
164: for (j = 0; j < ndat; j++)
165: if (dat[j].d > 0.0)
166: x += dat[j].d;
167:
168: if (option_trace >= 2 && final)
169: {
170: printf ("\n");
171: printf ("x is the sum of the badness from setting thresh at given size\n");
172: printf (" (minimum x is sought)\n");
173: printf ("i=%d size=%ld first x=%.4f\n", i, dat[j].size, x);
174: }
175:
176: min_x = x;
177: min_j = 0;
178:
179:
180: /* When stepping to the next dat[j].size, positive values are no longer
181: bad (so subtracted), negative values become bad (so add the absolute
182: value, meaning subtract). */
183: for (j = 0; j < ndat; x -= dat[j].d, j++)
184: {
185: if (option_trace >= 2 && final)
186: printf ("i=%d size=%ld x=%.4f\n", i, dat[j].size, x);
187:
188: if (x < min_x)
189: {
190: min_x = x;
191: min_j = j;
192: }
193: }
194:
195: return min_j;
196: }
197:
198:
199: double
200: tuneup_measure (speed_function_t fun, struct speed_params *s)
201: {
202: static mp_ptr xp, yp;
203: double t;
204: TMP_DECL (marker);
205:
206: TMP_MARK (marker);
207: s->xp = SPEED_TMP_ALLOC_LIMBS (s->size, 0);
208: s->yp = SPEED_TMP_ALLOC_LIMBS (s->size, 0);
209:
210: mpn_random (s->xp, s->size);
211: mpn_random (s->yp, s->size);
212:
213: t = speed_measure (fun, s);
214:
215: TMP_FREE (marker);
216: return t;
217: }
218:
219:
220: void
221: print_define (const char *name, mp_size_t value)
222: {
223: printf ("#ifndef %s\n", name);
224: printf ("#define %-23s ", name);
225: if (value == MP_SIZE_T_MAX)
226: printf ("MP_SIZE_T_MAX\n");
227: else
228: printf ("%5ld\n", value);
229: printf ("#endif\n");
230: }
231:
232:
233: /* table[i+1] needs to be set to a sensible value when testing method i+1
234: because mpn_mul_n uses TOOM3_MUL_THRESHOLD to size the temporary
235: workspace for mpn_kara_mul_n. */
236:
237: void
238: one (speed_function_t function, mp_size_t table[], size_t max_table,
239: struct param_t *param)
240: {
241: static struct param_t dummy;
242: int i;
243:
244: if (param == NULL) param = &dummy;
245:
246: #define DEFAULT(x,n) if (param->x == 0) param->x = (n);
247:
248: DEFAULT (stop_since_change, 80);
249: DEFAULT (min_size, 10);
250: for (i = 0; i < numberof (param->max_size); i++)
251: DEFAULT (max_size[i], MAX_SIZE);
252:
253: s.size = param->min_size;
254:
255: for (i = 0; i < max_table && s.size < MAX_SIZE; i++)
256: {
257: int since_positive, since_thresh_change;
258: int thresh_idx, new_thresh_idx;
259:
260: ndat = 0;
261: since_positive = 0;
262: since_thresh_change = 0;
263: thresh_idx = 0;
264:
265: if (option_trace >= 2)
266: {
267: printf (" algorithm-A algorithm-B ratio possible\n");
268: printf (" (seconds) (seconds) diff thresh\n");
269: }
270:
271: for ( ; s.size < MAX_SIZE;
272: s.size += MAX ((mp_size_t) floor (s.size * STEP_FACTOR), 1))
273: {
274: double ti, tiplus1, d;
275:
276: /* If there's a size limit and it's reached then it should still
277: be sensible to analyze the data since we want the threshold put
278: either at or near the limit. */
279: if (s.size >= param->max_size[i])
280: {
281: if (option_trace)
282: printf ("Reached maximum size (%ld) without otherwise stopping\n",
283: param->max_size[i]);
284: break;
285: }
286:
287: /*
288: FIXME: check minimum size requirements are met, possibly by just
289: checking for the -1 returns from the speed functions.
290: if (s.size < MPN_TOOM_TABLE_TO_MINSIZE (i))
291: continue;
292: */
293:
294: /* using method i at this size */
295: table[i] = s.size+1;
296: table[i+1] = MAX_SIZE;
297: ti = tuneup_measure (function, &s);
298: if (ti == -1.0)
299: abort ();
300:
301: /* using method i+1 at this size */
302: table[i] = s.size;
303: table[i+1] = s.size+1;
304: tiplus1 = tuneup_measure (function, &s);
305: if (tiplus1 == -1.0)
306: abort ();
307:
308: /* Calculate the fraction by which the one or the other routine is
309: slower. */
310: if (tiplus1 >= ti)
311: d = (tiplus1 - ti) / tiplus1; /* negative */
312: else
313: d = (tiplus1 - ti) / ti; /* positive */
314:
315: add_dat (s.size, d);
316:
317: new_thresh_idx = analyze_dat (i, 0);
318:
319:
320: if (option_trace >= 2)
321: printf ("i=%d size=%ld %.9f %.9f % .4f %c %d\n",
322: i, s.size, ti, tiplus1, d,
323: ti > tiplus1 ? '#' : ' ',
324: dat[new_thresh_idx].size);
325:
326: /* Stop if the last time method i was faster was more than a
327: certain number of measurements ago. */
328: #define STOP_SINCE_POSITIVE 200
329: if (d >= 0)
330: since_positive = 0;
331: else
332: if (++since_positive > STOP_SINCE_POSITIVE)
333: {
334: if (option_trace >= 1)
335: printf ("i=%d stopped due to since_positive (%d)\n",
336: i, STOP_SINCE_POSITIVE);
337: break;
338: }
339:
340: /* Stop if method i has become slower by a certain factor. */
341: #define STOP_FACTOR 1.2
342: if (ti >= tiplus1 * STOP_FACTOR)
343: {
344: if (option_trace >= 1)
345: printf ("i=%d stopped due to ti >= tiplus1 * factor (%.1f)\n",
346: i, STOP_FACTOR);
347: break;
348: }
349:
350: /* Stop if the threshold implied hasn't changed in a certain
351: number of measurements. (It's this condition that ususally
352: stops the loop.) */
353: if (thresh_idx != new_thresh_idx)
354: since_thresh_change = 0, thresh_idx = new_thresh_idx;
355: else
356: if (++since_thresh_change > param->stop_since_change)
357: {
358: if (option_trace >= 1)
359: printf ("i=%d stopped due to since_thresh_change (%d)\n",
360: i, param->stop_since_change);
361: break;
362: }
363:
364: /* Stop if the threshold implied is more than a certain number of
365: measurements ago. */
366: #define STOP_SINCE_AFTER 500
367: if (ndat - thresh_idx > STOP_SINCE_AFTER)
368: {
369: if (option_trace >= 1)
370: printf ("i=%d stopped due to ndat - thresh_idx > amount (%d)\n",
371: i, STOP_SINCE_AFTER);
372: break;
373: }
374: }
375:
376: /* Stop when the size limit is reached before the end of the
377: crossover, without a specified param->max_size[i]. */
378: if (s.size >= MAX_SIZE)
379: {
380: fprintf (stderr, "%s\n", param->name[i]);
381: fprintf (stderr, "i=%d sizes %ld to %ld total %d measurements\n",
382: i, dat[0].size, dat[ndat-1].size, ndat);
383: fprintf (stderr, " max size reached before end of crossover\n");
384: break;
385: }
386:
387: if (option_trace >= 1)
388: printf ("i=%d sizes %ld to %ld total %d measurements\n",
389: i, dat[0].size, dat[ndat-1].size, ndat);
390:
391: if (ndat == 0)
392: break;
393:
394: table[i] = dat[analyze_dat (i, 1)].size;
395:
396: print_define (param->name[i], table[i]);
397:
398: /* Look for the next threshold starting from the current one, but back
399: a bit. */
400: s.size = table[i]+1;
401: }
402: }
403:
404:
405: /* Special probing for the fft thresholds. The size restrictions on the
406: FFTs mean the graph of time vs size has a step effect. See this for
407: example using
408:
409: ./speed -s 4096-16384 -t 128 -P foo mpn_mul_fft.8 mpn_mul_fft.9
410: gnuplot foo.gnuplot
411:
412: The current approach is to compare routines at the midpoint of relevant
413: steps. Arguably a more sophisticated system of threshold data is wanted
414: if this step effect remains. */
415:
416: struct fft_param_t {
417: const char *table_name;
418: const char *threshold_name;
419: const char *modf_threshold_name;
420: mp_size_t *p_threshold;
421: mp_size_t *p_modf_threshold;
422: mp_size_t first_size;
423: mp_size_t max_size;
424: speed_function_t function;
425: speed_function_t mul_function;
426: mp_size_t sqr;
427: };
428:
429: /* mpn_mul_fft requires pl a multiple of 2^k limbs, but with
430: N=pl*BIT_PER_MP_LIMB it internally also pads out so N/2^k is a multiple
431: of 2^(k-1) bits. */
432:
433: mp_size_t
434: fft_step_size (int k)
435: {
436: if (2*k-1 > BITS_PER_INT)
437: {
438: printf ("Can't handle k=%d\n", k);
439: abort ();
440: }
441: return (1<<k) * (MAX (1<<(k-1), BITS_PER_MP_LIMB)) / BITS_PER_MP_LIMB;
442: }
443:
444: mp_size_t
445: fft_next_size (mp_size_t pl, int k)
446: {
447: mp_size_t m = fft_step_size (k);
448:
449: /* printf ("[k=%d %ld] %ld ->", k, m, pl); */
450:
451: if (pl == 0 || (pl & (m-1)) != 0)
452: pl = (pl | (m-1)) + 1;
453:
454: /* printf (" %ld\n", pl); */
455: return pl;
456: }
457:
458: void
459: fft (struct fft_param_t *p)
460: {
461: mp_size_t size;
462: int i, k;
463:
464: for (i = 0; i < numberof (mpn_fft_table[p->sqr]); i++)
465: mpn_fft_table[p->sqr][i] = MP_SIZE_T_MAX;
466:
467: *p->p_threshold = MP_SIZE_T_MAX;
468: *p->p_modf_threshold = MP_SIZE_T_MAX;
469:
470: option_trace = MAX (option_trace, option_fft_trace);
471:
472: printf ("#ifndef %s\n", p->table_name);
473: printf ("#define %s {", p->table_name);
474: if (option_trace >= 2)
475: printf ("\n");
476:
477: k = FFT_FIRST_K;
478: size = p->first_size;
479: for (;;)
480: {
481: double tk, tk1;
482:
483: size = fft_next_size (size+1, k+1);
484:
485: if (size >= p->max_size)
486: break;
487: if (k >= FFT_FIRST_K + numberof (mpn_fft_table[p->sqr]))
488: break;
489:
490: usleep(10000);
491:
492: /* compare k to k+1 in the middle of the current k+1 step */
493: s.size = size + fft_step_size (k+1) / 2;
494: s.r = k;
495: tk = tuneup_measure (p->function, &s);
496: if (tk == -1.0)
497: abort ();
498:
499: usleep(10000);
500:
501: s.r = k+1;
502: tk1 = tuneup_measure (p->function, &s);
503: if (tk1 == -1.0)
504: abort ();
505:
506: if (option_trace >= 2)
507: printf ("at %ld size=%ld k=%d %.9lf k=%d %.9lf\n",
508: size, s.size, k, tk, k+1, tk1);
509:
510: /* declare the k+1 threshold as soon as it's faster at its midpoint */
511: if (tk1 < tk)
512: {
513: mpn_fft_table[p->sqr][k-FFT_FIRST_K] = s.size;
514: printf (" %ld,", s.size);
515: if (option_trace >= 2) printf ("\n");
516: k++;
517: }
518: }
519:
520: mpn_fft_table[p->sqr][k-FFT_FIRST_K] = 0;
521: printf (" 0 }\n");
522: printf ("#endif\n");
523:
524:
525: size = p->first_size;
526:
527: /* Declare an FFT faster than a plain toom3 etc multiplication found as
528: soon as one faster measurement obtained. A multiplication in the
529: middle of the FFT step is tested. */
530: for (;;)
531: {
532: int modf = (*p->p_modf_threshold == MP_SIZE_T_MAX);
533: double tk, tm;
534:
535: /* k=7 should be the first FFT which can beat toom3 on a full
536: multiply, so jump to that threshold and save some probing after the
537: modf threshold is found. */
538: if (!modf && size < mpn_fft_table[p->sqr][2])
539: {
540: size = mpn_fft_table[p->sqr][2];
541: if (option_trace >= 2)
542: printf ("jump to size=%ld\n", size);
543: }
544:
545: size = fft_next_size (size+1, mpn_fft_best_k (size, p->sqr));
546: k = mpn_fft_best_k (size, p->sqr);
547:
548: if (size >= p->max_size)
549: break;
550:
551: usleep(10000);
552:
553: s.size = size + fft_step_size (k) / 2;
554: s.r = k;
555: tk = tuneup_measure (p->function, &s);
556: if (tk == -1.0)
557: abort ();
558:
559: usleep(10000);
560:
561: if (!modf) s.size /= 2;
562: tm = tuneup_measure (p->mul_function, &s);
563: if (tm == -1.0)
564: abort ();
565:
566: if (option_trace >= 2)
567: printf ("at %ld size=%ld k=%d %.9lf size=%ld %s mul %.9lf\n",
568: size,
569: size + fft_step_size (k) / 2, k, tk,
570: s.size, modf ? "modf" : "full", tm);
571:
572: if (tk < tm)
573: {
574: if (modf)
575: {
576: *p->p_modf_threshold = s.size;
577: print_define (p->modf_threshold_name, *p->p_modf_threshold);
578: }
579: else
580: {
581: *p->p_threshold = s.size;
582: print_define (p->threshold_name, *p->p_threshold);
583: break;
584: }
585: }
586: }
587:
588: }
589:
590:
591: void
592: all (void)
593: {
594: TMP_DECL (marker);
595:
596: TMP_MARK (marker);
597: s.xp_block = SPEED_TMP_ALLOC_LIMBS (SPEED_BLOCK_SIZE, 0);
598: s.yp_block = SPEED_TMP_ALLOC_LIMBS (SPEED_BLOCK_SIZE, 0);
599:
600: speed_time_init ();
601: fprintf (stderr, "speed_precision %d, speed_unittime %.2e\n",
602: speed_precision, speed_unittime);
603: fprintf (stderr, "MAX_SIZE %ld, fft_max_size %ld, STEP_FACTOR %.3f\n",
604: MAX_SIZE, option_fft_max_size, STEP_FACTOR);
605: fprintf (stderr, "\n");
606:
607: {
608: struct tm *tp;
609: time_t t;
610: time (&t);
611: tp = localtime (&t);
612: printf ("/* Generated by tuneup.c, %d-%02d-%02d. */\n\n",
613: tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday);
614: }
615:
616: {
617: static struct param_t param;
618: param.name[0] = "KARATSUBA_MUL_THRESHOLD";
619: param.name[1] = "TOOM3_MUL_THRESHOLD";
620: param.max_size[1] = TOOM3_MUL_THRESHOLD_LIMIT;
621: one (speed_mpn_mul_n, mul_threshold, numberof(mul_threshold)-1, ¶m);
622: }
623: printf("\n");
624:
625: {
626: static struct param_t param;
627: param.name[0] = "KARATSUBA_SQR_THRESHOLD";
628: param.name[1] = "TOOM3_SQR_THRESHOLD";
629: param.max_size[0] = KARATSUBA_SQR_MAX;
630: one (speed_mpn_sqr_n, sqr_threshold, numberof(sqr_threshold)-1, ¶m);
631: }
632: printf("\n");
633:
634: {
635: static struct param_t param;
636: param.name[0] = "BZ_THRESHOLD";
637: one (speed_mpn_bz_tdiv_qr, bz_threshold, 1, ¶m);
638: }
639: printf("\n");
640:
641: {
642: static struct param_t param;
643: param.name[0] = "FIB_THRESHOLD";
644: one (speed_mpz_fib_ui, fib_threshold, 1, ¶m);
645: }
646: printf("\n");
647:
648: /* mpz_powm becomes slow before long, so stop soon after the determined
649: threshold stops changing. */
650: {
651: static struct param_t param;
652: param.name[0] = "POWM_THRESHOLD";
653: param.stop_since_change = 15;
654: one (speed_mpz_powm, powm_threshold, 1, ¶m);
655: }
656: printf("\n");
657:
658: {
659: static struct param_t param;
660: param.name[0] = "GCD_ACCEL_THRESHOLD";
661: param.min_size = 1;
662: one (speed_mpn_gcd, gcd_accel_threshold, 1, ¶m);
663: }
664: {
665: static struct param_t param;
666: param.name[0] = "GCDEXT_THRESHOLD";
667: param.min_size = 1;
668: param.max_size[0] = 200;
669: one (speed_mpn_gcdext, gcdext_threshold, 1, ¶m);
670: }
671: printf("\n");
672:
673: if (option_fft_max_size != 0)
674: {
675: {
676: static struct fft_param_t param;
677: param.table_name = "FFT_MUL_TABLE";
678: param.threshold_name = "FFT_MUL_THRESHOLD";
679: param.p_threshold = &FFT_MUL_THRESHOLD;
680: param.modf_threshold_name = "FFT_MODF_MUL_THRESHOLD";
681: param.p_modf_threshold = &FFT_MODF_MUL_THRESHOLD;
682: param.first_size = TOOM3_MUL_THRESHOLD / 2;
683: param.max_size = option_fft_max_size;
684: param.function = speed_mpn_mul_fft;
685: param.mul_function = speed_mpn_mul_n;
686: param.sqr = 0;
687: fft (¶m);
688: }
689: printf("\n");
690: {
691: static struct fft_param_t param;
692: param.table_name = "FFT_SQR_TABLE";
693: param.threshold_name = "FFT_SQR_THRESHOLD";
694: param.p_threshold = &FFT_SQR_THRESHOLD;
695: param.modf_threshold_name = "FFT_MODF_SQR_THRESHOLD";
696: param.p_modf_threshold = &FFT_MODF_SQR_THRESHOLD;
697: param.first_size = TOOM3_SQR_THRESHOLD / 2;
698: param.max_size = option_fft_max_size;
699: param.function = speed_mpn_mul_fft_sqr;
700: param.mul_function = speed_mpn_sqr_n;
701: param.sqr = 0;
702: fft (¶m);
703: }
704: printf ("\n");
705: }
706:
707: TMP_FREE (marker);
708: }
709:
710:
711: int
712: main (int argc, char *argv[])
713: {
714: int opt;
715:
716: /* Unbuffered so if output is redirected to a file it isn't lost if the
717: program is killed part way through. */
718: setbuf (stdout, NULL);
719: setbuf (stderr, NULL);
720:
721: while ((opt = getopt(argc, argv, "f:o:p:t")) != EOF)
722: {
723: switch (opt) {
724: case 'f':
725: if (optarg[0] == 't')
726: option_fft_trace = 2;
727: else
728: option_fft_max_size = atol (optarg);
729: break;
730: case 'o':
731: speed_option_set (optarg);
732: break;
733: case 'p':
734: speed_precision = atoi (optarg);
735: break;
736: case 't':
737: option_trace++;
738: break;
739: case '?':
740: exit(1);
741: }
742: }
743:
744: all ();
745: return 0;
746: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>