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 }