]>
Commit | Line | Data |
---|---|---|
412a5c57 VZ |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: printfbench.cpp | |
3 | // Purpose: A sample console app which benchmarks wxPrintf*() functions | |
4 | // Author: Francesco Montorsi | |
5 | // Modified by: | |
6 | // Created: 27/3/2006 | |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) 2006 Francesco Montorsi | |
9 | // Licence: wxWindows license | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
a15302de FM |
12 | // |
13 | // Profiling under Linux: | |
14 | // ===================== | |
15 | // | |
16 | // 1) configure wxWidgets in release mode | |
17 | // 2) make sure that HAVE_UNIX98_PRINTF is undefined (just #defining it to zero | |
18 | // does not work; you must comment out the entire #define) in your setup.h; | |
19 | // and also that wxUSE_PRINTF_POS_PARAMS is set to 1; this will force the | |
20 | // use of wx's own implementation of wxVsnprintf() | |
21 | // 3) compile wx | |
22 | // 4) set wxTEST_WX_ONLY to 1 and compile tests as well | |
23 | // | |
24 | // Now you have two main choices: | |
25 | // | |
26 | // - using gprof: | |
27 | // 5) add to the Makefile of this test program the -pg option both to | |
28 | // CXXFLAGS and to LDFLAGS | |
29 | // 6) run the test | |
30 | // 7) look at the gmon.out file with gprof utility | |
31 | // | |
32 | // - using valgrind: | |
33 | // 4) run "valgrind --tool=callgrind ./printfbench" | |
34 | // 5) run "kcachegrind dump_file_generated_by_callgrind" | |
35 | // | |
36 | ||
37 | ||
412a5c57 VZ |
38 | // ============================================================================ |
39 | // declarations | |
40 | // ============================================================================ | |
41 | ||
42 | // ---------------------------------------------------------------------------- | |
43 | // headers | |
44 | // ---------------------------------------------------------------------------- | |
45 | ||
ce939fe1 VZ |
46 | #include "testprec.h" |
47 | ||
48 | #ifdef __BORLANDC__ | |
49 | #pragma hdrstop | |
50 | #endif | |
51 | ||
52 | #ifndef WX_PRECOMP | |
53 | #include <wx/string.h> | |
54 | #endif // WX_PRECOMP | |
55 | ||
412a5c57 VZ |
56 | #include <wx/stopwatch.h> |
57 | #include <wx/utils.h> | |
58 | #include <wx/cmdline.h> | |
59 | #include <wx/app.h> | |
30957174 | 60 | #include <wx/wxchar.h> |
412a5c57 VZ |
61 | |
62 | ||
63 | // ---------------------------------------------------------------------------- | |
64 | // command line | |
65 | // ---------------------------------------------------------------------------- | |
66 | ||
a15302de | 67 | #define HELP_SWITCH "h" |
09e89ab1 | 68 | #define NUMBENCHMARK_OPTION "n" |
412a5c57 VZ |
69 | |
70 | static const wxCmdLineEntryDesc g_cmdLineDesc[] = | |
71 | { | |
09e89ab1 VZ |
72 | { wxCMD_LINE_SWITCH, HELP_SWITCH, "help", |
73 | "displays help on the command line parameters" }, | |
412a5c57 | 74 | |
09e89ab1 VZ |
75 | { wxCMD_LINE_OPTION, NUMBENCHMARK_OPTION, "numtest", |
76 | "the number of wxPrintf() calls to benchmark", wxCMD_LINE_VAL_NUMBER }, | |
412a5c57 VZ |
77 | |
78 | { wxCMD_LINE_NONE } | |
79 | }; | |
80 | ||
81 | ||
82 | // ---------------------------------------------------------------------------- | |
83 | // constants | |
84 | // ---------------------------------------------------------------------------- | |
85 | ||
86 | #define DEFAULT_NUMBENCHMARKS 100000 | |
87 | #define BUFSIZE 10000 | |
88 | ||
89 | // set wxTEST_WX_ONLY to 1 when you want to profile wx's implementation only. | |
412a5c57 VZ |
90 | #define wxTEST_WX_ONLY 1 |
91 | ||
92 | ||
93 | const wxString g_verylongString = | |
94 | wxT("very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very ") | |
95 | wxT("very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long string!\n\n\n"); | |
96 | ||
97 | ||
98 | // ---------------------------------------------------------------------------- | |
99 | // benchmarking helpers | |
100 | // ---------------------------------------------------------------------------- | |
101 | ||
102 | #define DO_LONG_BENCHMARK(fnc) \ | |
103 | fnc(buffer, BUFSIZE, \ | |
104 | wxT("This is a reasonably long string with various %s arguments, exactly %d, ") \ | |
105 | wxT("and is used as benchmark for %s - %% %.2f %d %s"), \ | |
106 | wxT("(many!!)"), 6, wxT("this program"), 23.342f, 999, \ | |
107 | g_verylongString.c_str()); | |
108 | ||
109 | #define DO_LONG_POSITIONAL_BENCHMARK(fnc) \ | |
110 | fnc(buffer, BUFSIZE, \ | |
111 | wxT("This is a %2$s and thus is harder to parse... let's %1$s ") \ | |
112 | wxT("for our benchmarking aims - %% %3$f %5$d %4$s"), \ | |
113 | wxT("test it"), wxT("string with positional arguments"), 23.342f, \ | |
114 | g_verylongString.c_str(), 999); | |
115 | ||
116 | #define DO_BENCHMARK(fnc) \ | |
117 | fnc(buffer, BUFSIZE, \ | |
118 | wxT("This is a short %s string with very few words"), wxT("test")); | |
119 | ||
120 | #define DO_POSITIONAL_BENCHMARK(fnc) \ | |
121 | fnc(buffer, BUFSIZE, \ | |
122 | wxT("This is a %2$s and thus is harder to parse... nonetheless, %1$s !"), \ | |
123 | wxT("test it"), wxT("string with positional arguments")); | |
124 | ||
125 | // the configure script of wxWidgets will define HAVE_UNIX98_PRINTF on those | |
126 | // system with a *printf() family of functions conformant to Unix 98 standard; | |
127 | // systems without the configure script as build system (e.g. Windows) do not | |
128 | // have positional support anyway | |
129 | #ifdef HAVE_UNIX98_PRINTF | |
130 | #define wxSYSTEM_HAS_POSPARAM_SUPPORT 1 | |
131 | #else | |
132 | #define wxSYSTEM_HAS_POSPARAM_SUPPORT 1 | |
133 | #endif | |
134 | ||
135 | // we need to avoid the use of wxPrintf() here since it could have been mapped | |
136 | // to wxWidgets' implementation of wxVsnPrintf() ! | |
137 | #if wxUSE_UNICODE | |
138 | #define sys_printf swprintf | |
139 | #else | |
140 | #define sys_printf snprintf | |
141 | #endif | |
142 | ||
143 | // the given stopwatch returns a time delta in milliseconds thus this macro | |
144 | // returns the number of microseconds required for a single *printf() call | |
145 | #define wxFMT(sw) ((double)((sw.Time()*1000.0)/tests)) | |
146 | ||
147 | ||
148 | ||
149 | ||
150 | // ---------------------------------------------------------------------------- | |
151 | // main | |
152 | // ---------------------------------------------------------------------------- | |
153 | ||
154 | int main(int argc, char **argv) | |
155 | { | |
156 | wxApp::CheckBuildOptions(WX_BUILD_OPTIONS_SIGNATURE, "program"); | |
157 | wxInitializer initializer; | |
158 | if ( !initializer ) | |
159 | { | |
160 | fprintf(stderr, "Failed to initialize the wxWidgets library, aborting."); | |
161 | ||
162 | return -1; | |
163 | } | |
164 | ||
165 | // parse the command line | |
166 | // ---------------------- | |
167 | ||
168 | wxCmdLineParser cmdParser(g_cmdLineDesc, argc, argv); | |
169 | if (cmdParser.Parse() != 0) | |
170 | return false; | |
171 | ||
172 | if (cmdParser.Found(HELP_SWITCH)) | |
173 | { | |
174 | cmdParser.Usage(); | |
175 | return false; | |
176 | } | |
177 | ||
178 | long tests; | |
179 | if (!cmdParser.Found(NUMBENCHMARK_OPTION, &tests)) | |
180 | tests = DEFAULT_NUMBENCHMARKS; | |
181 | ||
182 | ||
183 | ||
184 | // print some info useful to compare different benchmarks | |
185 | // ------------------------------------------------------- | |
186 | ||
187 | wxPrintf(wxT("\nRunning on %s\n"), wxGetOsDescription().c_str()); | |
188 | wxPrintf(wxT("Compiled in %s-%s-%s mode...\n\n"), | |
189 | #if wxUSE_UNICODE | |
190 | wxT("unicode"), | |
191 | #else | |
192 | wxT("ansi"), | |
193 | #endif | |
194 | #ifdef __WXDEBUG__ | |
195 | wxT("debug"), | |
196 | #else | |
197 | wxT("release"), | |
198 | #endif | |
199 | #ifdef WXUSINGDLL | |
200 | wxT("shared") | |
201 | #else | |
202 | wxT("static") | |
203 | #endif | |
204 | ); | |
205 | wxPrintf(wxT("Running %ld tests, for each configuration/implementation\n\n"), tests); | |
206 | ||
207 | ||
208 | ||
209 | // start! | |
210 | // ---------------------- | |
211 | ||
212 | wxChar buffer[BUFSIZE]; | |
213 | ||
214 | #if !wxTEST_WX_ONLY | |
215 | ||
216 | #if wxUSE_PRINTF_POS_PARAMS | |
217 | wxStopWatch wxPos; | |
218 | for (int i=0; i < tests; i++) | |
219 | { | |
220 | DO_LONG_POSITIONAL_BENCHMARK(wxSnprintf) | |
221 | DO_POSITIONAL_BENCHMARK(wxSnprintf) | |
222 | } | |
223 | wxPos.Pause(); | |
224 | #endif | |
225 | ||
226 | // benchmark system implementation of snprintf() | |
227 | wxStopWatch sys; | |
228 | for (int i=0; i < tests; i++) | |
229 | { | |
230 | DO_LONG_BENCHMARK(sys_printf) | |
231 | DO_BENCHMARK(sys_printf) | |
232 | } | |
233 | sys.Pause(); | |
234 | ||
235 | #if wxSYSTEM_HAS_POSPARAM_SUPPORT | |
236 | wxStopWatch sysPos; | |
237 | for (int i=0; i < tests; i++) | |
238 | { | |
239 | DO_LONG_POSITIONAL_BENCHMARK(wxSnprintf) | |
240 | DO_POSITIONAL_BENCHMARK(wxSnprintf) | |
241 | } | |
242 | sysPos.Pause(); | |
243 | #endif | |
244 | ||
245 | #else // !wxTEST_WX_ONLY | |
246 | ||
247 | // fake stopwatches | |
248 | wxStopWatch wxPos, sys, sysPos; | |
249 | wxPos.Pause(); | |
250 | sys.Pause(); | |
251 | sysPos.Pause(); | |
252 | ||
253 | #endif // !wxTEST_WX_ONLY | |
254 | ||
255 | // benchmark wxWidgets implementation of wxSnprintf() | |
256 | wxStopWatch wx; | |
257 | for (int i=0; i < tests; i++) | |
258 | { | |
259 | DO_LONG_BENCHMARK(wxSnprintf) | |
260 | DO_BENCHMARK(wxSnprintf) | |
261 | } | |
262 | wx.Pause(); | |
263 | ||
264 | // print results | |
265 | // ---------------------- | |
266 | ||
267 | wxPrintf(wxT("\n ============================== RESULTS ==============================\n")); | |
268 | wxPrintf(wxT(" => Time for the system's snprintf(): %.5f microsec\n"), wxFMT(sys)); | |
269 | #if wxSYSTEM_HAS_POSPARAM_SUPPORT | |
270 | wxPrintf(wxT(" => Time for the system's snprintf() with positionals: %.5f microsec\n"), wxFMT(sysPos)); | |
271 | #endif | |
272 | wxPrintf(wxT(" => Time for wxSnprintf(): %.5f microsec\n"), wxFMT(wx)); | |
273 | #if wxUSE_PRINTF_POS_PARAMS | |
274 | wxPrintf(wxT(" => Time for wxSnprintf() with positionals: %.5f microsec\n"), wxFMT(wxPos)); | |
275 | #endif | |
276 | ||
277 | double medium; | |
278 | #if wxSYSTEM_HAS_POSPARAM_SUPPORT && wxUSE_PRINTF_POS_PARAMS | |
279 | medium = ((double)wx.Time() / (double)sys.Time() + (double)wxPos.Time() / (double)sysPos.Time()) / 2; | |
280 | #else | |
281 | medium = (double)wx.Time() / (double)sys.Time(); | |
282 | #endif | |
283 | ||
284 | if (medium > 0.0) | |
285 | { | |
286 | // sometimes it happens that with a small number of tests, medium results zero; | |
287 | // in that case doing the 1.0/medium will not be a wise thing! | |
288 | wxPrintf(wxT("\nwxWidgets implementation is %.3f times slower\n") | |
289 | wxT("(i.e. %.3f times faster) than system implementation.\n"), medium, 1.0/medium); | |
290 | } | |
291 | ||
292 | wxPrintf(wxT("\n\n")); | |
293 | return 0; | |
294 | } | |
295 |