1 /**
2 Copyright: Copyright Thomas Stuart Bockman 2015
3 License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
4 Authors: Thomas Stuart Bockman
5 */
6 
7 module checkedint.tests.benchmark;
8 import checkedint, checkedint.flags, checkedint.traits;
9 
10 import std.algorithm, std.stdio;
11 static if(__VERSION__ >= 2068) {
12     version(GNU) { static assert(false); }
13     import std.meta : AliasSeq;
14 } else
15     import std.typetuple : AliasSeq = TypeTuple;
16 
17 /+@safe:+/
18 
19 void benchMacro() {
20     benchMacro!"trialPrimes"();
21     benchMacro!"collatzSort"();
22 }
23 
24 ulong checkSum;
25 bool invalid;
26 void benchMacro(string testStr)() {
27     import std.conv : to;
28     import std.datetime : benchmark, Duration;
29 
30     mixin("alias test = " ~ testStr ~ ";");
31     writeln();
32     write("Running "); write(testStr); writeln("() benchmark... ");
33     function() @trusted { stdout.flush(); }();
34 
35     checkSum = 0;
36     test!int();
37     enum trials = 3;
38     enum laps = 3;
39     const compSum = checkSum * laps * trials;
40 
41     foreach(V; AliasSeq!(int, uint, long, ulong)) {
42         foreach(N; AliasSeq!(
43             V,
44             SafeInt!(V, true, false),
45             SafeInt!(V, true, true),
46             SmartInt!(V, true, false),
47             SmartInt!(V, true, true)))
48         {
49             checkSum = 0;
50             invalid = false;
51             writef("%40s: ", N.stringof);
52 
53             auto best = Duration.max;
54             foreach(i; 0 .. trials) {
55                 auto r = to!Duration(benchmark!(test!N)(laps)[0]) / laps;
56                 if(r < best)
57                     best = r;
58             }
59 
60             if(checkSum != compSum)
61                 write("!CHECKSUM ");
62             if(invalid)
63                 write("!INVALID ");
64             writeln(to!Duration(best));
65         }
66     }
67 
68     writeln("DONE");
69 }
70 
71 template SafeFold(N) {
72     template SafeFold(real folded) {
73         alias BN = BasicScalar!N;
74         static assert(BN.min <= folded && folded <= BN.max);
75         enum SafeFold = cast(BN)folded;
76     }
77 }
78 
79 /+pragma(inline, true) {+/
80     auto mulPow2(N, M)(const N coef, const M exp) {
81         return coef << exp; }
82     auto divPow2(N, M)(const N coef, const M exp) {
83         return coef >> exp; }
84 /+}+/
85 
86 void trialPrimes(N)() {
87     alias V = SafeFold!N;
88 
89     static auto floorSqrt(N n) {
90         assert(n >= V!0);
91 
92         enum N maxT = isSigned!N?
93             V!((1414L.mulPow2((N.sizeof * 4) - 11)) - 1L) :
94             V!((1L.mulPow2(N.sizeof * 4)) - 1L);
95         N t = min((n/V!2 + V!1), maxT);
96         N r0 = t;
97         N sq0 = r0 * r0;
98         assert(n <= sq0);
99 
100         while(t >= V!1) {
101             if(sq0 < n) {
102                 const r1 = r0 + t;
103                 const sq1 = r1 * r1;
104 
105                 if(sq1 <= n) {
106                     r0 = r1;
107                     sq0 = sq1;
108                 } else
109                     t /= V!2;
110             } else if(sq0 > n) {
111                 r0 = r0 - t;
112                 sq0 = r0 * r0;
113 
114                 t /= V!2;
115             } else
116                 break;
117         }
118 
119         return r0;
120     }
121 
122     enum PrimeCount = V!40000;
123     N[PrimeCount] primes;
124     N[PrimeCount] primeRoots;
125 
126     N p = V!0;
127     primes[idx(p)] = N.max;
128     N n = V!2;
129     while(true) {
130         const N rootN = floorSqrt(n);
131 
132         bool pass = true;
133         for(N dP = V!0; primes[idx(dP)] <= rootN; ++dP) {
134             if(n % primes[idx(dP)] == V!0) {
135                 pass = false;
136                 break;
137             }
138         }
139 
140         if(pass) {
141             primes[idx(p)] = n;
142             primeRoots[idx(p)] = rootN;
143 
144             ++p;
145             if(p < PrimeCount)
146                 primes[idx(p)] = N.max;
147             else
148                 break;
149         }
150 
151         ++n;
152     }
153 
154     N subSum = V!0;
155     for(N pu = V!0; pu < PrimeCount; ++pu)
156         subSum += primeRoots[idx(pu)];
157     checkSum += subSum.bscal;
158     invalid = invalid || IntFlags.local;
159     IntFlags.local.clear();
160 
161   /+for(N q = 0; q < p; ++q) {
162         write(primes[idx(q)]);
163         write(" : ");
164         write(primeRoots[idx(q)]);
165         if(q % 8 != 7)
166             write(", ");
167         else
168             writeln();
169     }
170     writeln();
171     stdin.readln();+/
172 }
173 
174 void collatzSort(N)() {
175     alias V = SafeFold!N;
176 
177     static void quickSort(N[] array, N lowX, N highX) {
178         if(lowX >= highX)
179             return;
180 
181         N pivotX = (lowX + highX).divPow2(1u);
182         N pivotV = array[idx(pivotX)];
183         array[idx(pivotX)] = array[idx(highX)];
184         array[idx(highX)] = pivotV;
185 
186         N storeX = lowX;
187         N iX = lowX;
188         while(iX < highX) {
189             const iV = array[idx(iX)];
190             if(iV < pivotV) {
191                 array[idx(iX)] = array[idx(storeX)];
192                 array[idx(storeX)] = iV;
193                 ++storeX;
194             }
195             ++iX;
196         }
197         pivotX = storeX;
198 
199         pivotV = array[idx(pivotX)];
200         array[idx(pivotX)] = array[idx(highX)];
201         array[idx(highX)] = pivotV;
202 
203         quickSort(array, lowX, pivotX - V!1);
204         quickSort(array, pivotX + V!1, highX);
205     }
206 
207     enum N maxN = V!113_382;
208     N[idx(maxN)] finalIs;
209 
210     for(N n = V!0; n < maxN; ++n) {
211         N i = V!0;
212         N ai = n + V!1;
213         while(ai != V!1) {
214             if((ai & V!0x1) ==  V!0)
215                 ai = ai.divPow2(1u);
216             else
217                 ai = V!3*ai + V!1;
218 
219             ++i;
220         }
221 
222         finalIs[idx(n)] = i;
223     }
224 
225     quickSort(finalIs, N(V!0), maxN - V!1);
226 
227     N subSum = finalIs[0];
228     for(N x = V!1; x < maxN; ++x) {
229         subSum += finalIs[idx(x)];
230         if(finalIs[idx(x)] < finalIs[idx(x - V!1)])
231             invalid = true;
232     }
233     checkSum += subSum.bscal;
234     invalid = invalid || IntFlags.local;
235     IntFlags.local.clear();
236 }