bench.cpp 8.6 KB

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