The rounded corners look really dumb at this size.
[wxWidgets.git] / tests / benchmarks / bench.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: tests/benchmarks/bench.cpp
3 // Purpose: Main file of the benchmarking suite
4 // Author: Vadim Zeitlin
5 // Created: 2008-07-19
6 // Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // ============================================================================
11 // declarations
12 // ============================================================================
13
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17
18 #include "wx/app.h"
19 #include "wx/cmdline.h"
20 #include "wx/stopwatch.h"
21
22 #if wxUSE_GUI
23 #include "wx/frame.h"
24 #endif
25
26 #include "bench.h"
27
28 // ----------------------------------------------------------------------------
29 // constants
30 // ----------------------------------------------------------------------------
31
32 static const char OPTION_LIST = 'l';
33 static const char OPTION_SINGLE = '1';
34
35 static const char OPTION_AVG_COUNT = 'a';
36 static const char OPTION_NUM_RUNS = 'n';
37 static const char OPTION_NUMERIC_PARAM = 'p';
38 static const char OPTION_STRING_PARAM = 's';
39
40 // ----------------------------------------------------------------------------
41 // BenchApp declaration
42 // ----------------------------------------------------------------------------
43
44 #if wxUSE_GUI
45 typedef wxApp BenchAppBase;
46 #else
47 typedef wxAppConsole BenchAppBase;
48 #endif
49
50 class BenchApp : public BenchAppBase
51 {
52 public:
53 BenchApp();
54
55 // standard overrides
56 virtual void OnInitCmdLine(wxCmdLineParser& parser);
57 virtual bool OnCmdLineParsed(wxCmdLineParser& parser);
58 virtual bool OnInit();
59 virtual int OnRun();
60 virtual int OnExit();
61
62 // accessors
63 int GetNumericParameter() const { return m_numParam; }
64 const wxString& GetStringParameter() const { return m_strParam; }
65
66 private:
67 // list all registered benchmarks
68 void ListBenchmarks();
69
70 // command lines options/parameters
71 wxSortedArrayString m_toRun;
72 long m_numRuns,
73 m_avgCount,
74 m_numParam;
75 wxString m_strParam;
76 };
77
78 IMPLEMENT_APP_CONSOLE(BenchApp)
79
80 // ============================================================================
81 // Bench namespace symbols implementation
82 // ============================================================================
83
84 Bench::Function *Bench::Function::ms_head = NULL;
85
86 long Bench::GetNumericParameter()
87 {
88 return wxGetApp().GetNumericParameter();
89 }
90
91 wxString Bench::GetStringParameter()
92 {
93 return wxGetApp().GetStringParameter();
94 }
95
96 // ============================================================================
97 // BenchApp implementation
98 // ============================================================================
99
100 BenchApp::BenchApp()
101 {
102 m_avgCount = 10;
103 m_numRuns = 10000; // just some default (TODO: switch to time-based one)
104 m_numParam = 0;
105 }
106
107 bool BenchApp::OnInit()
108 {
109 if ( !BenchAppBase::OnInit() )
110 return false;
111
112 wxPrintf("wxWidgets benchmarking program\n"
113 "Build: %s\n", WX_BUILD_OPTIONS_SIGNATURE);
114
115 #if wxUSE_GUI
116 // create a hidden parent window to be used as parent for the GUI controls
117 new wxFrame(NULL, wxID_ANY, "Hidden wx benchmark frame");
118 #endif // wxUSE_GUI
119
120 return true;
121 }
122
123 void BenchApp::OnInitCmdLine(wxCmdLineParser& parser)
124 {
125 BenchAppBase::OnInitCmdLine(parser);
126
127 parser.AddSwitch(OPTION_LIST,
128 "list",
129 "list all the existing benchmarks");
130
131 parser.AddSwitch(OPTION_SINGLE,
132 "single",
133 "run the benchmark once only");
134
135 parser.AddOption(OPTION_AVG_COUNT,
136 "avg-count",
137 wxString::Format
138 (
139 "number of times to run benchmarking loop (default: %ld)",
140 m_avgCount
141 ),
142 wxCMD_LINE_VAL_NUMBER);
143 parser.AddOption(OPTION_NUM_RUNS,
144 "num-runs",
145 wxString::Format
146 (
147 "number of times to run each benchmark in a loop "
148 "(default: %ld)",
149 m_numRuns
150 ),
151 wxCMD_LINE_VAL_NUMBER);
152 parser.AddOption(OPTION_NUMERIC_PARAM,
153 "num-param",
154 wxString::Format
155 (
156 "numeric parameter used by some benchmark functions "
157 "(default: %ld)",
158 m_numParam
159 ),
160 wxCMD_LINE_VAL_NUMBER);
161 parser.AddOption(OPTION_STRING_PARAM,
162 "str-param",
163 "string parameter used by some benchmark functions "
164 "(default: empty)",
165 wxCMD_LINE_VAL_STRING);
166
167 parser.AddParam("benchmark name",
168 wxCMD_LINE_VAL_STRING,
169 wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
170 }
171
172 bool BenchApp::OnCmdLineParsed(wxCmdLineParser& parser)
173 {
174 if ( parser.Found(OPTION_LIST) )
175 {
176 ListBenchmarks();
177
178 return false;
179 }
180
181 const size_t count = parser.GetParamCount();
182 if ( !count )
183 {
184 parser.Usage();
185
186 ListBenchmarks();
187
188 return false;
189 }
190
191 bool numRunsSpecified = false;
192 if ( parser.Found(OPTION_AVG_COUNT, &m_avgCount) )
193 numRunsSpecified = true;
194 if ( parser.Found(OPTION_NUM_RUNS, &m_numRuns) )
195 numRunsSpecified = true;
196 parser.Found(OPTION_NUMERIC_PARAM, &m_numParam);
197 parser.Found(OPTION_STRING_PARAM, &m_strParam);
198 if ( parser.Found(OPTION_SINGLE) )
199 {
200 if ( numRunsSpecified )
201 {
202 wxFprintf(stderr, "Incompatible options specified.\n");
203
204 return false;
205 }
206
207 m_avgCount =
208 m_numRuns = 1;
209 }
210
211 // construct sorted array for quick verification of benchmark names
212 wxSortedArrayString benchmarks;
213 for ( Bench::Function *func = Bench::Function::GetFirst();
214 func;
215 func = func->GetNext() )
216 {
217 benchmarks.push_back(func->GetName());
218 }
219
220 for ( size_t n = 0; n < count; n++ )
221 {
222 const wxString name = parser.GetParam(n);
223 if ( benchmarks.Index(name) == wxNOT_FOUND )
224 {
225 wxFprintf(stderr, "No benchmark named \"%s\".\n", name);
226 return false;
227 }
228
229 m_toRun.push_back(name);
230 }
231
232 return BenchAppBase::OnCmdLineParsed(parser);
233 }
234
235 int BenchApp::OnRun()
236 {
237 int rc = EXIT_SUCCESS;
238 for ( Bench::Function *func = Bench::Function::GetFirst();
239 func;
240 func = func->GetNext() )
241 {
242 if ( m_toRun.Index(func->GetName()) == wxNOT_FOUND )
243 continue;
244
245 wxString params;
246 if ( m_numParam )
247 params += wxString::Format(" with N=%ld", m_numParam);
248 if ( !m_strParam.empty() )
249 {
250 if ( !params.empty() )
251 params += " and";
252 params += wxString::Format(" with s=\"%s\"", m_strParam);
253 }
254
255 wxPrintf("Benchmarking %s%s: ", func->GetName(), params);
256
257 long timeMin = LONG_MAX,
258 timeMax = 0,
259 timeTotal = 0;
260 bool ok = func->Init();
261 for ( long a = 0; ok && a < m_avgCount; a++ )
262 {
263 wxStopWatch sw;
264 for ( long n = 0; n < m_numRuns && ok; n++ )
265 {
266 ok = func->Run();
267 }
268
269 sw.Pause();
270
271 const long t = sw.Time();
272 if ( t < timeMin )
273 timeMin = t;
274 if ( t > timeMax )
275 timeMax = t;
276 timeTotal += t;
277 }
278
279 func->Done();
280
281 if ( !ok )
282 {
283 wxPrintf("ERROR\n");
284 rc = EXIT_FAILURE;
285 }
286 else
287 {
288 wxPrintf("%ldms total, ", timeTotal);
289
290 long times = m_avgCount;
291 if ( m_avgCount > 2 )
292 {
293 timeTotal -= timeMin + timeMax;
294 times -= 2;
295 }
296
297 wxPrintf("%.2f avg (min=%ld, max=%ld)\n",
298 (float)timeTotal / times, timeMin, timeMax);
299 }
300
301 fflush(stdout);
302 }
303
304 return rc;
305 }
306
307 int BenchApp::OnExit()
308 {
309 #if wxUSE_GUI
310 delete GetTopWindow();
311 #endif // wxUSE_GUI
312
313 return 0;
314 }
315
316 /* static */
317 void BenchApp::ListBenchmarks()
318 {
319 wxPrintf("Available benchmarks:\n");
320 for ( Bench::Function *func = Bench::Function::GetFirst();
321 func;
322 func = func->GetNext() )
323 {
324 wxPrintf("\t%s\n", func->GetName());
325 }
326 }