1 /*
2    AngelCode Scripting Library
3    Copyright (c) 2003-2016 Andreas Jonsson
4 
5    This software is provided 'as-is', without any express or implied
6    warranty. In no event will the authors be held liable for any
7    damages arising from the use of this software.
8 
9    Permission is granted to anyone to use this software for any
10    purpose, including commercial applications, and to alter it and
11    redistribute it freely, subject to the following restrictions:
12 
13    1. The origin of this software must not be misrepresented; you
14       must not claim that you wrote the original software. If you use
15       this software in a product, an acknowledgment in the product
16       documentation would be appreciated but is not required.
17 
18    2. Altered source versions must be plainly marked as such, and
19       must not be misrepresented as being the original software.
20 
21    3. This notice may not be removed or altered from any source
22       distribution.
23 
24    The original version of this library can be located at:
25    http://www.angelcode.com/angelscript/
26 
27    Andreas Jonsson
28    andreas@angelcode.com
29 */
30 
31 
32 //
33 // as_debug.h
34 //
35 
36 #ifndef AS_DEBUG_H
37 #define AS_DEBUG_H
38 
39 #include "as_config.h"
40 
41 #if defined(AS_DEBUG)
42 
43 #ifndef AS_WII
44 // The Wii SDK doesn't have these, we'll survive without AS_DEBUG
45 
46 #ifndef _WIN32_WCE
47 // Neither does WinCE
48 
49 #ifndef AS_PSVITA
50 // Possible on PSVita, but requires SDK access
51 
52 #if !defined(_MSC_VER) && (defined(__GNUC__) || defined(AS_MARMALADE))
53 
54 #ifdef __ghs__
55 // WIIU defines __GNUC__ but types are not defined here in 'conventional' way
56 #include <types.h>
57 typedef signed char int8_t;
58 typedef unsigned char uint8_t;
59 typedef signed short int16_t;
60 typedef unsigned short uint16_t;
61 typedef signed int int32_t;
62 typedef unsigned int uint32_t;
63 typedef signed long long int64_t;
64 typedef unsigned long long uint64_t;
65 typedef float float32_t;
66 typedef double float64_t;
67 #else
68 // Define mkdir for GNUC
69 #include <sys/stat.h>
70 #include <sys/types.h>
71 #define _mkdir(dirname) mkdir(dirname, S_IRWXU)
72 #endif
73 #else
74 #include <direct.h>
75 #endif
76 
77 #endif // AS_PSVITA
78 #endif // _WIN32_WCE
79 #endif // AS_WII
80 
81 #endif // !defined(AS_DEBUG)
82 
83 
84 
85 #if defined(_MSC_VER) && defined(AS_PROFILE)
86 // Currently only do profiling with MSVC++
87 
88 #include <mmsystem.h>
89 #include <direct.h>
90 #include "as_string.h"
91 #include "as_map.h"
92 #include "as_string_util.h"
93 
94 BEGIN_AS_NAMESPACE
95 
96 struct TimeCount
97 {
98 	double time;
99 	int    count;
100 	double max;
101 	double min;
102 };
103 
104 class CProfiler
105 {
106 public:
CProfiler()107 	CProfiler()
108 	{
109 		// We need to know how often the clock is updated
110 		__int64 tps;
111 		if( !QueryPerformanceFrequency((LARGE_INTEGER *)&tps) )
112 			usePerformance = false;
113 		else
114 		{
115 			usePerformance = true;
116 			ticksPerSecond = double(tps);
117 		}
118 
119 		timeOffset = GetTime();
120 	}
121 
~CProfiler()122 	~CProfiler()
123 	{
124 		WriteSummary();
125 	}
126 
GetTime()127 	double GetTime()
128 	{
129 		if( usePerformance )
130 		{
131 			__int64 ticks;
132 			QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
133 
134 			return double(ticks)/ticksPerSecond - timeOffset;
135 		}
136 
137 		return double(timeGetTime())/1000.0 - timeOffset;
138 	}
139 
Begin(const char * name)140 	double Begin(const char *name)
141 	{
142 		double time = GetTime();
143 
144 		// Add the scope to the key
145 		if( key.GetLength() )
146 			key += "|";
147 		key += name;
148 
149 		// Compensate for the time spent writing to the file
150 		timeOffset += GetTime() - time;
151 
152 		return time;
153 	}
154 
End(const char *,double beginTime)155 	void End(const char * /*name*/, double beginTime)
156 	{
157 		double time = GetTime();
158 
159 		double elapsed = time - beginTime;
160 
161 		// Update the profile info for this scope
162 		asSMapNode<asCString, TimeCount> *cursor;
163 		if( map.MoveTo(&cursor, key) )
164 		{
165 			cursor->value.time += elapsed;
166 			cursor->value.count++;
167 			if( cursor->value.max < elapsed )
168 				cursor->value.max = elapsed;
169 			if( cursor->value.min > elapsed )
170 				cursor->value.min = elapsed;
171 		}
172 		else
173 		{
174 			TimeCount tc = {elapsed, 1, elapsed, elapsed};
175 			map.Insert(key, tc);
176 		}
177 
178 		// Remove the inner most scope from the key
179 		int n = key.FindLast("|");
180 		if( n > 0 )
181 			key.SetLength(n);
182 		else
183 			key.SetLength(0);
184 
185 		// Compensate for the time spent writing to the file
186 		timeOffset += GetTime() - time;
187 	}
188 
189 protected:
WriteSummary()190 	void WriteSummary()
191 	{
192 		// Write the analyzed info into a file for inspection
193 		_mkdir("AS_DEBUG");
194 		FILE *fp;
195 		#if _MSC_VER >= 1500 && !defined(AS_MARMALADE)
196 			fopen_s(&fp, "AS_DEBUG/profiling_summary.txt", "wt");
197 		#else
198 			fp = fopen("AS_DEBUG/profiling_summary.txt", "wt");
199 		#endif
200 		if( fp == 0 )
201 			return;
202 
203 		fprintf(fp, "%-60s %10s %15s %15s %15s %15s\n\n", "Scope", "Count", "Tot time", "Avg time", "Max time", "Min time");
204 
205 		asSMapNode<asCString, TimeCount> *cursor;
206 		map.MoveLast(&cursor);
207 		while( cursor )
208 		{
209 			asCString key = cursor->key;
210 			int count;
211 			int n = key.FindLast("|", &count);
212 			if( count )
213 			{
214 				key = asCString("                                               ", count) + key.SubString(n+1);
215 			}
216 
217 			fprintf(fp, "%-60s %10d %15.6f %15.6f %15.6f %15.6f\n", key.AddressOf(), cursor->value.count, cursor->value.time, cursor->value.time / cursor->value.count, cursor->value.max, cursor->value.min);
218 
219 			map.MovePrev(&cursor, cursor);
220 		}
221 
222 		fclose(fp);
223 	}
224 
225 	double  timeOffset;
226 	double  ticksPerSecond;
227 	bool    usePerformance;
228 
229 	asCString                    key;
230 	asCMap<asCString, TimeCount> map;
231 };
232 
233 extern CProfiler g_profiler;
234 
235 class CProfilerScope
236 {
237 public:
CProfilerScope(const char * name)238 	CProfilerScope(const char *name)
239 	{
240 		this->name = name;
241 		beginTime = g_profiler.Begin(name);
242 	}
243 
~CProfilerScope()244 	~CProfilerScope()
245 	{
246 		g_profiler.End(name, beginTime);
247 	}
248 
249 protected:
250 	const char *name;
251 	double      beginTime;
252 };
253 
254 #define TimeIt(x) CProfilerScope profilescope(x)
255 
256 END_AS_NAMESPACE
257 
258 #else // !(_MSC_VER && AS_PROFILE)
259 
260 // Define it so nothing is done
261 #define TimeIt(x)
262 
263 #endif // !(_MSC_VER && AS_PROFILE)
264 
265 
266 
267 
268 #endif // defined(AS_DEBUG_H)
269 
270 
271