]>
Commit | Line | Data |
---|---|---|
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 | } |