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