speed.c
上传用户:qaz666999
上传日期:2022-08-06
资源大小:2570k
文件大小:39k
源码类别:

数学计算

开发平台:

Unix_Linux

  1. /* Speed measuring program.
  2. Copyright 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2008, 2009, 2010 Free
  3. Software Foundation, Inc.
  4. This file is part of the GNU MP Library.
  5. The GNU MP Library is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU Lesser General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or (at your
  8. option) any later version.
  9. The GNU MP Library is distributed in the hope that it will be useful, but
  10. WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  12. License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
  15. /* Usage message is in the code below, run with no arguments to print it.
  16.    See README for interesting applications.
  17.    To add a new routine foo(), create a speed_foo() function in the style of
  18.    the existing ones and add an entry in the routine[] array.  Put FLAG_R if
  19.    speed_foo() wants an "r" parameter.
  20.    The routines don't have help messages or descriptions, but most have
  21.    suggestive names.  See the source code for full details.
  22. */
  23. #include "config.h"
  24. #include <limits.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #if HAVE_UNISTD_H
  29. #include <unistd.h>  /* for getpid, R_OK */
  30. #endif
  31. #if TIME_WITH_SYS_TIME
  32. # include <sys/time.h>  /* for struct timeval */
  33. # include <time.h>
  34. #else
  35. # if HAVE_SYS_TIME_H
  36. #  include <sys/time.h>
  37. # else
  38. #  include <time.h>
  39. # endif
  40. #endif
  41. #if HAVE_SYS_RESOURCE_H
  42. #include <sys/resource.h>  /* for getrusage() */
  43. #endif
  44. #include "gmp.h"
  45. #include "gmp-impl.h"
  46. #include "longlong.h"  /* for the benefit of speed-many.c */
  47. #include "tests.h"
  48. #include "speed.h"
  49. #if !HAVE_DECL_OPTARG
  50. extern char *optarg;
  51. extern int optind, opterr;
  52. #endif
  53. #if !HAVE_STRTOUL
  54. #define strtoul(p,e,b)  (unsigned long) strtol(p,e,b)
  55. #endif
  56. #ifdef SPEED_EXTRA_PROTOS
  57. SPEED_EXTRA_PROTOS
  58. #endif
  59. #ifdef SPEED_EXTRA_PROTOS2
  60. SPEED_EXTRA_PROTOS2
  61. #endif
  62. #define MPN_FILL(ptr, size, n)          
  63.   do {                                  
  64.     mp_size_t __i;                      
  65.     ASSERT ((size) >= 0);               
  66.     for (__i = 0; __i < (size); __i++)  
  67.       (ptr)[__i] = (n);                 
  68.   } while (0)
  69. #if GMP_LIMB_BITS == 32
  70. #define GMP_NUMB_0xAA  (CNST_LIMB(0xAAAAAAAA) & GMP_NUMB_MASK)
  71. #endif
  72. #if GMP_LIMB_BITS == 64
  73. #define GMP_NUMB_0xAA  (CNST_LIMB(0xAAAAAAAAAAAAAAAA) & GMP_NUMB_MASK)
  74. #endif
  75. #define CMP_ABSOLUTE     1
  76. #define CMP_RATIO        2
  77. #define CMP_DIFFERENCE   3
  78. #define CMP_DIFFPREV     4
  79. int  option_cmp = CMP_ABSOLUTE;
  80. #define UNIT_SECONDS        1
  81. #define UNIT_CYCLES         2
  82. #define UNIT_CYCLESPERLIMB  3
  83. int  option_unit = UNIT_SECONDS;
  84. #define DATA_RANDOM   1
  85. #define DATA_RANDOM2  2
  86. #define DATA_ZEROS    3
  87. #define DATA_AAS      4
  88. #define DATA_FFS      5
  89. #define DATA_2FD      6
  90. int  option_data = DATA_RANDOM;
  91. int        option_square = 0;
  92. double     option_factor = 0.0;
  93. mp_size_t  option_step = 1;
  94. int        option_gnuplot = 0;
  95. char      *option_gnuplot_basename;
  96. struct size_array_t {
  97.   mp_size_t start, end;
  98. } *size_array = NULL;
  99. mp_size_t  size_num = 0;
  100. mp_size_t  size_allocnum = 0;
  101. int        option_resource_usage = 0;
  102. long       option_seed = 123456789;
  103. struct speed_params  sp;
  104. #define COLUMN_WIDTH  13  /* for the free-form output */
  105. #define FLAG_R            (1<<0)  /* require ".r" */
  106. #define FLAG_R_OPTIONAL   (1<<1)  /* optional ".r" */
  107. #define FLAG_RSIZE        (1<<2)
  108. #define FLAG_NODATA       (1<<3)  /* don't alloc xp, yp */
  109. const struct routine_t {
  110.   /* constants */
  111.   const char        *name;
  112.   speed_function_t  fun;
  113.   int               flag;
  114. } routine[] = {
  115.   { "noop",              speed_noop                 },
  116.   { "noop_wxs",          speed_noop_wxs             },
  117.   { "noop_wxys",         speed_noop_wxys            },
  118.   { "mpn_add_n",         speed_mpn_add_n,     FLAG_R_OPTIONAL },
  119.   { "mpn_sub_n",         speed_mpn_sub_n,     FLAG_R_OPTIONAL },
  120. #if HAVE_NATIVE_mpn_add_n_sub_n
  121.   { "mpn_add_n_sub_n",      speed_mpn_add_n_sub_n,     FLAG_R_OPTIONAL },
  122. #endif
  123.   { "mpn_addmul_1",      speed_mpn_addmul_1,  FLAG_R },
  124.   { "mpn_submul_1",      speed_mpn_submul_1,  FLAG_R },
  125. #if HAVE_NATIVE_mpn_addmul_2
  126.   { "mpn_addmul_2",      speed_mpn_addmul_2,  FLAG_R_OPTIONAL },
  127. #endif
  128. #if HAVE_NATIVE_mpn_addmul_3
  129.   { "mpn_addmul_3",      speed_mpn_addmul_3,  FLAG_R_OPTIONAL },
  130. #endif
  131. #if HAVE_NATIVE_mpn_addmul_4
  132.   { "mpn_addmul_4",      speed_mpn_addmul_4,  FLAG_R_OPTIONAL },
  133. #endif
  134. #if HAVE_NATIVE_mpn_addmul_5
  135.   { "mpn_addmul_5",      speed_mpn_addmul_5,  FLAG_R_OPTIONAL },
  136. #endif
  137. #if HAVE_NATIVE_mpn_addmul_6
  138.   { "mpn_addmul_6",      speed_mpn_addmul_6,  FLAG_R_OPTIONAL },
  139. #endif
  140. #if HAVE_NATIVE_mpn_addmul_7
  141.   { "mpn_addmul_7",      speed_mpn_addmul_7,  FLAG_R_OPTIONAL },
  142. #endif
  143. #if HAVE_NATIVE_mpn_addmul_8
  144.   { "mpn_addmul_8",      speed_mpn_addmul_8,  FLAG_R_OPTIONAL },
  145. #endif
  146.   { "mpn_mul_1",         speed_mpn_mul_1,     FLAG_R },
  147.   { "mpn_mul_1_inplace", speed_mpn_mul_1_inplace, FLAG_R },
  148. #if HAVE_NATIVE_mpn_mul_2
  149.   { "mpn_mul_2",         speed_mpn_mul_2,     FLAG_R_OPTIONAL },
  150. #endif
  151. #if HAVE_NATIVE_mpn_mul_3
  152.   { "mpn_mul_3",         speed_mpn_mul_3,     FLAG_R_OPTIONAL },
  153. #endif
  154. #if HAVE_NATIVE_mpn_mul_4
  155.   { "mpn_mul_4",         speed_mpn_mul_4,     FLAG_R_OPTIONAL },
  156. #endif
  157.   { "mpn_divrem_1",      speed_mpn_divrem_1,  FLAG_R },
  158.   { "mpn_divrem_1f",     speed_mpn_divrem_1f, FLAG_R },
  159. #if HAVE_NATIVE_mpn_divrem_1c
  160.   { "mpn_divrem_1c",     speed_mpn_divrem_1c, FLAG_R },
  161.   { "mpn_divrem_1cf",    speed_mpn_divrem_1cf,FLAG_R },
  162. #endif
  163.   { "mpn_mod_1",         speed_mpn_mod_1,     FLAG_R_OPTIONAL },
  164. #if HAVE_NATIVE_mpn_mod_1c
  165.   { "mpn_mod_1c",        speed_mpn_mod_1c,    FLAG_R_OPTIONAL },
  166. #endif
  167.   { "mpn_preinv_divrem_1",  speed_mpn_preinv_divrem_1,  FLAG_R },
  168.   { "mpn_preinv_divrem_1f", speed_mpn_preinv_divrem_1f, FLAG_R },
  169.   { "mpn_preinv_mod_1",  speed_mpn_preinv_mod_1, FLAG_R },
  170.   { "mpn_mod_1_1",       speed_mpn_mod_1_1,       FLAG_R_OPTIONAL },
  171.   { "mpn_mod_1s_2",      speed_mpn_mod_1_2,       FLAG_R_OPTIONAL },
  172.   { "mpn_mod_1s_3",      speed_mpn_mod_1_3,       FLAG_R_OPTIONAL },
  173.   { "mpn_mod_1s_4",      speed_mpn_mod_1_4,       FLAG_R_OPTIONAL },
  174.   { "mpn_divrem_1_div",  speed_mpn_divrem_1_div,  FLAG_R },
  175.   { "mpn_divrem_1_inv",  speed_mpn_divrem_1_inv,  FLAG_R },
  176.   { "mpn_divrem_1f_div", speed_mpn_divrem_1f_div, FLAG_R },
  177.   { "mpn_divrem_1f_inv", speed_mpn_divrem_1f_inv, FLAG_R },
  178.   { "mpn_mod_1_div",     speed_mpn_mod_1_div,     FLAG_R },
  179.   { "mpn_mod_1_inv",     speed_mpn_mod_1_inv,     FLAG_R },
  180.   { "mpn_divrem_2",      speed_mpn_divrem_2,        },
  181.   { "mpn_divrem_2_div",  speed_mpn_divrem_2_div,    },
  182.   { "mpn_divrem_2_inv",  speed_mpn_divrem_2_inv,    },
  183.   { "mpn_divexact_1",    speed_mpn_divexact_1,    FLAG_R },
  184.   { "mpn_divexact_by3",  speed_mpn_divexact_by3          },
  185.   { "mpn_bdiv_q_1",      speed_mpn_bdiv_q_1,      FLAG_R_OPTIONAL },
  186.   { "mpn_pi1_bdiv_q_1",  speed_mpn_pi1_bdiv_q_1,  FLAG_R_OPTIONAL },
  187.   { "mpn_bdiv_dbm1c",    speed_mpn_bdiv_dbm1c,    FLAG_R_OPTIONAL },
  188. #if HAVE_NATIVE_mpn_modexact_1_odd
  189.   { "mpn_modexact_1_odd",  speed_mpn_modexact_1_odd,  FLAG_R },
  190. #endif
  191.   { "mpn_modexact_1c_odd", speed_mpn_modexact_1c_odd, FLAG_R },
  192. #if GMP_NUMB_BITS % 4 == 0
  193.   { "mpn_mod_34lsub1",   speed_mpn_mod_34lsub1 },
  194. #endif
  195.   { "mpn_lshift",        speed_mpn_lshift, FLAG_R   },
  196.   { "mpn_lshiftc",       speed_mpn_lshiftc, FLAG_R   },
  197.   { "mpn_rshift",        speed_mpn_rshift, FLAG_R   },
  198.   { "mpn_and_n",         speed_mpn_and_n,  FLAG_R_OPTIONAL },
  199.   { "mpn_andn_n",        speed_mpn_andn_n, FLAG_R_OPTIONAL },
  200.   { "mpn_nand_n",        speed_mpn_nand_n, FLAG_R_OPTIONAL },
  201.   { "mpn_ior_n",         speed_mpn_ior_n,  FLAG_R_OPTIONAL },
  202.   { "mpn_iorn_n",        speed_mpn_iorn_n, FLAG_R_OPTIONAL },
  203.   { "mpn_nior_n",        speed_mpn_nior_n, FLAG_R_OPTIONAL },
  204.   { "mpn_xor_n",         speed_mpn_xor_n,  FLAG_R_OPTIONAL },
  205.   { "mpn_xnor_n",        speed_mpn_xnor_n, FLAG_R_OPTIONAL },
  206.   { "mpn_com",           speed_mpn_com              },
  207.   { "mpn_popcount",      speed_mpn_popcount         },
  208.   { "mpn_hamdist",       speed_mpn_hamdist          },
  209.   { "mpn_matrix22_mul",  speed_mpn_matrix22_mul     },
  210.   { "mpn_hgcd",          speed_mpn_hgcd             },
  211.   { "mpn_hgcd_lehmer",   speed_mpn_hgcd_lehmer      },
  212.   { "mpn_gcd_1",         speed_mpn_gcd_1,  FLAG_R_OPTIONAL },
  213.   { "mpn_gcd_1N",        speed_mpn_gcd_1N, FLAG_R_OPTIONAL },
  214.   { "mpn_gcd",           speed_mpn_gcd                    },
  215. #if 0
  216.   { "mpn_gcd_binary",    speed_mpn_gcd_binary             },
  217.   { "mpn_gcd_accel",     speed_mpn_gcd_accel              },
  218.   { "find_a",            speed_find_a,        FLAG_NODATA },
  219. #endif
  220.   { "mpn_gcdext",            speed_mpn_gcdext            },
  221.   { "mpn_gcdext_single",     speed_mpn_gcdext_single     },
  222.   { "mpn_gcdext_double",     speed_mpn_gcdext_double     },
  223.   { "mpn_gcdext_one_single", speed_mpn_gcdext_one_single },
  224.   { "mpn_gcdext_one_double", speed_mpn_gcdext_one_double },
  225. #if 0
  226.   { "mpn_gcdext_lehmer",     speed_mpn_gcdext_lehmer     },
  227. #endif
  228.   { "mpz_jacobi",        speed_mpz_jacobi           },
  229.   { "mpn_jacobi_base",   speed_mpn_jacobi_base      },
  230.   { "mpn_jacobi_base_1", speed_mpn_jacobi_base_1    },
  231.   { "mpn_jacobi_base_2", speed_mpn_jacobi_base_2    },
  232.   { "mpn_jacobi_base_3", speed_mpn_jacobi_base_3    },
  233.   { "mpn_mul",           speed_mpn_mul,         FLAG_R_OPTIONAL },
  234.   { "mpn_mul_basecase",  speed_mpn_mul_basecase,FLAG_R_OPTIONAL },
  235.   { "mpn_sqr_basecase",  speed_mpn_sqr_basecase     },
  236. #if HAVE_NATIVE_mpn_sqr_diagonal
  237.   { "mpn_sqr_diagonal",  speed_mpn_sqr_diagonal     },
  238. #endif
  239.   { "mpn_mul_n",         speed_mpn_mul_n            },
  240.   { "mpn_sqr",           speed_mpn_sqr              },
  241.   { "mpn_toom2_sqr",     speed_mpn_toom2_sqr        },
  242.   { "mpn_toom3_sqr",     speed_mpn_toom3_sqr        },
  243.   { "mpn_toom4_sqr",     speed_mpn_toom4_sqr        },
  244.   { "mpn_toom6_sqr",     speed_mpn_toom6_sqr        },
  245.   { "mpn_toom8_sqr",     speed_mpn_toom8_sqr        },
  246.   { "mpn_toom22_mul",    speed_mpn_toom22_mul       },
  247.   { "mpn_toom33_mul",    speed_mpn_toom33_mul       },
  248.   { "mpn_toom44_mul",    speed_mpn_toom44_mul       },
  249.   { "mpn_toom6h_mul",    speed_mpn_toom6h_mul       },
  250.   { "mpn_toom8h_mul",    speed_mpn_toom8h_mul       },
  251.   { "mpn_toom32_mul",    speed_mpn_toom32_mul       },
  252.   { "mpn_toom42_mul",    speed_mpn_toom42_mul       },
  253.   { "mpn_toom43_mul",    speed_mpn_toom43_mul       },
  254.   { "mpn_toom63_mul",    speed_mpn_toom63_mul       },
  255.   { "mpn_nussbaumer_mul",    speed_mpn_nussbaumer_mul    },
  256.   { "mpn_nussbaumer_mul_sqr",speed_mpn_nussbaumer_mul_sqr},
  257. #if WANT_OLD_FFT_FULL
  258.   { "mpn_mul_fft_full",      speed_mpn_mul_fft_full      },
  259.   { "mpn_mul_fft_full_sqr",  speed_mpn_mul_fft_full_sqr  },
  260. #endif
  261.   { "mpn_mul_fft",       speed_mpn_mul_fft,     FLAG_R_OPTIONAL },
  262.   { "mpn_mul_fft_sqr",   speed_mpn_mul_fft_sqr, FLAG_R_OPTIONAL },
  263.   { "mpn_mullo_n",        speed_mpn_mullo_n         },
  264.   { "mpn_mullo_basecase", speed_mpn_mullo_basecase  },
  265.   { "mpn_bc_mulmod_bnm1",      speed_mpn_bc_mulmod_bnm1      },
  266.   { "mpn_mulmod_bnm1",         speed_mpn_mulmod_bnm1         },
  267.   { "mpn_mulmod_bnm1_rounded", speed_mpn_mulmod_bnm1_rounded },
  268.   { "mpn_sqrmod_bnm1",         speed_mpn_sqrmod_bnm1         },
  269.   { "mpn_invert",              speed_mpn_invert              },
  270.   { "mpn_invertappr",          speed_mpn_invertappr          },
  271.   { "mpn_ni_invertappr",       speed_mpn_ni_invertappr       },
  272.   { "mpn_binvert",             speed_mpn_binvert             },
  273.   { "mpn_sbpi1_div_qr",        speed_mpn_sbpi1_div_qr,    FLAG_R_OPTIONAL},
  274.   { "mpn_dcpi1_div_qr",        speed_mpn_dcpi1_div_qr,    FLAG_R_OPTIONAL},
  275.   { "mpn_mu_div_qr",           speed_mpn_mu_div_qr,       FLAG_R_OPTIONAL},
  276.   { "mpn_mupi_div_qr",         speed_mpn_mupi_div_qr,     FLAG_R_OPTIONAL},
  277.   { "mpn_sbpi1_divappr_q",     speed_mpn_sbpi1_divappr_q, FLAG_R_OPTIONAL},
  278.   { "mpn_dcpi1_divappr_q",     speed_mpn_dcpi1_divappr_q, FLAG_R_OPTIONAL},
  279.   { "mpn_sbpi1_bdiv_qr",       speed_mpn_sbpi1_bdiv_qr       },
  280.   { "mpn_dcpi1_bdiv_qr",       speed_mpn_dcpi1_bdiv_qr       },
  281.   { "mpn_sbpi1_bdiv_q",        speed_mpn_sbpi1_bdiv_q        },
  282.   { "mpn_dcpi1_bdiv_q",        speed_mpn_dcpi1_bdiv_q        },
  283.   { "mpn_get_str",          speed_mpn_get_str,     FLAG_R_OPTIONAL },
  284.   { "mpn_set_str",          speed_mpn_set_str,     FLAG_R_OPTIONAL },
  285.   { "mpn_set_str_basecase", speed_mpn_bc_set_str,  FLAG_R_OPTIONAL },
  286.   { "mpn_sqrtrem",       speed_mpn_sqrtrem          },
  287.   { "mpn_rootrem",       speed_mpn_rootrem, FLAG_R  },
  288.   { "mpn_fib2_ui",       speed_mpn_fib2_ui,    FLAG_NODATA },
  289.   { "mpz_fib_ui",        speed_mpz_fib_ui,     FLAG_NODATA },
  290.   { "mpz_fib2_ui",       speed_mpz_fib2_ui,    FLAG_NODATA },
  291.   { "mpz_lucnum_ui",     speed_mpz_lucnum_ui,  FLAG_NODATA },
  292.   { "mpz_lucnum2_ui",    speed_mpz_lucnum2_ui, FLAG_NODATA },
  293.   { "mpz_add",           speed_mpz_add              },
  294.   { "mpz_bin_uiui",      speed_mpz_bin_uiui, FLAG_NODATA | FLAG_R_OPTIONAL },
  295.   { "mpz_fac_ui",        speed_mpz_fac_ui,   FLAG_NODATA   },
  296.   { "mpz_powm",          speed_mpz_powm             },
  297.   { "mpz_powm_mod",      speed_mpz_powm_mod         },
  298.   { "mpz_powm_redc",     speed_mpz_powm_redc        },
  299.   { "mpz_powm_ui",       speed_mpz_powm_ui,  FLAG_R_OPTIONAL },
  300.   { "mpz_mod",           speed_mpz_mod              },
  301.   { "mpn_redc_1",        speed_mpn_redc_1           },
  302.   { "mpn_redc_2",        speed_mpn_redc_2           },
  303.   { "mpn_redc_n",        speed_mpn_redc_n           },
  304.   { "MPN_COPY",          speed_MPN_COPY             },
  305.   { "MPN_COPY_INCR",     speed_MPN_COPY_INCR        },
  306.   { "MPN_COPY_DECR",     speed_MPN_COPY_DECR        },
  307.   { "memcpy",            speed_memcpy               },
  308. #if HAVE_NATIVE_mpn_copyi
  309.   { "mpn_copyi",         speed_mpn_copyi            },
  310. #endif
  311. #if HAVE_NATIVE_mpn_copyd
  312.   { "mpn_copyd",         speed_mpn_copyd            },
  313. #endif
  314. #if HAVE_NATIVE_mpn_addlsh1_n
  315.   { "mpn_addlsh1_n",     speed_mpn_addlsh1_n        },
  316. #endif
  317. #if HAVE_NATIVE_mpn_sublsh1_n
  318.   { "mpn_sublsh1_n",     speed_mpn_sublsh1_n        },
  319. #endif
  320. #if HAVE_NATIVE_mpn_rsblsh1_n
  321.   { "mpn_rsblsh1_n",     speed_mpn_rsblsh1_n        },
  322. #endif
  323. #if HAVE_NATIVE_mpn_addlsh2_n
  324.   { "mpn_addlsh2_n",     speed_mpn_addlsh2_n        },
  325. #endif
  326. #if HAVE_NATIVE_mpn_sublsh2_n
  327.   { "mpn_sublsh2_n",     speed_mpn_sublsh2_n        },
  328. #endif
  329. #if HAVE_NATIVE_mpn_rsblsh2_n
  330.   { "mpn_rsblsh2_n",     speed_mpn_rsblsh2_n        },
  331. #endif
  332. #if HAVE_NATIVE_mpn_rsh1add_n
  333.   { "mpn_rsh1add_n",     speed_mpn_rsh1add_n        },
  334. #endif
  335. #if HAVE_NATIVE_mpn_rsh1sub_n
  336.   { "mpn_rsh1sub_n",     speed_mpn_rsh1sub_n        },
  337. #endif
  338.   { "MPN_ZERO",          speed_MPN_ZERO             },
  339.   { "binvert_limb",       speed_binvert_limb,       FLAG_NODATA },
  340.   { "binvert_limb_mul1",  speed_binvert_limb_mul1,  FLAG_NODATA },
  341.   { "binvert_limb_loop",  speed_binvert_limb_loop,  FLAG_NODATA },
  342.   { "binvert_limb_cond",  speed_binvert_limb_cond,  FLAG_NODATA },
  343.   { "binvert_limb_arith", speed_binvert_limb_arith, FLAG_NODATA },
  344.   { "malloc_free",                  speed_malloc_free                  },
  345.   { "malloc_realloc_free",          speed_malloc_realloc_free          },
  346.   { "gmp_allocate_free",            speed_gmp_allocate_free            },
  347.   { "gmp_allocate_reallocate_free", speed_gmp_allocate_reallocate_free },
  348.   { "mpz_init_clear",               speed_mpz_init_clear               },
  349.   { "mpq_init_clear",               speed_mpq_init_clear               },
  350.   { "mpf_init_clear",               speed_mpf_init_clear               },
  351.   { "mpz_init_realloc_clear",       speed_mpz_init_realloc_clear       },
  352.   { "umul_ppmm",         speed_umul_ppmm,     FLAG_R_OPTIONAL },
  353. #if HAVE_NATIVE_mpn_umul_ppmm
  354.   { "mpn_umul_ppmm",     speed_mpn_umul_ppmm, FLAG_R_OPTIONAL },
  355. #endif
  356. #if HAVE_NATIVE_mpn_umul_ppmm_r
  357.   { "mpn_umul_ppmm_r",   speed_mpn_umul_ppmm_r, FLAG_R_OPTIONAL },
  358. #endif
  359.   { "count_leading_zeros",  speed_count_leading_zeros,  FLAG_NODATA | FLAG_R_OPTIONAL },
  360.   { "count_trailing_zeros", speed_count_trailing_zeros, FLAG_NODATA | FLAG_R_OPTIONAL },
  361.   { "udiv_qrnnd",             speed_udiv_qrnnd,             FLAG_R_OPTIONAL },
  362.   { "udiv_qrnnd_preinv1",     speed_udiv_qrnnd_preinv1,     FLAG_R_OPTIONAL },
  363.   { "udiv_qrnnd_preinv2",     speed_udiv_qrnnd_preinv2,     FLAG_R_OPTIONAL },
  364.   { "udiv_qrnnd_c",           speed_udiv_qrnnd_c,           FLAG_R_OPTIONAL },
  365. #if HAVE_NATIVE_mpn_udiv_qrnnd
  366.   { "mpn_udiv_qrnnd",         speed_mpn_udiv_qrnnd,         FLAG_R_OPTIONAL },
  367. #endif
  368. #if HAVE_NATIVE_mpn_udiv_qrnnd_r
  369.   { "mpn_udiv_qrnnd_r",       speed_mpn_udiv_qrnnd_r,       FLAG_R_OPTIONAL },
  370. #endif
  371.   { "invert_limb",            speed_invert_limb,            FLAG_R_OPTIONAL },
  372.   { "operator_div",           speed_operator_div,           FLAG_R_OPTIONAL },
  373.   { "operator_mod",           speed_operator_mod,           FLAG_R_OPTIONAL },
  374.   { "gmp_randseed",    speed_gmp_randseed,    FLAG_R_OPTIONAL               },
  375.   { "gmp_randseed_ui", speed_gmp_randseed_ui, FLAG_R_OPTIONAL | FLAG_NODATA },
  376.   { "mpz_urandomb",    speed_mpz_urandomb,    FLAG_R_OPTIONAL | FLAG_NODATA },
  377. #ifdef SPEED_EXTRA_ROUTINES
  378.   SPEED_EXTRA_ROUTINES
  379. #endif
  380. #ifdef SPEED_EXTRA_ROUTINES2
  381.   SPEED_EXTRA_ROUTINES2
  382. #endif
  383. };
  384. struct choice_t {
  385.   const struct routine_t  *p;
  386.   mp_limb_t               r;
  387.   double                  scale;
  388.   double                  time;
  389.   int                     no_time;
  390.   double                  prev_time;
  391.   const char              *name;
  392. };
  393. struct choice_t  *choice;
  394. int  num_choices = 0;
  395. void
  396. data_fill (mp_ptr ptr, mp_size_t size)
  397. {
  398.   switch (option_data) {
  399.   case DATA_RANDOM:
  400.     mpn_random (ptr, size);
  401.     break;
  402.   case DATA_RANDOM2:
  403.     mpn_random2 (ptr, size);
  404.     break;
  405.   case DATA_ZEROS:
  406.     MPN_ZERO (ptr, size);
  407.     break;
  408.   case DATA_AAS:
  409.     MPN_FILL (ptr, size, GMP_NUMB_0xAA);
  410.     break;
  411.   case DATA_FFS:
  412.     MPN_FILL (ptr, size, GMP_NUMB_MAX);
  413.     break;
  414.   case DATA_2FD:
  415.     MPN_FILL (ptr, size, GMP_NUMB_MAX);
  416.     ptr[0] -= 2;
  417.     break;
  418.   default:
  419.     abort();
  420.     /*NOTREACHED*/
  421.   }
  422. }
  423. /* The code here handling the various combinations of output options isn't
  424.    too attractive, but it works and is fairly clean.  */
  425. #define SIZE_TO_DIVISOR(n)              
  426.   (option_square == 1 ? (n)*(n)         
  427.   : option_square == 2 ? (n)*((n)+1)/2  
  428.   : (n))
  429. void
  430. run_one (FILE *fp, struct speed_params *s, mp_size_t prev_size)
  431. {
  432.   const char  *first_open_fastest, *first_open_notfastest, *first_close;
  433.   int         i, fastest, want_data;
  434.   double      fastest_time;
  435.   TMP_DECL;
  436.   TMP_MARK;
  437.   /* allocate data, unless all routines are NODATA */
  438.   want_data = 0;
  439.   for (i = 0; i < num_choices; i++)
  440.     want_data |= ((choice[i].p->flag & FLAG_NODATA) == 0);
  441.   if (want_data)
  442.     {
  443.       SPEED_TMP_ALLOC_LIMBS (sp.xp, s->size, s->align_xp);
  444.       SPEED_TMP_ALLOC_LIMBS (sp.yp, s->size, s->align_yp);
  445.       data_fill (s->xp, s->size);
  446.       data_fill (s->yp, s->size);
  447.     }
  448.   else
  449.     {
  450.       sp.xp = NULL;
  451.       sp.yp = NULL;
  452.     }
  453.   if (prev_size == -1 && option_cmp == CMP_DIFFPREV)
  454.     {
  455.       first_open_fastest = "(#";
  456.       first_open_notfastest = " (";
  457.       first_close = ")";
  458.     }
  459.   else
  460.     {
  461.       first_open_fastest = "#";
  462.       first_open_notfastest = " ";
  463.       first_close = "";
  464.     }
  465.   fastest = -1;
  466.   fastest_time = -1.0;
  467.   for (i = 0; i < num_choices; i++)
  468.     {
  469.       s->r = choice[i].r;
  470.       choice[i].time = speed_measure (choice[i].p->fun, s);
  471.       choice[i].no_time = (choice[i].time == -1.0);
  472.       if (! choice[i].no_time)
  473.         choice[i].time *= choice[i].scale;
  474.       /* Apply the effect of CMP_DIFFPREV, but the new choice[i].prev_time
  475.          is before any differences.  */
  476.       {
  477.         double     t;
  478.         t = choice[i].time;
  479.         if (t != -1.0 && option_cmp == CMP_DIFFPREV && prev_size != -1)
  480.           {
  481.             if (choice[i].prev_time == -1.0)
  482.               choice[i].no_time = 1;
  483.             else
  484.               choice[i].time = choice[i].time - choice[i].prev_time;
  485.           }
  486.         choice[i].prev_time = t;
  487.       }
  488.       if (choice[i].no_time)
  489.         continue;
  490.       /* Look for the fastest after CMP_DIFFPREV has been applied, but
  491.          before CMP_RATIO or CMP_DIFFERENCE.  There's only a fastest shown
  492.          if there's more than one routine.  */
  493.       if (num_choices > 1 && (fastest == -1 || choice[i].time < fastest_time))
  494.         {
  495.           fastest = i;
  496.           fastest_time = choice[i].time;
  497.         }
  498.       if (option_cmp == CMP_DIFFPREV)
  499.         {
  500.           /* Conversion for UNIT_CYCLESPERLIMB differs in CMP_DIFFPREV. */
  501.           if (option_unit == UNIT_CYCLES)
  502.             choice[i].time /= speed_cycletime;
  503.           else if (option_unit == UNIT_CYCLESPERLIMB)
  504.             {
  505.               if (prev_size == -1)
  506.                 choice[i].time /= speed_cycletime;
  507.               else
  508.                 choice[i].time /=  (speed_cycletime
  509.                                     * (SIZE_TO_DIVISOR(s->size)
  510.                                        - SIZE_TO_DIVISOR(prev_size)));
  511.             }
  512.         }
  513.       else
  514.         {
  515.           if (option_unit == UNIT_CYCLES)
  516.             choice[i].time /= speed_cycletime;
  517.           else if (option_unit == UNIT_CYCLESPERLIMB)
  518.             choice[i].time /= (speed_cycletime * SIZE_TO_DIVISOR(s->size));
  519.           if (option_cmp == CMP_RATIO && i > 0)
  520.             {
  521.               /* A ratio isn't affected by the units chosen. */
  522.               if (choice[0].no_time || choice[0].time == 0.0)
  523.                 choice[i].no_time = 1;
  524.               else
  525.                 choice[i].time /= choice[0].time;
  526.             }
  527.           else if (option_cmp == CMP_DIFFERENCE && i > 0)
  528.             {
  529.               if (choice[0].no_time)
  530.                 {
  531.                   choice[i].no_time = 1;
  532.                   continue;
  533.                 }
  534.               choice[i].time -= choice[0].time;
  535.             }
  536.         }
  537.     }
  538.   if (option_gnuplot)
  539.     {
  540.       /* In CMP_DIFFPREV, don't print anything for the first size, start
  541.          with the second where an actual difference is available.
  542.          In CMP_RATIO, print the first column as 1.0.
  543.          The 9 decimals printed is much more than the expected precision of
  544.          the measurements actually. */
  545.       if (! (option_cmp == CMP_DIFFPREV && prev_size == -1))
  546.         {
  547.           fprintf (fp, "%-6ld ", s->size);
  548.           for (i = 0; i < num_choices; i++)
  549.             fprintf (fp, "  %.9e",
  550.                      choice[i].no_time ? 0.0
  551.                      : (option_cmp == CMP_RATIO && i == 0) ? 1.0
  552.                      : choice[i].time);
  553.           fprintf (fp, "n");
  554.         }
  555.     }
  556.   else
  557.     {
  558.       fprintf (fp, "%-6ld ", s->size);
  559.       for (i = 0; i < num_choices; i++)
  560.         {
  561.           char  buf[128];
  562.           int   decimals;
  563.           if (choice[i].no_time)
  564.             {
  565.               fprintf (fp, " %*s", COLUMN_WIDTH, "n/a");
  566.             }
  567.           else
  568.             {if (option_unit == UNIT_CYCLESPERLIMB
  569.                  || (option_cmp == CMP_RATIO && i > 0))
  570.                 decimals = 4;
  571.               else if (option_unit == UNIT_CYCLES)
  572.                 decimals = 2;
  573.               else
  574.                 decimals = 9;
  575.               sprintf (buf, "%s%.*f%s",
  576.                        i == fastest ? first_open_fastest : first_open_notfastest,
  577.                        decimals, choice[i].time, first_close);
  578.               fprintf (fp, " %*s", COLUMN_WIDTH, buf);
  579.             }
  580.         }
  581.       fprintf (fp, "n");
  582.     }
  583.   TMP_FREE;
  584. }
  585. void
  586. run_all (FILE *fp)
  587. {
  588.   mp_size_t  prev_size;
  589.   int        i;
  590.   TMP_DECL;
  591.   TMP_MARK;
  592.   SPEED_TMP_ALLOC_LIMBS (sp.xp_block, SPEED_BLOCK_SIZE, sp.align_xp);
  593.   SPEED_TMP_ALLOC_LIMBS (sp.yp_block, SPEED_BLOCK_SIZE, sp.align_yp);
  594.   data_fill (sp.xp_block, SPEED_BLOCK_SIZE);
  595.   data_fill (sp.yp_block, SPEED_BLOCK_SIZE);
  596.   for (i = 0; i < size_num; i++)
  597.     {
  598.       sp.size = size_array[i].start;
  599.       prev_size = -1;
  600.       for (;;)
  601.         {
  602.           mp_size_t  step;
  603.           if (option_data == DATA_2FD && sp.size >= 2)
  604.             sp.xp[sp.size-1] = 2;
  605.           run_one (fp, &sp, prev_size);
  606.           prev_size = sp.size;
  607.           if (option_data == DATA_2FD && sp.size >= 2)
  608.             sp.xp[sp.size-1] = MP_LIMB_T_MAX;
  609.           if (option_factor != 0.0)
  610.             {
  611.               step = (mp_size_t) (sp.size * option_factor - sp.size);
  612.               if (step < 1)
  613.                 step = 1;
  614.             }
  615.           else
  616.             step = 1;
  617.           if (step < option_step)
  618.             step = option_step;
  619.           sp.size += step;
  620.           if (sp.size > size_array[i].end)
  621.             break;
  622.         }
  623.     }
  624.   TMP_FREE;
  625. }
  626. FILE *
  627. fopen_for_write (const char *filename)
  628. {
  629.   FILE  *fp;
  630.   if ((fp = fopen (filename, "w")) == NULL)
  631.     {
  632.       fprintf (stderr, "Cannot create %sn", filename);
  633.       exit(1);
  634.     }
  635.   return fp;
  636. }
  637. void
  638. fclose_written (FILE *fp, const char *filename)
  639. {
  640.   int  err;
  641.   err = ferror (fp);
  642.   err |= fclose (fp);
  643.   if (err)
  644.     {
  645.       fprintf (stderr, "Error writing %sn", filename);
  646.       exit(1);
  647.     }
  648. }
  649. void
  650. run_gnuplot (int argc, char *argv[])
  651. {
  652.   char  *plot_filename;
  653.   char  *data_filename;
  654.   FILE  *fp;
  655.   int   i;
  656.   plot_filename = (char *) (*__gmp_allocate_func)
  657.     (strlen (option_gnuplot_basename) + 20);
  658.   data_filename = (char *) (*__gmp_allocate_func)
  659.     (strlen (option_gnuplot_basename) + 20);
  660.   sprintf (plot_filename, "%s.gnuplot", option_gnuplot_basename);
  661.   sprintf (data_filename, "%s.data",    option_gnuplot_basename);
  662.   fp = fopen_for_write (plot_filename);
  663.   fprintf (fp, "# Generated with:n");
  664.   fprintf (fp, "#");
  665.   for (i = 0; i < argc; i++)
  666.     fprintf (fp, " %s", argv[i]);
  667.   fprintf (fp, "n");
  668.   fprintf (fp, "n");
  669.   fprintf (fp, "resetn");
  670.   /* Putting the key at the top left is usually good, and you can change it
  671.      interactively if it's not. */
  672.   fprintf (fp, "set key leftn");
  673.   /* designed to make it possible to see crossovers easily */
  674.   fprintf (fp, "set data style linesn");
  675.   fprintf (fp, "plot ");
  676.   for (i = 0; i < num_choices; i++)
  677.     {
  678.       fprintf (fp, " "%s" using 1:%d", data_filename, i+2);
  679.       fprintf (fp, " title "%s"", choice[i].name);
  680.       if (i != num_choices-1)
  681.         fprintf (fp, ", \");
  682.       fprintf (fp, "n");
  683.     }
  684.   fprintf (fp, "load "-"n");
  685.   fclose_written (fp, plot_filename);
  686.   fp = fopen_for_write (data_filename);
  687.   /* Unbuffered so you can see where the program was up to if it crashes or
  688.      you kill it. */
  689.   setbuf (fp, NULL);
  690.   run_all (fp);
  691.   fclose_written (fp, data_filename);
  692. }
  693. /* Return a limb with n many one bits (starting from the least significant) */
  694. #define LIMB_ONES(n) 
  695.   ((n) == GMP_LIMB_BITS ? MP_LIMB_T_MAX      
  696.     : (n) == 0 ? CNST_LIMB(0)                   
  697.     : (CNST_LIMB(1) << (n)) - 1)
  698. mp_limb_t
  699. r_string (const char *s)
  700. {
  701.   const char  *s_orig = s;
  702.   long        n;
  703.   if (strcmp (s, "aas") == 0)
  704.     return GMP_NUMB_0xAA;
  705.   {
  706.     mpz_t      z;
  707.     mp_limb_t  l;
  708.     int        set, siz;
  709.     mpz_init (z);
  710.     set = mpz_set_str (z, s, 0);
  711.     siz = SIZ(z);
  712.     l = (siz == 0 ? 0 : siz > 0 ? PTR(z)[0] : -PTR(z)[0]);
  713.     mpz_clear (z);
  714.     if (set == 0)
  715.       {
  716.         if (siz > 1 || siz < -1)
  717.           printf ("Warning, r parameter %s truncated to %d bitsn",
  718.                   s_orig, GMP_LIMB_BITS);
  719.         return l;
  720.       }
  721.   }
  722.   if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
  723.     n = strtoul (s+2, (char **) &s, 16);
  724.   else
  725.     n = strtol (s, (char **) &s, 10);
  726.   if (strcmp (s, "bits") == 0)
  727.     {
  728.       mp_limb_t  l;
  729.       if (n > GMP_LIMB_BITS)
  730.         {
  731.           fprintf (stderr, "%ld bit parameter invalid (max %d bits)n",
  732.                    n, GMP_LIMB_BITS);
  733.           exit (1);
  734.         }
  735.       mpn_random (&l, 1);
  736.       return (l | (CNST_LIMB(1) << (n-1))) & LIMB_ONES(n);
  737.     }
  738.   else  if (strcmp (s, "ones") == 0)
  739.     {
  740.       if (n > GMP_LIMB_BITS)
  741.         {
  742.           fprintf (stderr, "%ld bit parameter invalid (max %d bits)n",
  743.                    n, GMP_LIMB_BITS);
  744.           exit (1);
  745.         }
  746.       return LIMB_ONES (n);
  747.     }
  748.   else if (*s != '')
  749.     {
  750.       fprintf (stderr, "invalid r parameter: %sn", s_orig);
  751.       exit (1);
  752.     }
  753.   return n;
  754. }
  755. void
  756. routine_find (struct choice_t *c, const char *s_orig)
  757. {
  758.   const char  *s;
  759.   int     i;
  760.   size_t  nlen;
  761.   c->name = s_orig;
  762.   s = strchr (s_orig, '*');
  763.   if (s != NULL)
  764.     {
  765.       c->scale = atof(s_orig);
  766.       s++;
  767.     }
  768.   else
  769.     {
  770.       c->scale = 1.0;
  771.       s = s_orig;
  772.     }
  773.   for (i = 0; i < numberof (routine); i++)
  774.     {
  775.       nlen = strlen (routine[i].name);
  776.       if (memcmp (s, routine[i].name, nlen) != 0)
  777.         continue;
  778.       if (s[nlen] == '.')
  779.         {
  780.           /* match, with a .r parameter */
  781.           if (! (routine[i].flag & (FLAG_R|FLAG_R_OPTIONAL)))
  782.             {
  783.               fprintf (stderr,
  784.                        "Choice %s bad: doesn't take a ".<r>" parametern",
  785.                        s_orig);
  786.               exit (1);
  787.             }
  788.           c->p = &routine[i];
  789.           c->r = r_string (s + nlen + 1);
  790.           return;
  791.         }
  792.       if (s[nlen] == '')
  793.         {
  794.           /* match, with no parameter */
  795.           if (routine[i].flag & FLAG_R)
  796.             {
  797.               fprintf (stderr,
  798.                        "Choice %s bad: needs a ".<r>" parametern",
  799.                        s_orig);
  800.               exit (1);
  801.             }
  802.           c->p = &routine[i];
  803.           c->r = 0;
  804.           return;
  805.         }
  806.     }
  807.   fprintf (stderr, "Choice %s unrecognisedn", s_orig);
  808.   exit (1);
  809. }
  810. void
  811. usage (void)
  812. {
  813.   int  i;
  814.   speed_time_init ();
  815.   printf ("Usage: speed [-options] -s size <routine>...n");
  816.   printf ("Measure the speed of some routines.n");
  817.   printf ("Times are in seconds, accuracy is shown.n");
  818.   printf ("n");
  819.   printf ("   -p num     set precision as number of time units each routine must runn");
  820.   printf ("   -s size[-end][,size[-end]]...   sizes to measuren");
  821.   printf ("              single sizes or ranges, sep with comma or use multiple -sn");
  822.   printf ("   -t step    step through sizes by given amountn");
  823.   printf ("   -f factor  step through sizes by given factor (eg. 1.05)n");
  824.   printf ("   -r         show times as ratios of the first routinen");
  825.   printf ("   -d         show times as difference from the first routinen");
  826.   printf ("   -D         show times as difference from previous size shownn");
  827.   printf ("   -c         show times in CPU cyclesn");
  828.   printf ("   -C         show times in cycles per limbn");
  829.   printf ("   -u         print resource usage (memory) at endn");
  830.   printf ("   -P name    output plot files "name.gnuplot" and "name.data"n");
  831.   printf ("   -a <type>  use given data: random(default), random2, zeros, aas, ffs, 2fdn");
  832.   printf ("   -x, -y, -w, -W <align>  specify data alignments, sources and destsn");
  833.   printf ("   -o addrs   print addresses of data blocksn");
  834.   printf ("n");
  835.   printf ("If both -t and -f are used, it means step by the factor or the step, whichevern");
  836.   printf ("is greater.n");
  837.   printf ("If both -C and -D are used, it means cycles per however many limbs between an");
  838.   printf ("size and the previous size.n");
  839.   printf ("n");
  840.   printf ("After running with -P, plots can be viewed with Gnuplot or Quickplot.n");
  841.   printf (""gnuplot name.gnuplot" (use "set logscale xy; replot" at the prompt forn");
  842.   printf ("a log/log plot).n");
  843.   printf (""quickplot -s name.data" (has interactive zooming, and note -s is importantn");
  844.   printf ("when viewing more than one routine, it means same axis scales for all data).n");
  845.   printf ("n");
  846.   printf ("The available routines are as follows.n");
  847.   printf ("n");
  848.   for (i = 0; i < numberof (routine); i++)
  849.     {
  850.       if (routine[i].flag & FLAG_R)
  851.         printf ("t%s.rn", routine[i].name);
  852.       else if (routine[i].flag & FLAG_R_OPTIONAL)
  853.         printf ("t%s (optional .r)n", routine[i].name);
  854.       else
  855.         printf ("t%sn", routine[i].name);
  856.     }
  857.   printf ("n");
  858.   printf ("Routines with a ".r" need an extra parameter, for example mpn_lshift.6n");
  859.   printf ("r should be in decimal, or use 0xN for hexadecimal.n");
  860.   printf ("n");
  861.   printf ("Special forms for r are "<N>bits" for a random N bit number, "<N>ones" forn");
  862.   printf ("N one bits, or "aas" for 0xAA..AA.n");
  863.   printf ("n");
  864.   printf ("Times for sizes out of the range accepted by a routine are shown as 0.n");
  865.   printf ("The fastest routine at each size is marked with a # (free form output only).n");
  866.   printf ("n");
  867.   printf ("%s", speed_time_string);
  868.   printf ("n");
  869.   printf ("Gnuplot home page http://www.gnuplot.info/n");
  870.   printf ("Quickplot home page http://quickplot.sourceforge.net/n");
  871. }
  872. void
  873. check_align_option (const char *name, mp_size_t align)
  874. {
  875.   if (align < 0 || align > SPEED_TMP_ALLOC_ADJUST_MASK)
  876.     {
  877.       fprintf (stderr, "Alignment request out of range: %s %ldn",
  878.                name, (long) align);
  879.       fprintf (stderr, "  should be 0 to %d (limbs), inclusiven",
  880.                SPEED_TMP_ALLOC_ADJUST_MASK);
  881.       exit (1);
  882.     }
  883. }
  884. int
  885. main (int argc, char *argv[])
  886. {
  887.   int  i;
  888.   int  opt;
  889.   /* Unbuffered so output goes straight out when directed to a pipe or file
  890.      and isn't lost on killing the program half way.  */
  891.   setbuf (stdout, NULL);
  892.   for (;;)
  893.     {
  894.       opt = getopt(argc, argv, "a:CcDdEFf:o:p:P:rRs:t:ux:y:w:W:z");
  895.       if (opt == EOF)
  896.         break;
  897.       switch (opt) {
  898.       case 'a':
  899.         if (strcmp (optarg, "random") == 0)       option_data = DATA_RANDOM;
  900.         else if (strcmp (optarg, "random2") == 0) option_data = DATA_RANDOM2;
  901.         else if (strcmp (optarg, "zeros") == 0)   option_data = DATA_ZEROS;
  902.         else if (strcmp (optarg, "aas") == 0)     option_data = DATA_AAS;
  903.         else if (strcmp (optarg, "ffs") == 0)     option_data = DATA_FFS;
  904.         else if (strcmp (optarg, "2fd") == 0)     option_data = DATA_2FD;
  905.         else
  906.           {
  907.             fprintf (stderr, "unrecognised data option: %sn", optarg);
  908.             exit (1);
  909.           }
  910.         break;
  911.       case 'C':
  912.         if (option_unit  != UNIT_SECONDS) goto bad_unit;
  913.         option_unit = UNIT_CYCLESPERLIMB;
  914.         break;
  915.       case 'c':
  916.         if (option_unit != UNIT_SECONDS)
  917.           {
  918.           bad_unit:
  919.             fprintf (stderr, "cannot use more than one of -c, -Cn");
  920.             exit (1);
  921.           }
  922.         option_unit = UNIT_CYCLES;
  923.         break;
  924.       case 'D':
  925.         if (option_cmp != CMP_ABSOLUTE) goto bad_cmp;
  926.         option_cmp = CMP_DIFFPREV;
  927.         break;
  928.       case 'd':
  929.         if (option_cmp != CMP_ABSOLUTE)
  930.           {
  931.           bad_cmp:
  932.             fprintf (stderr, "cannot use more than one of -d, -D, -rn");
  933.             exit (1);
  934.           }
  935.         option_cmp = CMP_DIFFERENCE;
  936.         break;
  937.       case 'E':
  938.         option_square = 1;
  939.         break;
  940.       case 'F':
  941.         option_square = 2;
  942.         break;
  943.       case 'f':
  944.         option_factor = atof (optarg);
  945.         if (option_factor <= 1.0)
  946.           {
  947.             fprintf (stderr, "-f factor must be > 1.0n");
  948.             exit (1);
  949.           }
  950.         break;
  951.       case 'o':
  952.         speed_option_set (optarg);
  953.         break;
  954.       case 'P':
  955.         option_gnuplot = 1;
  956.         option_gnuplot_basename = optarg;
  957.         break;
  958.       case 'p':
  959.         speed_precision = atoi (optarg);
  960.         break;
  961.       case 'R':
  962.         option_seed = time (NULL);
  963.         break;
  964.       case 'r':
  965.         if (option_cmp != CMP_ABSOLUTE)
  966.           goto bad_cmp;
  967.         option_cmp = CMP_RATIO;
  968.         break;
  969.       case 's':
  970.         {
  971.           char  *s;
  972.           for (s = strtok (optarg, ","); s != NULL; s = strtok (NULL, ","))
  973.             {
  974.               if (size_num == size_allocnum)
  975.                 {
  976.                   size_array = (struct size_array_t *)
  977.                     __gmp_allocate_or_reallocate
  978.                     (size_array,
  979.                      size_allocnum * sizeof(size_array[0]),
  980.                      (size_allocnum+10) * sizeof(size_array[0]));
  981.                   size_allocnum += 10;
  982.                 }
  983.               if (sscanf (s, "%ld-%ld",
  984.                           &size_array[size_num].start,
  985.                           &size_array[size_num].end) != 2)
  986.                 {
  987.                   size_array[size_num].start = size_array[size_num].end
  988.                     = atol (s);
  989.                 }
  990.               if (size_array[size_num].start < 0
  991.                   || size_array[size_num].end < 0
  992.                   || size_array[size_num].start > size_array[size_num].end)
  993.                 {
  994.                   fprintf (stderr, "invalid size parameter: %sn", s);
  995.                   exit (1);
  996.                 }
  997.               size_num++;
  998.             }
  999.         }
  1000.         break;
  1001.       case 't':
  1002.         option_step = atol (optarg);
  1003.         if (option_step < 1)
  1004.           {
  1005.             fprintf (stderr, "-t step must be >= 1n");
  1006.             exit (1);
  1007.           }
  1008.         break;
  1009.       case 'u':
  1010.         option_resource_usage = 1;
  1011.         break;
  1012.       case 'z':
  1013.         sp.cache = 1;
  1014.         break;
  1015.       case 'x':
  1016.         sp.align_xp = atol (optarg);
  1017.         check_align_option ("-x", sp.align_xp);
  1018.         break;
  1019.       case 'y':
  1020.         sp.align_yp = atol (optarg);
  1021.         check_align_option ("-y", sp.align_yp);
  1022.         break;
  1023.       case 'w':
  1024.         sp.align_wp = atol (optarg);
  1025.         check_align_option ("-w", sp.align_wp);
  1026.         break;
  1027.       case 'W':
  1028.         sp.align_wp2 = atol (optarg);
  1029.         check_align_option ("-W", sp.align_wp2);
  1030.         break;
  1031.       case '?':
  1032.         exit(1);
  1033.       }
  1034.     }
  1035.   if (optind >= argc)
  1036.     {
  1037.       usage ();
  1038.       exit (1);
  1039.     }
  1040.   if (size_num == 0)
  1041.     {
  1042.       fprintf (stderr, "-s <size> must be specifiedn");
  1043.       exit (1);
  1044.     }
  1045.   gmp_randinit_default (__gmp_rands);
  1046.   __gmp_rands_initialized = 1;
  1047.   gmp_randseed_ui (__gmp_rands, option_seed);
  1048.   choice = (struct choice_t *) (*__gmp_allocate_func)
  1049.     ((argc - optind) * sizeof(choice[0]));
  1050.   for ( ; optind < argc; optind++)
  1051.     {
  1052.       struct choice_t  c;
  1053.       routine_find (&c, argv[optind]);
  1054.       choice[num_choices] = c;
  1055.       num_choices++;
  1056.     }
  1057.   if ((option_cmp == CMP_RATIO || option_cmp == CMP_DIFFERENCE) &&
  1058.       num_choices < 2)
  1059.     {
  1060.       fprintf (stderr, "WARNING, -d or -r does nothing when only one routine requestedn");
  1061.     }
  1062.   speed_time_init ();
  1063.   if (option_unit == UNIT_CYCLES || option_unit == UNIT_CYCLESPERLIMB)
  1064.     speed_cycletime_need_cycles ();
  1065.   else
  1066.     speed_cycletime_need_seconds ();
  1067.   if (option_gnuplot)
  1068.     {
  1069.       run_gnuplot (argc, argv);
  1070.     }
  1071.   else
  1072.     {
  1073.       if (option_unit == UNIT_SECONDS)
  1074.         printf ("overhead %.9f secs", speed_measure (speed_noop, NULL));
  1075.       else
  1076.         printf ("overhead %.2f cycles",
  1077.                 speed_measure (speed_noop, NULL) / speed_cycletime);
  1078.       printf (", precision %d units of %.2e secs",
  1079.               speed_precision, speed_unittime);
  1080.       if (speed_cycletime == 1.0 || speed_cycletime == 0.0)
  1081.         printf (", CPU freq unknownn");
  1082.       else
  1083.         printf (", CPU freq %.2f MHzn", 1e-6/speed_cycletime);
  1084.       printf ("       ");
  1085.       for (i = 0; i < num_choices; i++)
  1086.         printf (" %*s", COLUMN_WIDTH, choice[i].name);
  1087.       printf ("n");
  1088.       run_all (stdout);
  1089.     }
  1090.   if (option_resource_usage)
  1091.     {
  1092. #if HAVE_GETRUSAGE
  1093.       {
  1094.         /* This doesn't give data sizes on linux 2.0.x, only utime. */
  1095.         struct rusage  r;
  1096.         if (getrusage (RUSAGE_SELF, &r) != 0)
  1097.           perror ("getrusage");
  1098.         else
  1099.           printf ("getrusage(): utime %ld.%06ld data %ld stack %ld maxresident %ldn",
  1100.                   r.ru_utime.tv_sec, r.ru_utime.tv_usec,
  1101.                   r.ru_idrss, r.ru_isrss, r.ru_ixrss);
  1102.       }
  1103. #else
  1104.       printf ("getrusage() not availablen");
  1105. #endif
  1106.       /* Linux kernel. */
  1107.       {
  1108.         char  buf[128];
  1109.         sprintf (buf, "/proc/%d/status", getpid());
  1110.         if (access (buf, R_OK) == 0)
  1111.           {
  1112.             sprintf (buf, "cat /proc/%d/status", getpid());
  1113.             system (buf);
  1114.           }
  1115.       }
  1116.     }
  1117.   return 0;
  1118. }