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
41using CLOCK = std::chrono::steady_clock;
42using 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
60using BENCH_FUNC = std::function<void(const wxFileName&, int, BENCH_REPORT&)>;
61
62
64{
67 wxString name;
68};
69
70
75static 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
98static 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
122template<typename LR>
123static 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
141template<typename LR>
142static 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
163static 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
188static 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
211template<typename S>
212static 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
236template<typename S>
237static 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
260template<typename WXIS>
261static 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
286template<typename WXIS>
287static 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
309static 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
334static 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
350static 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
363BENCH_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
381int 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
422}
423
424
426 "io_benchmark",
427 "Benchmark various kinds of IO methods",
429} );
A LINE_READER that reads from a wxInputStream object.
Definition: richio.h:275
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:315
char * Line() const
Return a pointer to the last line that was read in.
Definition: richio.h:117
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:241
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:276
static bool Register(const KI_TEST::UTILITY_PROGRAM &aProgInfo)
Register a utility program factory function against an ID string.
#define OK
static void bench_fstream_reuse(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using a raw std::ifstream, with no LINE_READER wrapper.
int io_benchmark_func(int argc, char *argv[])
static void bench_line_reader(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using a given LINE_READER implementation.
static bool registered
static wxString getBenchFlags()
Construct string of all flags used for specifying benchmarks on the command line.
BENCH_REPORT executeBenchMark(const BENCHMARK &aBenchmark, int aReps, const wxFileName &aFilename)
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_line_reader_reuse(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using a given LINE_READER implementation.
std::function< void(const wxFileName &, int, BENCH_REPORT &)> BENCH_FUNC
static void bench_wxbis(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using a 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_wxbis_reuse(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using a INPUTSTREAM_LINE_READER with a given wxInputStream implementation,...
std::chrono::time_point< CLOCK > TIME_PT
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,...
std::chrono::steady_clock CLOCK
static void bench_fstream(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.
static void bench_wxis(const wxFileName &aFile, int aReps, BENCH_REPORT &report)
Benchmark using an INPUTSTREAM_LINE_READER with a given wxInputStream implementation.
static wxString getBenchDescriptions()
Usage description of a benchmakr spec.
@ BAD_CMDLINE
The command line was not correct for the tool.
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
BENCH_FUNC func
char triggerChar
wxString name
unsigned charAcc
Char accumulator, used to prevent compilers optimising away otherwise unused line buffers,...
std::chrono::milliseconds benchDurMs
unsigned linesRead