timeconst.pl 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. #!/usr/bin/perl
  2. # -----------------------------------------------------------------------
  3. #
  4. # Copyright 2007-2008 rPath, Inc. - All Rights Reserved
  5. #
  6. # This file is part of the Linux kernel, and is made available under
  7. # the terms of the GNU General Public License version 2 or (at your
  8. # option) any later version; incorporated herein by reference.
  9. #
  10. # -----------------------------------------------------------------------
  11. #
  12. #
  13. # Usage: timeconst.pl HZ > timeconst.h
  14. #
  15. # Precomputed values for systems without Math::BigInt
  16. # Generated by:
  17. # timeconst.pl --can 24 32 48 64 100 122 128 200 250 256 300 512 1000 1024 1200
  18. %canned_values = (
  19. 24 => [
  20. '0xa6aaaaab','0x2aaaaaa',26,
  21. 125,3,
  22. '0xc49ba5e4','0x1fbe76c8b4',37,
  23. 3,125,
  24. '0xa2c2aaab','0xaaaa',16,
  25. 125000,3,
  26. '0xc9539b89','0x7fffbce4217d',47,
  27. 3,125000,
  28. ], 32 => [
  29. '0xfa000000','0x6000000',27,
  30. 125,4,
  31. '0x83126e98','0xfdf3b645a',36,
  32. 4,125,
  33. '0xf4240000','0x0',17,
  34. 31250,1,
  35. '0x8637bd06','0x3fff79c842fa',46,
  36. 1,31250,
  37. ], 48 => [
  38. '0xa6aaaaab','0x6aaaaaa',27,
  39. 125,6,
  40. '0xc49ba5e4','0xfdf3b645a',36,
  41. 6,125,
  42. '0xa2c2aaab','0x15555',17,
  43. 62500,3,
  44. '0xc9539b89','0x3fffbce4217d',46,
  45. 3,62500,
  46. ], 64 => [
  47. '0xfa000000','0xe000000',28,
  48. 125,8,
  49. '0x83126e98','0x7ef9db22d',35,
  50. 8,125,
  51. '0xf4240000','0x0',18,
  52. 15625,1,
  53. '0x8637bd06','0x1fff79c842fa',45,
  54. 1,15625,
  55. ], 100 => [
  56. '0xa0000000','0x0',28,
  57. 10,1,
  58. '0xcccccccd','0x733333333',35,
  59. 1,10,
  60. '0x9c400000','0x0',18,
  61. 10000,1,
  62. '0xd1b71759','0x1fff2e48e8a7',45,
  63. 1,10000,
  64. ], 122 => [
  65. '0x8325c53f','0xfbcda3a',28,
  66. 500,61,
  67. '0xf9db22d1','0x7fbe76c8b',35,
  68. 61,500,
  69. '0x8012e2a0','0x3ef36',18,
  70. 500000,61,
  71. '0xffda4053','0x1ffffbce4217',45,
  72. 61,500000,
  73. ], 128 => [
  74. '0xfa000000','0x1e000000',29,
  75. 125,16,
  76. '0x83126e98','0x3f7ced916',34,
  77. 16,125,
  78. '0xf4240000','0x40000',19,
  79. 15625,2,
  80. '0x8637bd06','0xfffbce4217d',44,
  81. 2,15625,
  82. ], 200 => [
  83. '0xa0000000','0x0',29,
  84. 5,1,
  85. '0xcccccccd','0x333333333',34,
  86. 1,5,
  87. '0x9c400000','0x0',19,
  88. 5000,1,
  89. '0xd1b71759','0xfff2e48e8a7',44,
  90. 1,5000,
  91. ], 250 => [
  92. '0x80000000','0x0',29,
  93. 4,1,
  94. '0x80000000','0x180000000',33,
  95. 1,4,
  96. '0xfa000000','0x0',20,
  97. 4000,1,
  98. '0x83126e98','0x7ff7ced9168',43,
  99. 1,4000,
  100. ], 256 => [
  101. '0xfa000000','0x3e000000',30,
  102. 125,32,
  103. '0x83126e98','0x1fbe76c8b',33,
  104. 32,125,
  105. '0xf4240000','0xc0000',20,
  106. 15625,4,
  107. '0x8637bd06','0x7ffde7210be',43,
  108. 4,15625,
  109. ], 300 => [
  110. '0xd5555556','0x2aaaaaaa',30,
  111. 10,3,
  112. '0x9999999a','0x1cccccccc',33,
  113. 3,10,
  114. '0xd0555556','0xaaaaa',20,
  115. 10000,3,
  116. '0x9d495183','0x7ffcb923a29',43,
  117. 3,10000,
  118. ], 512 => [
  119. '0xfa000000','0x7e000000',31,
  120. 125,64,
  121. '0x83126e98','0xfdf3b645',32,
  122. 64,125,
  123. '0xf4240000','0x1c0000',21,
  124. 15625,8,
  125. '0x8637bd06','0x3ffef39085f',42,
  126. 8,15625,
  127. ], 1000 => [
  128. '0x80000000','0x0',31,
  129. 1,1,
  130. '0x80000000','0x0',31,
  131. 1,1,
  132. '0xfa000000','0x0',22,
  133. 1000,1,
  134. '0x83126e98','0x1ff7ced9168',41,
  135. 1,1000,
  136. ], 1024 => [
  137. '0xfa000000','0xfe000000',32,
  138. 125,128,
  139. '0x83126e98','0x7ef9db22',31,
  140. 128,125,
  141. '0xf4240000','0x3c0000',22,
  142. 15625,16,
  143. '0x8637bd06','0x1fff79c842f',41,
  144. 16,15625,
  145. ], 1200 => [
  146. '0xd5555556','0xd5555555',32,
  147. 5,6,
  148. '0x9999999a','0x66666666',31,
  149. 6,5,
  150. '0xd0555556','0x2aaaaa',22,
  151. 2500,3,
  152. '0x9d495183','0x1ffcb923a29',41,
  153. 3,2500,
  154. ]
  155. );
  156. $has_bigint = eval 'use Math::BigInt qw(bgcd); 1;';
  157. sub bint($)
  158. {
  159. my($x) = @_;
  160. return Math::BigInt->new($x);
  161. }
  162. #
  163. # Constants for division by reciprocal multiplication.
  164. # (bits, numerator, denominator)
  165. #
  166. sub fmul($$$)
  167. {
  168. my ($b,$n,$d) = @_;
  169. $n = bint($n);
  170. $d = bint($d);
  171. return scalar (($n << $b)+$d-bint(1))/$d;
  172. }
  173. sub fadj($$$)
  174. {
  175. my($b,$n,$d) = @_;
  176. $n = bint($n);
  177. $d = bint($d);
  178. $d = $d/bgcd($n, $d);
  179. return scalar (($d-bint(1)) << $b)/$d;
  180. }
  181. sub fmuls($$$) {
  182. my($b,$n,$d) = @_;
  183. my($s,$m);
  184. my($thres) = bint(1) << ($b-1);
  185. $n = bint($n);
  186. $d = bint($d);
  187. for ($s = 0; 1; $s++) {
  188. $m = fmul($s,$n,$d);
  189. return $s if ($m >= $thres);
  190. }
  191. return 0;
  192. }
  193. # Generate a hex value if the result fits in 64 bits;
  194. # otherwise skip.
  195. sub bignum_hex($) {
  196. my($x) = @_;
  197. my $s = $x->as_hex();
  198. return (length($s) > 18) ? undef : $s;
  199. }
  200. # Provides mul, adj, and shr factors for a specific
  201. # (bit, time, hz) combination
  202. sub muladj($$$) {
  203. my($b, $t, $hz) = @_;
  204. my $s = fmuls($b, $t, $hz);
  205. my $m = fmul($s, $t, $hz);
  206. my $a = fadj($s, $t, $hz);
  207. return (bignum_hex($m), bignum_hex($a), $s);
  208. }
  209. # Provides numerator, denominator values
  210. sub numden($$) {
  211. my($n, $d) = @_;
  212. my $g = bgcd($n, $d);
  213. return ($n/$g, $d/$g);
  214. }
  215. # All values for a specific (time, hz) combo
  216. sub conversions($$) {
  217. my ($t, $hz) = @_;
  218. my @val = ();
  219. # HZ_TO_xx
  220. push(@val, muladj(32, $t, $hz));
  221. push(@val, numden($t, $hz));
  222. # xx_TO_HZ
  223. push(@val, muladj(32, $hz, $t));
  224. push(@val, numden($hz, $t));
  225. return @val;
  226. }
  227. sub compute_values($) {
  228. my($hz) = @_;
  229. my @val = ();
  230. my $s, $m, $a, $g;
  231. if (!$has_bigint) {
  232. die "$0: HZ == $hz not canned and ".
  233. "Math::BigInt not available\n";
  234. }
  235. # MSEC conversions
  236. push(@val, conversions(1000, $hz));
  237. # USEC conversions
  238. push(@val, conversions(1000000, $hz));
  239. return @val;
  240. }
  241. sub outputval($$)
  242. {
  243. my($name, $val) = @_;
  244. my $csuf;
  245. if (defined($val)) {
  246. if ($name !~ /SHR/) {
  247. $val = "U64_C($val)";
  248. }
  249. printf "#define %-23s %s\n", $name.$csuf, $val.$csuf;
  250. }
  251. }
  252. sub output($@)
  253. {
  254. my($hz, @val) = @_;
  255. my $pfx, $bit, $suf, $s, $m, $a;
  256. print "/* Automatically generated by kernel/timeconst.pl */\n";
  257. print "/* Conversion constants for HZ == $hz */\n";
  258. print "\n";
  259. print "#ifndef KERNEL_TIMECONST_H\n";
  260. print "#define KERNEL_TIMECONST_H\n";
  261. print "\n";
  262. print "#include <linux/param.h>\n";
  263. print "#include <linux/types.h>\n";
  264. print "\n";
  265. print "#if HZ != $hz\n";
  266. print "#error \"kernel/timeconst.h has the wrong HZ value!\"\n";
  267. print "#endif\n";
  268. print "\n";
  269. foreach $pfx ('HZ_TO_MSEC','MSEC_TO_HZ',
  270. 'HZ_TO_USEC','USEC_TO_HZ') {
  271. foreach $bit (32) {
  272. foreach $suf ('MUL', 'ADJ', 'SHR') {
  273. outputval("${pfx}_$suf$bit", shift(@val));
  274. }
  275. }
  276. foreach $suf ('NUM', 'DEN') {
  277. outputval("${pfx}_$suf", shift(@val));
  278. }
  279. }
  280. print "\n";
  281. print "#endif /* KERNEL_TIMECONST_H */\n";
  282. }
  283. # Pretty-print Perl values
  284. sub perlvals(@) {
  285. my $v;
  286. my @l = ();
  287. foreach $v (@_) {
  288. if (!defined($v)) {
  289. push(@l, 'undef');
  290. } elsif ($v =~ /^0x/) {
  291. push(@l, "\'".$v."\'");
  292. } else {
  293. push(@l, $v.'');
  294. }
  295. }
  296. return join(',', @l);
  297. }
  298. ($hz) = @ARGV;
  299. # Use this to generate the %canned_values structure
  300. if ($hz eq '--can') {
  301. shift(@ARGV);
  302. @hzlist = sort {$a <=> $b} (@ARGV);
  303. print "# Precomputed values for systems without Math::BigInt\n";
  304. print "# Generated by:\n";
  305. print "# timeconst.pl --can ", join(' ', @hzlist), "\n";
  306. print "\%canned_values = (\n";
  307. my $pf = "\t";
  308. foreach $hz (@hzlist) {
  309. my @values = compute_values($hz);
  310. print "$pf$hz => [\n";
  311. while (scalar(@values)) {
  312. my $bit;
  313. foreach $bit (32) {
  314. my $m = shift(@values);
  315. my $a = shift(@values);
  316. my $s = shift(@values);
  317. print "\t\t", perlvals($m,$a,$s), ",\n";
  318. }
  319. my $n = shift(@values);
  320. my $d = shift(@values);
  321. print "\t\t", perlvals($n,$d), ",\n";
  322. }
  323. print "\t]";
  324. $pf = ', ';
  325. }
  326. print "\n);\n";
  327. } else {
  328. $hz += 0; # Force to number
  329. if ($hz < 1) {
  330. die "Usage: $0 HZ\n";
  331. }
  332. @val = @{$canned_values{$hz}};
  333. if (!defined(@val)) {
  334. @val = compute_values($hz);
  335. }
  336. output($hz, @val);
  337. }
  338. exit 0;