1 module chimpfella.kernels; 2 import chimpfella.measurement; 3 import std.traits; 4 import std.range.primitives; 5 6 @nogc: 7 @safe: 8 /+++ 9 If you want to generate templated data for a `TemplateBenchmark`, this will forward the current iterated 10 parameter to the parameter of ForwardTemplate. 11 +/ 12 struct ForwardTemplate(alias forwardThis) 13 { 14 alias contents = forwardThis; 15 } 16 17 /// 18 struct FunctionBenchmark(string name, alias genIndependantVariable, alias independantToData = void) 19 if (!is(genIndependantVariable == void) && isValidIndependantRange!genIndependantVariable) 20 { 21 static if (!is(independantToData == void)) 22 { 23 static if (isInstanceOf!(ForwardTemplate, independantToData)) 24 { 25 //Forward template to it 26 enum forward = true; 27 //pragma(msg, "wowo"); 28 } 29 else 30 { 31 enum forward = false; 32 //Try to check some things early. 33 static if (isCallable!(genIndependantVariable)) 34 alias elemT = ElementType!(typeof(genIndependantVariable())); 35 else 36 alias elemT = ElementType!(typeof(genIndependantVariable)); 37 alias forceEval = elemT; 38 static if (__traits(isTemplate, independantToData)) 39 alias finalFunc = independantToData!forceEval; 40 else 41 alias finalFunc = independantToData; 42 43 static if (arity!finalFunc) 44 { 45 enum compiles = __traits(compiles, finalFunc(elemT.init)); 46 //pragma(msg, fullyQualifiedName!finalFunc); 47 static if (__traits(isTemplate, finalFunc)) 48 { 49 //pragma(msg, "Magic"); 50 } 51 else 52 { 53 static assert(__traits(compiles, finalFunc(elemT.init))); 54 } 55 56 } 57 } 58 59 } 60 61 //The library knows everything about a function so running it with external data can be handled someplace else 62 63 ///Template parameter repeated as a struct field to simplify code elsewhere. 64 immutable string benchmarkName = name; 65 66 alias genIndSet = genIndependantVariable; 67 68 alias genData = independantToData; 69 70 /// 71 const Measurements[] measurementList; 72 this(in Measurements[] theList) 73 { 74 measurementList = theList; 75 } 76 } 77 /// 78 enum isValidIndependantRange(alias T) = isInputRange!(typeof(T)) 79 || isInputRange!(ReturnType!(typeof(T))); 80 /// 81 @safe unittest 82 { 83 import std.range : iota; 84 85 enum meas = [PhobosTimer("A stub").toMeasurement]; 86 @FunctionBenchmark!("Something with an integer", iota(1, 10_000))(meas) void func(int l) 87 { 88 89 } 90 91 alias getIota = () => iota(1, 200); 92 @FunctionBenchmark!("Something with an integer", getIota)(meas) void func2(int l) 93 { 94 95 } 96 } 97 /// 98 struct TemplateBenchmark(uint pIndex, Args...) 99 { 100 uint paramIndex = pIndex; 101 alias paramPack = Args; 102 } 103 /// 104 @safe unittest 105 { 106 import std.meta; 107 import std.range : repeat; 108 109 auto getRandPair(T)() 110 { 111 import std.random; 112 113 struct rndParams 114 { 115 AliasSeq!(T, T) pack; 116 } 117 118 rndParams tmp; 119 auto rnd = Random(unpredictableSeed); 120 121 // Generate an integer in [0, 1023] 122 tmp.pack[0] = cast(T) uniform(0, 1024, rnd); 123 tmp.pack[1] = cast(T) uniform(0, 1024, rnd); 124 } 125 126 @FunctionBenchmark!("int add benchmark", 0.repeat(100), getRandPair!int) int add(int x, int y) 127 { 128 return x + y; 129 } 130 131 @TemplateBenchmark!(0, int, float, double) @FunctionBenchmark!( 132 "Templated add benchmark", 0.repeat(100), getRandPair) T templatedAdd(T)(T x, T y) 133 { 134 return x + y; 135 } 136 }