KiCad PCB EDA Suite
io_benchmark.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2017-2019 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 #include <wx/wx.h>
25 #include <richio.h>
26 
27 #include <chrono>
28 #include <ios>
29 #include <functional>
30 #include <iostream>
31 
32 #include <fstream>
33 
34 #include <wx/wfstream.h>
35 #include <wx/filename.h>
36 
39 
40 
41 using CLOCK = std::chrono::steady_clock;
42 using TIME_PT = std::chrono::time_point<CLOCK>;
43 
44 
46 {
47  unsigned linesRead;
48 
54  unsigned charAcc;
55 
56  std::chrono::milliseconds benchDurMs;
57 };
58 
59 
60 using BENCH_FUNC = std::function<void(const wxFileName&, int, BENCH_REPORT&)>;
61 
62 
63 struct BENCHMARK
64 {
67  wxString name;
68 };
69 
70 
75 static void bench_fstream( const wxFileName& aFile, int aReps, BENCH_REPORT& report )
76 {
77  std::string line;
78 
79  for( int i = 0; i < aReps; ++i)
80  {
81  std::ifstream fstr( aFile.GetFullPath().ToUTF8() );
82 
83  while( getline( fstr, line ) )
84  {
85  report.linesRead++;
86  report.charAcc += (unsigned char) line[0];
87  }
88 
89  fstr.close();
90  }
91 }
92 
93 
98 static void bench_fstream_reuse( const wxFileName& aFile, int aReps, BENCH_REPORT& report )
99 {
100  std::string line;
101  std::ifstream fstr( aFile.GetFullPath().ToUTF8() );
102 
103  for( int i = 0; i < aReps; ++i)
104  {
105  while( getline( fstr, line ) )
106  {
107  report.linesRead++;
108  report.charAcc += (unsigned char) line[0];
109  }
110  fstr.clear() ;
111  fstr.seekg(0, std::ios::beg) ;
112  }
113 
114  fstr.close();
115 }
116 
117 
122 template<typename LR>
123 static void bench_line_reader( const wxFileName& aFile, int aReps, BENCH_REPORT& report )
124 {
125  for( int i = 0; i < aReps; ++i)
126  {
127  LR fstr( aFile.GetFullPath() );
128  while( fstr.ReadLine() )
129  {
130  report.linesRead++;
131  report.charAcc += (unsigned char) fstr.Line()[0];
132  }
133  }
134 }
135 
136 
141 template<typename LR>
142 static void bench_line_reader_reuse( const wxFileName& aFile, int aReps, BENCH_REPORT& report )
143 {
144  LR fstr( aFile.GetFullPath() );
145  for( int i = 0; i < aReps; ++i)
146  {
147 
148  while( fstr.ReadLine() )
149  {
150  report.linesRead++;
151  report.charAcc += (unsigned char) fstr.Line()[0];
152  }
153 
154  fstr.Rewind();
155  }
156 }
157 
158 
163 static void bench_string_lr( const wxFileName& aFile, int aReps, BENCH_REPORT& report )
164 {
165  for( int i = 0; i < aReps; ++i)
166  {
167  std::ifstream ifs( aFile.GetFullPath().ToStdString() );
168  std::string content((std::istreambuf_iterator<char>(ifs)),
169  std::istreambuf_iterator<char>());
170 
171  STRING_LINE_READER fstr( content, aFile.GetFullPath() );
172  while( fstr.ReadLine() )
173  {
174  report.linesRead++;
175  report.charAcc += (unsigned char) fstr.Line()[0];
176  }
177  }
178 }
179 
180 
188 static void bench_string_lr_reuse( const wxFileName& aFile, int aReps, BENCH_REPORT& report )
189 {
190  std::ifstream ifs( aFile.GetFullPath().ToStdString() );
191  std::string content((std::istreambuf_iterator<char>(ifs)),
192  std::istreambuf_iterator<char>());
193 
194  for( int i = 0; i < aReps; ++i)
195  {
196  STRING_LINE_READER fstr( content, aFile.GetFullPath() );
197  while( fstr.ReadLine() )
198  {
199  report.linesRead++;
200  report.charAcc += (unsigned char) fstr.Line()[0];
201  }
202  }
203 }
204 
205 
211 template<typename S>
212 static void bench_wxis( const wxFileName& aFile, int aReps, BENCH_REPORT& report )
213 {
214  S fileStream( aFile.GetFullPath() );
215 
216  for( int i = 0; i < aReps; ++i)
217  {
218  INPUTSTREAM_LINE_READER istr( &fileStream, aFile.GetFullPath() );
219 
220  while( istr.ReadLine() )
221  {
222  report.linesRead++;
223  report.charAcc += (unsigned char) istr.Line()[0];
224  }
225 
226  fileStream.SeekI( 0 );
227  }
228 }
229 
230 
236 template<typename S>
237 static void bench_wxis_reuse( const wxFileName& aFile, int aReps, BENCH_REPORT& report )
238 {
239  S fileStream( aFile.GetFullPath() );
240  INPUTSTREAM_LINE_READER istr( &fileStream, aFile.GetFullPath() );
241 
242  for( int i = 0; i < aReps; ++i)
243  {
244  while( istr.ReadLine() )
245  {
246  report.linesRead++;
247  report.charAcc += (unsigned char) istr.Line()[0];
248  }
249 
250  fileStream.SeekI( 0 );
251  }
252 }
253 
254 
260 template<typename WXIS>
261 static void bench_wxbis( const wxFileName& aFile, int aReps, BENCH_REPORT& report )
262 {
263  WXIS fileStream( aFile.GetFullPath() );
264  wxBufferedInputStream bufferedStream( fileStream );
265 
266  for( int i = 0; i < aReps; ++i)
267  {
268  INPUTSTREAM_LINE_READER istr( &bufferedStream, aFile.GetFullPath() );
269 
270  while( istr.ReadLine() )
271  {
272  report.linesRead++;
273  report.charAcc += (unsigned char) istr.Line()[0];
274  }
275 
276  fileStream.SeekI( 0 );
277  }
278 }
279 
280 
286 template<typename WXIS>
287 static void bench_wxbis_reuse( const wxFileName& aFile, int aReps, BENCH_REPORT& report )
288 {
289  WXIS fileStream( aFile.GetFullPath() );
290  wxBufferedInputStream bufferedStream( fileStream );
291 
292  INPUTSTREAM_LINE_READER istr( &bufferedStream, aFile.GetFullPath() );
293 
294  for( int i = 0; i < aReps; ++i)
295  {
296  while( istr.ReadLine() )
297  {
298  report.linesRead++;
299  report.charAcc += (unsigned char) istr.Line()[0];
300  }
301 
302  fileStream.SeekI( 0 );
303  }
304 }
305 
309 static std::vector<BENCHMARK> benchmarkList =
310 {
311  { 'f', bench_fstream, "std::fstream" },
312  { 'F', bench_fstream_reuse, "std::fstream, reused" },
313  { 'r', bench_line_reader<FILE_LINE_READER>, "RichIO FILE_L_R" },
314  { 'R', bench_line_reader_reuse<FILE_LINE_READER>, "RichIO FILE_L_R, reused" },
315  { 'n', bench_line_reader<IFSTREAM_LINE_READER>, "std::ifstream L_R" },
316  { 'N', bench_line_reader_reuse<IFSTREAM_LINE_READER>, "std::ifstream L_R, reused" },
317  { 's', bench_string_lr, "RichIO STRING_L_R"},
318  { 'S', bench_string_lr_reuse, "RichIO STRING_L_R, reused"},
319  { 'w', bench_wxis<wxFileInputStream>, "wxFileIStream" },
320  { 'W', bench_wxis<wxFileInputStream>, "wxFileIStream, reused" },
321  { 'g', bench_wxis<wxFFileInputStream>, "wxFFileIStream" },
322  { 'G', bench_wxis_reuse<wxFFileInputStream>, "wxFFileIStream, reused" },
323  { 'b', bench_wxbis<wxFileInputStream>, "wxFileIStream. buf'd" },
324  { 'B', bench_wxbis_reuse<wxFileInputStream>, "wxFileIStream, buf'd, reused" },
325  { 'c', bench_wxbis<wxFFileInputStream>, "wxFFileIStream. buf'd" },
326  { 'C', bench_wxbis_reuse<wxFFileInputStream>, "wxFFileIStream, buf'd, reused" },
327 };
328 
329 
334 static wxString getBenchFlags()
335 {
336  wxString flags;
337 
338  for( auto& bmark : benchmarkList )
339  {
340  flags << bmark.triggerChar;
341  }
342 
343  return flags;
344 }
345 
346 
350 static wxString getBenchDescriptions()
351 {
352  wxString desc;
353 
354  for( auto& bmark : benchmarkList )
355  {
356  desc << " " << bmark.triggerChar << ": " << bmark.name << "\n";
357  }
358 
359  return desc;
360 }
361 
362 
363 BENCH_REPORT executeBenchMark( const BENCHMARK& aBenchmark, int aReps,
364  const wxFileName& aFilename )
365 {
366  BENCH_REPORT report = {};
367 
368  TIME_PT start = CLOCK::now();
369  aBenchmark.func( aFilename, aReps, report );
370  TIME_PT end = CLOCK::now();
371 
372  using std::chrono::milliseconds;
373  using std::chrono::duration_cast;
374 
375  report.benchDurMs = duration_cast<milliseconds>( end - start );
376 
377  return report;
378 }
379 
380 
381 int io_benchmark_func( int argc, char* argv[] )
382 {
383  auto& os = std::cout;
384 
385  if (argc < 3)
386  {
387  os << "Usage: " << argv[0] << " <FILE> <REPS> [" << getBenchFlags() << "]\n\n";
388  os << "Benchmarks:\n";
389  os << getBenchDescriptions();
391  }
392 
393  wxFileName inFile( argv[1] );
394 
395  long reps = 0;
396  wxString( argv[2] ).ToLong( &reps );
397 
398  // get the benchmark to do, or all of them if nothing given
399  wxString bench;
400  if ( argc == 4 )
401  bench = argv[3];
402 
403  os << "IO Bench Mark Util" << std::endl;
404 
405  os << " Benchmark file: " << inFile.GetFullPath() << std::endl;
406  os << " Repetitions: " << (int) reps << std::endl;
407  os << std::endl;
408 
409  for( auto& bmark : benchmarkList )
410  {
411  if( bench.size() && !bench.Contains( bmark.triggerChar ) )
412  continue;
413 
414  BENCH_REPORT report = executeBenchMark( bmark, reps, inFile );
415 
416  os << wxString::Format( "%-30s %u lines, acc: %u in %u ms",
417  bmark.name, report.linesRead, report.charAcc, (int) report.benchDurMs.count() )
418  << std::endl;;
419  }
420 
421  return KI_TEST::RET_CODES::OK;
422 }
423 
424 
426  "io_benchmark",
427  "Benchmark various kinds of IO methods",
429 } );
static void bench_fstream_reuse(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using a raw std::ifstream, with no LINE_READER wrapper.
static std::vector< BENCHMARK > benchmarkList
List of available benchmarks.
wxString name
char triggerChar
A LINE_READER that reads from a wxInputStream object.
Definition: richio.h:274
static void bench_string_lr(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using STRING_LINE_READER on string data read into memory from a file using std::ifstream,...
unsigned linesRead
#define OK
The command line was not correct for the tool.
std::chrono::time_point< CLOCK > TIME_PT
static void bench_wxbis_reuse(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using a INPUTSTREAM_LINE_READER with a given wxInputStream implementation,...
int io_benchmark_func(int argc, char *argv[])
std::chrono::steady_clock CLOCK
static bool registered
unsigned charAcc
Char accumulator, used to prevent compilers optimising away otherwise unused line buffers,...
std::function< void(const wxFileName &, int, BENCH_REPORT &)> BENCH_FUNC
static void bench_fstream(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using a raw std::ifstream, with no LINE_READER wrapper.
static bool Register(const KI_TEST::UTILITY_PROGRAM &aProgInfo)
Register a utility program factory function against an ID string.
std::chrono::milliseconds benchDurMs
static void bench_line_reader_reuse(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using a given LINE_READER implementation.
static wxString getBenchFlags()
Construct string of all flags used for specifying benchmarks on the command line.
static wxString getBenchDescriptions()
Usage description of a benchmakr spec.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
static void bench_wxis(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using an INPUTSTREAM_LINE_READER with a given wxInputStream implementation.
static void bench_string_lr_reuse(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using STRING_LINE_READER on string data read into memory from a file using std::ifstream.
static void bench_line_reader(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using a given LINE_READER implementation.
BENCH_FUNC func
static void bench_wxis_reuse(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using an INPUTSTREAM_LINE_READER with a given wxInputStream implementation.
static void bench_wxbis(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using a INPUTSTREAM_LINE_READER with a given wxInputStream implementation,...
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:240
BENCH_REPORT executeBenchMark(const BENCHMARK &aBenchmark, int aReps, const wxFileName &aFilename)