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