1 /** 2 * Simple benchmarking/profiling code 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.utils.bench; 15 16 import std.datetime; 17 import ae.sys.timing; 18 19 MonoTime lastTime; 20 21 static this() 22 { 23 lastTime = MonoTime.currTime(); 24 } 25 26 Duration elapsedTime() 27 { 28 auto c = MonoTime.currTime(); 29 auto d = c - lastTime; 30 lastTime = c; 31 return d; 32 } 33 34 struct TimedAction 35 { 36 string name; 37 Duration duration; 38 } 39 40 TimedAction[] timedActions; 41 size_t[string] timeNameIndices; 42 string currentAction = null; 43 44 void timeEnd(string action = null) 45 { 46 if (action && currentAction && action != currentAction) 47 action = currentAction ~ " / " ~ action; 48 if (action is null) 49 action = currentAction; 50 if (action is null) 51 action = "other"; 52 currentAction = null; 53 54 // ordered 55 if (action !in timeNameIndices) 56 { 57 timeNameIndices[action] = timedActions.length; 58 timedActions ~= TimedAction(action, elapsedTime()); 59 } 60 else 61 timedActions[timeNameIndices[action]].duration += elapsedTime(); 62 } 63 64 65 void timeStart(string action = null) 66 { 67 timeEnd(); 68 currentAction = action; 69 } 70 71 void timeAction(string action, void delegate() p) 72 { 73 timeStart(action); 74 p(); 75 timeEnd(action); 76 } 77 78 void clearTimes() 79 { 80 timedActions = null; 81 timeNameIndices = null; 82 lastTime = MonoTime.currTime(); 83 } 84 85 /// Retrieves current times and clears them. 86 string getTimes()() 87 { 88 timeEnd(); 89 90 import std.string, std.array; 91 string[] lines; 92 int maxLength; 93 foreach (action; timedActions) 94 if (!action.duration.empty) 95 if (maxLength < action.name.length) 96 maxLength = action.name.length; 97 string fmt = format("%%%ds : %%10d (%%s)", maxLength); 98 foreach (action; timedActions) 99 if (!action.duration.empty) 100 lines ~= format(fmt, action.name, action.duration.total!"hnsecs", action.duration); 101 clearTimes(); 102 return join(lines, "\n"); 103 } 104 105 void dumpTimes()() 106 { 107 import std.stdio; 108 import ae.sys.console; 109 auto times = getTimes(); 110 if (times.length) 111 writeln(times); 112 } 113 114 private string[] timeStack; 115 116 void timePush(string action = null) 117 { 118 timeStack ~= currentAction; 119 timeStart(action); 120 } 121 122 void timePop(string action = null) 123 { 124 timeEnd(action); 125 timeStart(timeStack[$-1]); 126 timeStack = timeStack[0..$-1]; 127 }