Commit 70730bca1331fc50c3caacaea00439de1325bd6e

Authored by H. Peter Anvin
Committed by Michal Marek
1 parent 6543becf26

kernel: Replace timeconst.pl with a bc script

bc is the standard tool for multi-precision arithmetic.  We switched
to Perl because akpm reported a hard-to-reproduce build hang, which
was very odd because affected and unaffected machines were all running
the same version of GNU bc.

Unfortunately switching to Perl required a really ugly "canning"
mechanism to support Perl < 5.8 installations lacking the Math::BigInt
module.

It was recently pointed out to me that some very old versions of GNU
make had problems with pipes in subshells, which was indeed the
construct used in the Makefile rules in that version of the patch;
Perl didn't need it so switching to Perl fixed the problem for
unrelated reasons.  With the problem (hopefully) root-caused, we can
switch back to bc and do the arbitrary-precision arithmetic naturally.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Michal Marek <mmarek@suse.cz>

Showing 3 changed files with 120 additions and 382 deletions Side-by-side Diff

... ... @@ -127,11 +127,19 @@
127 127  
128 128 $(obj)/time.o: $(obj)/timeconst.h
129 129  
130   -quiet_cmd_timeconst = TIMEC $@
131   - cmd_timeconst = $(PERL) $< $(CONFIG_HZ) > $@
  130 +quiet_cmd_hzfile = HZFILE $@
  131 + cmd_hzfile = echo "hz=$(CONFIG_HZ)" > $@
  132 +
  133 +targets += hz.bc
  134 +$(obj)/hz.bc: $(objtree)/include/config/hz.h FORCE
  135 + $(call if_changed,hzfile)
  136 +
  137 +quiet_cmd_bc = BC $@
  138 + cmd_bc = bc -q $(filter-out FORCE,$^) > $@
  139 +
132 140 targets += timeconst.h
133   -$(obj)/timeconst.h: $(src)/timeconst.pl FORCE
134   - $(call if_changed,timeconst)
  141 +$(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE
  142 + $(call if_changed,bc)
135 143  
136 144 ifeq ($(CONFIG_MODULE_SIG),y)
137 145 #
  1 +scale=0
  2 +
  3 +define gcd(a,b) {
  4 + auto t;
  5 + while (b) {
  6 + t = b;
  7 + b = a % b;
  8 + a = t;
  9 + }
  10 + return a;
  11 +}
  12 +
  13 +/* Division by reciprocal multiplication. */
  14 +define fmul(b,n,d) {
  15 + return (2^b*n+d-1)/d;
  16 +}
  17 +
  18 +/* Adjustment factor when a ceiling value is used. Use as:
  19 + (imul * n) + (fmulxx * n + fadjxx) >> xx) */
  20 +define fadj(b,n,d) {
  21 + auto v;
  22 + d = d/gcd(n,d);
  23 + v = 2^b*(d-1)/d;
  24 + return v;
  25 +}
  26 +
  27 +/* Compute the appropriate mul/adj values as well as a shift count,
  28 + which brings the mul value into the range 2^b-1 <= x < 2^b. Such
  29 + a shift value will be correct in the signed integer range and off
  30 + by at most one in the upper half of the unsigned range. */
  31 +define fmuls(b,n,d) {
  32 + auto s, m;
  33 + for (s = 0; 1; s++) {
  34 + m = fmul(s,n,d);
  35 + if (m >= 2^(b-1))
  36 + return s;
  37 + }
  38 + return 0;
  39 +}
  40 +
  41 +define timeconst(hz) {
  42 + print "/* Automatically generated by kernel/timeconst.bc */\n"
  43 + print "/* Time conversion constants for HZ == ", hz, " */\n"
  44 + print "\n"
  45 +
  46 + print "#ifndef KERNEL_TIMECONST_H\n"
  47 + print "#define KERNEL_TIMECONST_H\n\n"
  48 +
  49 + print "#include <linux/param.h>\n"
  50 + print "#include <linux/types.h>\n\n"
  51 +
  52 + print "#if HZ != ", hz, "\n"
  53 + print "#error \qkernel/timeconst.h has the wrong HZ value!\q\n"
  54 + print "#endif\n\n"
  55 +
  56 + if (hz < 2) {
  57 + print "#error Totally bogus HZ value!\n"
  58 + } else {
  59 + s=fmuls(32,1000,hz)
  60 + obase=16
  61 + print "#define HZ_TO_MSEC_MUL32\tU64_C(0x", fmul(s,1000,hz), ")\n"
  62 + print "#define HZ_TO_MSEC_ADJ32\tU64_C(0x", fadj(s,1000,hz), ")\n"
  63 + obase=10
  64 + print "#define HZ_TO_MSEC_SHR32\t", s, "\n"
  65 +
  66 + s=fmuls(32,hz,1000)
  67 + obase=16
  68 + print "#define MSEC_TO_HZ_MUL32\tU64_C(0x", fmul(s,hz,1000), ")\n"
  69 + print "#define MSEC_TO_HZ_ADJ32\tU64_C(0x", fadj(s,hz,1000), ")\n"
  70 + obase=10
  71 + print "#define MSEC_TO_HZ_SHR32\t", s, "\n"
  72 +
  73 + obase=10
  74 + cd=gcd(hz,1000)
  75 + print "#define HZ_TO_MSEC_NUM\t\t", 1000/cd, "\n"
  76 + print "#define HZ_TO_MSEC_DEN\t\t", hz/cd, "\n"
  77 + print "#define MSEC_TO_HZ_NUM\t\t", hz/cd, "\n"
  78 + print "#define MSEC_TO_HZ_DEN\t\t", 1000/cd, "\n"
  79 + print "\n"
  80 +
  81 + s=fmuls(32,1000000,hz)
  82 + obase=16
  83 + print "#define HZ_TO_USEC_MUL32\tU64_C(0x", fmul(s,1000000,hz), ")\n"
  84 + print "#define HZ_TO_USEC_ADJ32\tU64_C(0x", fadj(s,1000000,hz), ")\n"
  85 + obase=10
  86 + print "#define HZ_TO_USEC_SHR32\t", s, "\n"
  87 +
  88 + s=fmuls(32,hz,1000000)
  89 + obase=16
  90 + print "#define USEC_TO_HZ_MUL32\tU64_C(0x", fmul(s,hz,1000000), ")\n"
  91 + print "#define USEC_TO_HZ_ADJ32\tU64_C(0x", fadj(s,hz,1000000), ")\n"
  92 + obase=10
  93 + print "#define USEC_TO_HZ_SHR32\t", s, "\n"
  94 +
  95 + obase=10
  96 + cd=gcd(hz,1000000)
  97 + print "#define HZ_TO_USEC_NUM\t\t", 1000000/cd, "\n"
  98 + print "#define HZ_TO_USEC_DEN\t\t", hz/cd, "\n"
  99 + print "#define USEC_TO_HZ_NUM\t\t", hz/cd, "\n"
  100 + print "#define USEC_TO_HZ_DEN\t\t", 1000000/cd, "\n"
  101 + print "\n"
  102 +
  103 + print "#endif /* KERNEL_TIMECONST_H */\n"
  104 + }
  105 + halt
  106 +}
  107 +
  108 +timeconst(hz)
kernel/timeconst.pl
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   -#
14   -# Usage: timeconst.pl HZ > timeconst.h
15   -#
16   -
17   -# Precomputed values for systems without Math::BigInt
18   -# Generated by:
19   -# timeconst.pl --can 24 32 48 64 100 122 128 200 250 256 300 512 1000 1024 1200
20   -%canned_values = (
21   - 24 => [
22   - '0xa6aaaaab','0x2aaaaaa',26,
23   - 125,3,
24   - '0xc49ba5e4','0x1fbe76c8b4',37,
25   - 3,125,
26   - '0xa2c2aaab','0xaaaa',16,
27   - 125000,3,
28   - '0xc9539b89','0x7fffbce4217d',47,
29   - 3,125000,
30   - ], 32 => [
31   - '0xfa000000','0x6000000',27,
32   - 125,4,
33   - '0x83126e98','0xfdf3b645a',36,
34   - 4,125,
35   - '0xf4240000','0x0',17,
36   - 31250,1,
37   - '0x8637bd06','0x3fff79c842fa',46,
38   - 1,31250,
39   - ], 48 => [
40   - '0xa6aaaaab','0x6aaaaaa',27,
41   - 125,6,
42   - '0xc49ba5e4','0xfdf3b645a',36,
43   - 6,125,
44   - '0xa2c2aaab','0x15555',17,
45   - 62500,3,
46   - '0xc9539b89','0x3fffbce4217d',46,
47   - 3,62500,
48   - ], 64 => [
49   - '0xfa000000','0xe000000',28,
50   - 125,8,
51   - '0x83126e98','0x7ef9db22d',35,
52   - 8,125,
53   - '0xf4240000','0x0',18,
54   - 15625,1,
55   - '0x8637bd06','0x1fff79c842fa',45,
56   - 1,15625,
57   - ], 100 => [
58   - '0xa0000000','0x0',28,
59   - 10,1,
60   - '0xcccccccd','0x733333333',35,
61   - 1,10,
62   - '0x9c400000','0x0',18,
63   - 10000,1,
64   - '0xd1b71759','0x1fff2e48e8a7',45,
65   - 1,10000,
66   - ], 122 => [
67   - '0x8325c53f','0xfbcda3a',28,
68   - 500,61,
69   - '0xf9db22d1','0x7fbe76c8b',35,
70   - 61,500,
71   - '0x8012e2a0','0x3ef36',18,
72   - 500000,61,
73   - '0xffda4053','0x1ffffbce4217',45,
74   - 61,500000,
75   - ], 128 => [
76   - '0xfa000000','0x1e000000',29,
77   - 125,16,
78   - '0x83126e98','0x3f7ced916',34,
79   - 16,125,
80   - '0xf4240000','0x40000',19,
81   - 15625,2,
82   - '0x8637bd06','0xfffbce4217d',44,
83   - 2,15625,
84   - ], 200 => [
85   - '0xa0000000','0x0',29,
86   - 5,1,
87   - '0xcccccccd','0x333333333',34,
88   - 1,5,
89   - '0x9c400000','0x0',19,
90   - 5000,1,
91   - '0xd1b71759','0xfff2e48e8a7',44,
92   - 1,5000,
93   - ], 250 => [
94   - '0x80000000','0x0',29,
95   - 4,1,
96   - '0x80000000','0x180000000',33,
97   - 1,4,
98   - '0xfa000000','0x0',20,
99   - 4000,1,
100   - '0x83126e98','0x7ff7ced9168',43,
101   - 1,4000,
102   - ], 256 => [
103   - '0xfa000000','0x3e000000',30,
104   - 125,32,
105   - '0x83126e98','0x1fbe76c8b',33,
106   - 32,125,
107   - '0xf4240000','0xc0000',20,
108   - 15625,4,
109   - '0x8637bd06','0x7ffde7210be',43,
110   - 4,15625,
111   - ], 300 => [
112   - '0xd5555556','0x2aaaaaaa',30,
113   - 10,3,
114   - '0x9999999a','0x1cccccccc',33,
115   - 3,10,
116   - '0xd0555556','0xaaaaa',20,
117   - 10000,3,
118   - '0x9d495183','0x7ffcb923a29',43,
119   - 3,10000,
120   - ], 512 => [
121   - '0xfa000000','0x7e000000',31,
122   - 125,64,
123   - '0x83126e98','0xfdf3b645',32,
124   - 64,125,
125   - '0xf4240000','0x1c0000',21,
126   - 15625,8,
127   - '0x8637bd06','0x3ffef39085f',42,
128   - 8,15625,
129   - ], 1000 => [
130   - '0x80000000','0x0',31,
131   - 1,1,
132   - '0x80000000','0x0',31,
133   - 1,1,
134   - '0xfa000000','0x0',22,
135   - 1000,1,
136   - '0x83126e98','0x1ff7ced9168',41,
137   - 1,1000,
138   - ], 1024 => [
139   - '0xfa000000','0xfe000000',32,
140   - 125,128,
141   - '0x83126e98','0x7ef9db22',31,
142   - 128,125,
143   - '0xf4240000','0x3c0000',22,
144   - 15625,16,
145   - '0x8637bd06','0x1fff79c842f',41,
146   - 16,15625,
147   - ], 1200 => [
148   - '0xd5555556','0xd5555555',32,
149   - 5,6,
150   - '0x9999999a','0x66666666',31,
151   - 6,5,
152   - '0xd0555556','0x2aaaaa',22,
153   - 2500,3,
154   - '0x9d495183','0x1ffcb923a29',41,
155   - 3,2500,
156   - ]
157   -);
158   -
159   -$has_bigint = eval 'use Math::BigInt qw(bgcd); 1;';
160   -
161   -sub bint($)
162   -{
163   - my($x) = @_;
164   - return Math::BigInt->new($x);
165   -}
166   -
167   -#
168   -# Constants for division by reciprocal multiplication.
169   -# (bits, numerator, denominator)
170   -#
171   -sub fmul($$$)
172   -{
173   - my ($b,$n,$d) = @_;
174   -
175   - $n = bint($n);
176   - $d = bint($d);
177   -
178   - return scalar (($n << $b)+$d-bint(1))/$d;
179   -}
180   -
181   -sub fadj($$$)
182   -{
183   - my($b,$n,$d) = @_;
184   -
185   - $n = bint($n);
186   - $d = bint($d);
187   -
188   - $d = $d/bgcd($n, $d);
189   - return scalar (($d-bint(1)) << $b)/$d;
190   -}
191   -
192   -sub fmuls($$$) {
193   - my($b,$n,$d) = @_;
194   - my($s,$m);
195   - my($thres) = bint(1) << ($b-1);
196   -
197   - $n = bint($n);
198   - $d = bint($d);
199   -
200   - for ($s = 0; 1; $s++) {
201   - $m = fmul($s,$n,$d);
202   - return $s if ($m >= $thres);
203   - }
204   - return 0;
205   -}
206   -
207   -# Generate a hex value if the result fits in 64 bits;
208   -# otherwise skip.
209   -sub bignum_hex($) {
210   - my($x) = @_;
211   - my $s = $x->as_hex();
212   -
213   - return (length($s) > 18) ? undef : $s;
214   -}
215   -
216   -# Provides mul, adj, and shr factors for a specific
217   -# (bit, time, hz) combination
218   -sub muladj($$$) {
219   - my($b, $t, $hz) = @_;
220   - my $s = fmuls($b, $t, $hz);
221   - my $m = fmul($s, $t, $hz);
222   - my $a = fadj($s, $t, $hz);
223   - return (bignum_hex($m), bignum_hex($a), $s);
224   -}
225   -
226   -# Provides numerator, denominator values
227   -sub numden($$) {
228   - my($n, $d) = @_;
229   - my $g = bgcd($n, $d);
230   - return ($n/$g, $d/$g);
231   -}
232   -
233   -# All values for a specific (time, hz) combo
234   -sub conversions($$) {
235   - my ($t, $hz) = @_;
236   - my @val = ();
237   -
238   - # HZ_TO_xx
239   - push(@val, muladj(32, $t, $hz));
240   - push(@val, numden($t, $hz));
241   -
242   - # xx_TO_HZ
243   - push(@val, muladj(32, $hz, $t));
244   - push(@val, numden($hz, $t));
245   -
246   - return @val;
247   -}
248   -
249   -sub compute_values($) {
250   - my($hz) = @_;
251   - my @val = ();
252   - my $s, $m, $a, $g;
253   -
254   - if (!$has_bigint) {
255   - die "$0: HZ == $hz not canned and ".
256   - "Math::BigInt not available\n";
257   - }
258   -
259   - # MSEC conversions
260   - push(@val, conversions(1000, $hz));
261   -
262   - # USEC conversions
263   - push(@val, conversions(1000000, $hz));
264   -
265   - return @val;
266   -}
267   -
268   -sub outputval($$)
269   -{
270   - my($name, $val) = @_;
271   - my $csuf;
272   -
273   - if (defined($val)) {
274   - if ($name !~ /SHR/) {
275   - $val = "U64_C($val)";
276   - }
277   - printf "#define %-23s %s\n", $name.$csuf, $val.$csuf;
278   - }
279   -}
280   -
281   -sub output($@)
282   -{
283   - my($hz, @val) = @_;
284   - my $pfx, $bit, $suf, $s, $m, $a;
285   -
286   - print "/* Automatically generated by kernel/timeconst.pl */\n";
287   - print "/* Conversion constants for HZ == $hz */\n";
288   - print "\n";
289   - print "#ifndef KERNEL_TIMECONST_H\n";
290   - print "#define KERNEL_TIMECONST_H\n";
291   - print "\n";
292   -
293   - print "#include <linux/param.h>\n";
294   - print "#include <linux/types.h>\n";
295   -
296   - print "\n";
297   - print "#if HZ != $hz\n";
298   - print "#error \"kernel/timeconst.h has the wrong HZ value!\"\n";
299   - print "#endif\n";
300   - print "\n";
301   -
302   - foreach $pfx ('HZ_TO_MSEC','MSEC_TO_HZ',
303   - 'HZ_TO_USEC','USEC_TO_HZ') {
304   - foreach $bit (32) {
305   - foreach $suf ('MUL', 'ADJ', 'SHR') {
306   - outputval("${pfx}_$suf$bit", shift(@val));
307   - }
308   - }
309   - foreach $suf ('NUM', 'DEN') {
310   - outputval("${pfx}_$suf", shift(@val));
311   - }
312   - }
313   -
314   - print "\n";
315   - print "#endif /* KERNEL_TIMECONST_H */\n";
316   -}
317   -
318   -# Pretty-print Perl values
319   -sub perlvals(@) {
320   - my $v;
321   - my @l = ();
322   -
323   - foreach $v (@_) {
324   - if (!defined($v)) {
325   - push(@l, 'undef');
326   - } elsif ($v =~ /^0x/) {
327   - push(@l, "\'".$v."\'");
328   - } else {
329   - push(@l, $v.'');
330   - }
331   - }
332   - return join(',', @l);
333   -}
334   -
335   -($hz) = @ARGV;
336   -
337   -# Use this to generate the %canned_values structure
338   -if ($hz eq '--can') {
339   - shift(@ARGV);
340   - @hzlist = sort {$a <=> $b} (@ARGV);
341   -
342   - print "# Precomputed values for systems without Math::BigInt\n";
343   - print "# Generated by:\n";
344   - print "# timeconst.pl --can ", join(' ', @hzlist), "\n";
345   - print "\%canned_values = (\n";
346   - my $pf = "\t";
347   - foreach $hz (@hzlist) {
348   - my @values = compute_values($hz);
349   - print "$pf$hz => [\n";
350   - while (scalar(@values)) {
351   - my $bit;
352   - foreach $bit (32) {
353   - my $m = shift(@values);
354   - my $a = shift(@values);
355   - my $s = shift(@values);
356   - print "\t\t", perlvals($m,$a,$s), ",\n";
357   - }
358   - my $n = shift(@values);
359   - my $d = shift(@values);
360   - print "\t\t", perlvals($n,$d), ",\n";
361   - }
362   - print "\t]";
363   - $pf = ', ';
364   - }
365   - print "\n);\n";
366   -} else {
367   - $hz += 0; # Force to number
368   - if ($hz < 1) {
369   - die "Usage: $0 HZ\n";
370   - }
371   -
372   - @val = @{$canned_values{$hz}};
373   - if (!defined(@val)) {
374   - @val = compute_values($hz);
375   - }
376   - output($hz, @val);
377   -}
378   -exit 0;