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