]> git.saurik.com Git - wxWidgets.git/blob - tests/benchmarks/bench.cpp
handle loss of connection explicitly in Read/Write() to fix socket IO under Unix...
[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 = func->Init();
258 for ( long a = 0; ok && 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 const long t = sw.Time();
269 if ( t < timeMin )
270 timeMin = t;
271 if ( t > timeMax )
272 timeMax = t;
273 timeTotal += t;
274 }
275
276 func->Done();
277
278 if ( !ok )
279 {
280 wxPrintf("ERROR\n");
281 rc = EXIT_FAILURE;
282 }
283 else
284 {
285 wxPrintf("%ldms total, ", timeTotal);
286
287 long times = m_avgCount;
288 if ( m_avgCount > 2 )
289 {
290 timeTotal -= timeMin + timeMax;
291 times -= 2;
292 }
293
294 wxPrintf("%.2f avg (min=%ld, max=%ld)\n",
295 (float)timeTotal / times, timeMin, timeMax);
296 }
297 }
298
299 return rc;
300 }
301
302 int BenchApp::OnExit()
303 {
304 #if wxUSE_GUI
305 delete GetTopWindow();
306 #endif // wxUSE_GUI
307
308 return 0;
309 }
310
311 /* static */
312 void BenchApp::ListBenchmarks()
313 {
314 wxPrintf("Available benchmarks:\n");
315 for ( Bench::Function *func = Bench::Function::GetFirst();
316 func;
317 func = func->GetNext() )
318 {
319 wxPrintf("\t%s\n", func->GetName());
320 }
321 }