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