forked from pikhq/sabotage
-
Notifications
You must be signed in to change notification settings - Fork 68
/
linux-noperl-timeconst.patch
252 lines (247 loc) · 6.99 KB
/
linux-noperl-timeconst.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
Replace timeconst.bc with the c version I've been using for years (to replace
the perl version). Eventually I should add bc to toybox, but for now...
--- /dev/null
+++ linux/kernel/time/mktimeconst.c
@@ -0,0 +1,110 @@
+/* Copyright 2010 Parallels Inc, licensed under GPLv2 */
+/* Copyright 2010-2013 Rob Landley <rob@landley.net> */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+ uint64_t hz, periods[] = {1000, 1000000};
+ char *names[] = {"MSEC", "USEC"};
+ FILE *file;
+ int i, j;
+
+ if (argc != 3 || (hz = atol(argv[1])) < 1
+ || !(file = fopen(argv[2], "w")))
+ {
+ fprintf(stderr, "Usage: mktimeconst HZ FILENAME\n\n");
+ fprintf(stderr, "Generate a header file with constants to convert between\n");
+ fprintf(stderr, "decimal HZ timer ticks and milisecond or microsecond delays,\n");
+ fprintf(stderr, "using reciprocal multiplication to avoid 64 bit division.\n");
+ exit(1);
+ }
+
+ fprintf(file,
+ "/* Automatically generated by kernel/mktimeconst */\n"
+ "/* Conversion constants for HZ == %"PRIu64" */\n\n"
+ "#ifndef __KERNEL_TIMECONST_H\n"
+ "#define __KERNEL_TIMECONST_H\n\n"
+ "#include <linux/param.h>\n"
+ "#include <linux/types.h>\n\n"
+ "#if HZ != %"PRIu64"\n"
+ "#error \"kernel/timeconst.h has the wrong HZ value!\"\n"
+ "#endif\n\n", hz, hz);
+
+ /* Repeat for MSEC and USEC */
+
+ for (i = 0; i < 2; i++) {
+ uint64_t gcd, period;
+
+ /* Find greatest common denominator using Euclid's algorithm. */
+
+ gcd = hz;
+ period = periods[i];
+ while (period) {
+ uint64_t temp = gcd % period;
+ gcd = period;
+ period = temp;
+ }
+
+ /* Output both directions (HZ_TO_PERIOD and PERIOD_TO_HZ) */
+
+ for (j = 0; j < 2; j++) {
+ char name[16];
+ uint64_t from = j ? periods[i] : hz;
+ uint64_t to = j ? hz : periods[i];
+ uint64_t mul32 = 0, adj32 = 0, shift = 0;
+
+ sprintf(name, j ? "%s_TO_HZ" : "HZ_TO_%s", names[i]);
+
+ /* Figure out what shift value gives 32 significant
+ bits of MUL32 data. (Worst case to=1 from=1000000
+ uses 52 bits, to<<shift won't overflow 64 bit math.)
+ */
+
+ for (;;) {
+ mul32 = ((to << shift) + from - 1) / from;
+ if (mul32 >= (1UL<<31))
+ break;
+ shift++;
+ }
+
+ /* ADJ32 is is just (((FROM/GCD)-1)<<SHIFT)/(FROM/GCD)
+ but this can overflow 64 bit math (examples, HZ=24
+ or HZ=122). Worst case scenario uses 32+20+20=72
+ bits. Workaround: split off bottom 32 bits and
+ reassemble after calculation (32+64=96 bits). */
+
+ adj32 = from / gcd;
+
+ if (shift > 32) {
+ uint64_t upper, lower;
+
+ upper = (adj32 - 1) << (shift - 32);
+ lower = (upper % adj32) << 32;
+ adj32 = ((upper/adj32) << 32) + (lower/adj32);
+ } else
+ adj32 = ((adj32 - 1) << shift) / adj32;
+
+ /* Emit the constants into the header file. */
+
+ fprintf(file, "#define %s_MUL32\tU64_C(0x%"PRIx64")\n",
+ name, mul32);
+ fprintf(file, "#define %s_ADJ32\tU64_C(0x%"PRIx64")\n",
+ name, adj32);
+ fprintf(file, "#define %s_SHR32\t%"PRIu64"\n",
+ name, shift);
+ fprintf(file, "#define %s_NUM\t\tU64_C(%"PRIu64")\n",
+ name, to/gcd);
+ fprintf(file, "#define %s_DEN\t\tU64_C(%"PRIu64")\n\n",
+ name, from/gcd);
+ }
+ }
+ fprintf(file, "#endif /* __KERNEL_TIMECONST_H */\n");
+
+ /* Notice if the disk fills up. */
+
+ fflush(stdout);
+ return ferror(stdout);
+}
--- linux/kernel/time/timeconst.bc 2013-04-28 19:36:01.000000000 -0500
+++ /dev/null 2013-02-23 10:58:11.743993346 -0600
@@ -1,108 +0,0 @@
-scale=0
-
-define gcd(a,b) {
- auto t;
- while (b) {
- t = b;
- b = a % b;
- a = t;
- }
- return a;
-}
-
-/* Division by reciprocal multiplication. */
-define fmul(b,n,d) {
- return (2^b*n+d-1)/d;
-}
-
-/* Adjustment factor when a ceiling value is used. Use as:
- (imul * n) + (fmulxx * n + fadjxx) >> xx) */
-define fadj(b,n,d) {
- auto v;
- d = d/gcd(n,d);
- v = 2^b*(d-1)/d;
- return v;
-}
-
-/* Compute the appropriate mul/adj values as well as a shift count,
- which brings the mul value into the range 2^b-1 <= x < 2^b. Such
- a shift value will be correct in the signed integer range and off
- by at most one in the upper half of the unsigned range. */
-define fmuls(b,n,d) {
- auto s, m;
- for (s = 0; 1; s++) {
- m = fmul(s,n,d);
- if (m >= 2^(b-1))
- return s;
- }
- return 0;
-}
-
-define timeconst(hz) {
- print "/* Automatically generated by kernel/timeconst.bc */\n"
- print "/* Time conversion constants for HZ == ", hz, " */\n"
- print "\n"
-
- print "#ifndef KERNEL_TIMECONST_H\n"
- print "#define KERNEL_TIMECONST_H\n\n"
-
- print "#include <linux/param.h>\n"
- print "#include <linux/types.h>\n\n"
-
- print "#if HZ != ", hz, "\n"
- print "#error \qkernel/timeconst.h has the wrong HZ value!\q\n"
- print "#endif\n\n"
-
- if (hz < 2) {
- print "#error Totally bogus HZ value!\n"
- } else {
- s=fmuls(32,1000,hz)
- obase=16
- print "#define HZ_TO_MSEC_MUL32\tU64_C(0x", fmul(s,1000,hz), ")\n"
- print "#define HZ_TO_MSEC_ADJ32\tU64_C(0x", fadj(s,1000,hz), ")\n"
- obase=10
- print "#define HZ_TO_MSEC_SHR32\t", s, "\n"
-
- s=fmuls(32,hz,1000)
- obase=16
- print "#define MSEC_TO_HZ_MUL32\tU64_C(0x", fmul(s,hz,1000), ")\n"
- print "#define MSEC_TO_HZ_ADJ32\tU64_C(0x", fadj(s,hz,1000), ")\n"
- obase=10
- print "#define MSEC_TO_HZ_SHR32\t", s, "\n"
-
- obase=10
- cd=gcd(hz,1000)
- print "#define HZ_TO_MSEC_NUM\t\t", 1000/cd, "\n"
- print "#define HZ_TO_MSEC_DEN\t\t", hz/cd, "\n"
- print "#define MSEC_TO_HZ_NUM\t\t", hz/cd, "\n"
- print "#define MSEC_TO_HZ_DEN\t\t", 1000/cd, "\n"
- print "\n"
-
- s=fmuls(32,1000000,hz)
- obase=16
- print "#define HZ_TO_USEC_MUL32\tU64_C(0x", fmul(s,1000000,hz), ")\n"
- print "#define HZ_TO_USEC_ADJ32\tU64_C(0x", fadj(s,1000000,hz), ")\n"
- obase=10
- print "#define HZ_TO_USEC_SHR32\t", s, "\n"
-
- s=fmuls(32,hz,1000000)
- obase=16
- print "#define USEC_TO_HZ_MUL32\tU64_C(0x", fmul(s,hz,1000000), ")\n"
- print "#define USEC_TO_HZ_ADJ32\tU64_C(0x", fadj(s,hz,1000000), ")\n"
- obase=10
- print "#define USEC_TO_HZ_SHR32\t", s, "\n"
-
- obase=10
- cd=gcd(hz,1000000)
- print "#define HZ_TO_USEC_NUM\t\t", 1000000/cd, "\n"
- print "#define HZ_TO_USEC_DEN\t\t", hz/cd, "\n"
- print "#define USEC_TO_HZ_NUM\t\t", hz/cd, "\n"
- print "#define USEC_TO_HZ_DEN\t\t", 1000000/cd, "\n"
- print "\n"
-
- print "#endif /* KERNEL_TIMECONST_H */\n"
- }
- halt
-}
-
-timeconst(hz)
--- linux/kernel/time/Makefile
+++ linux/kernel/time/Makefile
@@ -125,17 +125,11 @@
$(obj)/time.o: $(obj)/timeconst.h
-quiet_cmd_hzfile = HZFILE $@
- cmd_hzfile = echo "hz=$(CONFIG_HZ)" > $@
-
-targets += hz.bc
-$(obj)/hz.bc: $(objtree)/include/config/hz.h FORCE
- $(call if_changed,hzfile)
-
-quiet_cmd_bc = BC $@
- cmd_bc = bc -q $(filter-out FORCE,$^) > $@
+hostprogs-y += mktimeconst
+quiet_cmd_mktimeconst = TIMEC $@
+ cmd_mktimeconst = $(obj)/mktimeconst $(CONFIG_HZ) $@ || ( rm -f $@ && exit 1 )
targets += timeconst.h
-$(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE
- $(call if_changed,bc)
+$(obj)/timeconst.h: $(obj)/mktimeconst FORCE
+ $(call if_changed,mktimeconst)