1 // Copyright Ferdinand Majerech 2014. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 7 /// Profiling event and its members. 8 module tharsis.prof.event; 9 10 11 /** Types of events recorded by Profiler. 12 */ 13 // All EventID values must be 5-bit integers, see below. 14 enum EventID: ubyte 15 { 16 // A 'checkpoint' event followed by an absolute time value (8 7-bit bytes). 17 Checkpoint = 0, 18 // Zone start. 19 ZoneStart = 1, 20 // Zone end. 21 ZoneEnd = 2, 22 // Info string. EventID/time bytes are followed by a string length byte and a string 23 // of up to 255 chars. 24 Info = 3, 25 26 // A variable value. VariableType followed by a 7-bit encoded big-endian variable value. 27 Variable = 4 28 } 29 30 /// Variable types that can be recorded. 31 enum VariableType: ubyte 32 { 33 /// int. Encoded as a 5-byte long 7-bit encoded block. 34 Int = 1, 35 /// uint. Encoded as a 5-byte long 7-bit encoded block. 36 Uint = 2, 37 /// float. Encoded as a 5-byte long 7-bit encoded block. 38 Float = 3 39 } 40 41 // Lengths of various variable types when encoded in 7-bit. 42 package enum variable7BitLengths = [size_t.max, 5, 5, 5]; 43 44 /// Get a VariableType value corresponding to a variable type. 45 VariableType variableType(V)() 46 { 47 static if(is(V == int)) { return VariableType.Int; } 48 else static if(is(V == uint)) { return VariableType.Uint; } 49 else static if(is(V == float)){ return VariableType.Float; } 50 else static assert(false, "Unsupported type for Despiker variable event: " ~ V.stringof); 51 } 52 53 // A global array with all event IDs 54 import std.traits; 55 package immutable allEventIDs = [EnumMembers!EventID]; 56 package immutable allVariableTypes = [EnumMembers!VariableType]; 57 58 /// A variable parsed from profile data. 59 struct Variable 60 { 61 package: 62 // Variable type. 63 VariableType type_; 64 union 65 { 66 // Integer value if type_ is VariableType.Int. 67 int int_; 68 // Unsigned integer value if type_ is VariableType.Uint. 69 uint uint_; 70 // Float value if type_ is VariableType.Float. 71 float float_; 72 } 73 74 public: 75 /// Get the variable type. 76 VariableType type() @safe pure nothrow const @nogc 77 { 78 return type_; 79 } 80 81 /// toString() with no allocations (except stack). 82 void toString(scope void delegate(const(char)[]) sink) const 83 { 84 char[128] buffer; 85 import core.stdc.stdio; // formattedWrite might be better, maybe rewrite 86 int length; 87 final switch(type_) with(VariableType) 88 { 89 case Int: length = snprintf(buffer.ptr, buffer.length, "%d", varInt); break; 90 case Uint: length = snprintf(buffer.ptr, buffer.length, "%u", varUint); break; 91 case Float: length = snprintf(buffer.ptr, buffer.length, "%f", varFloat); break; 92 } 93 assert(length > 0 && length < buffer.length, "Error formatting a value to string"); 94 sink(buffer[0 .. length]); 95 } 96 97 /** Get the integer value of the variable 98 * 99 * Can only be called if type is VariableType.Int. 100 */ 101 int varInt() @safe pure nothrow const @nogc 102 { 103 assert(type_ == VariableType.Int, "Trying to read a non-int variable as an int"); 104 return int_; 105 } 106 107 /** Get the unsigned integer value of the variable 108 * 109 * Can only be called if type is VariableType.Uint. 110 */ 111 uint varUint() @safe pure nothrow const @nogc 112 { 113 assert(type_ == VariableType.Uint, "Trying to read a non-uint variable as a uint"); 114 return uint_; 115 } 116 117 /** Get the float value of the variable 118 * 119 * Can only be called if type is VariableType.Float. 120 */ 121 float varFloat() @safe pure nothrow const @nogc 122 { 123 assert(type_ == VariableType.Float, "Trying to read a non-float variable as a float"); 124 return float_; 125 } 126 } 127 128 /// Profiling event generated by EventRange. 129 struct Event 130 { 131 /// Event ID or type. 132 EventID id; 133 /// Time of the event since recording started in hectonanoseconds. 134 ulong time; 135 136 package union 137 { 138 const(char)[] info_; 139 Variable var_; 140 } 141 142 /// Get the info string if this is an Info event. 143 const(char)[] info() @trusted pure nothrow const @nogc 144 { 145 assert(id == EventID.Info, "Can't access info if it's not an Info event"); 146 return info_; 147 } 148 149 Variable var() @trusted pure nothrow const @nogc 150 { 151 assert(id == EventID.Variable, "Can't access variable if it's not a Variable event"); 152 return var_; 153 } 154 155 bool opEquals(ref const(Event) rhs) @safe pure nothrow const @nogc 156 { 157 if(id != rhs.id || time != rhs.time) { return false; } 158 final switch(id) 159 { 160 case EventID.Checkpoint, EventID.ZoneStart, EventID.ZoneEnd: 161 return true; 162 case EventID.Info: 163 return info == rhs.info; 164 case EventID.Variable: 165 if(var.type != rhs.var.type) { return false; } 166 final switch(var.type) 167 { 168 case VariableType.Int: return var.varInt == rhs.var.varInt; 169 case VariableType.Uint: return var.varUint == rhs.var.varUint; 170 case VariableType.Float: return var.varFloat == rhs.var.varFloat; 171 } 172 } 173 } 174 }