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