Skip to content

Commit 7c187a7

Browse files
committed
add benchmarking code for linux; needs implemented on WIN32, OSX
* 'getMemAndTime()' can be used from C or C++ * 'benchmark' class calculates a delta for phys/virt memory and user/sys cpu time. Uses getMemAndTime() internally.
1 parent ad2675f commit 7c187a7

File tree

4 files changed

+205
-8
lines changed

4 files changed

+205
-8
lines changed

src/base/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ set(SCL_BASE_SOURCES
33
scl_memmgr.cc
44
scl_trace_fprintf.c
55
sc_getopt.cc
6+
sc_benchmark.cc
67
)
78

89
if(MSVC OR BORLAND)

src/base/sc_benchmark.cc

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/// \file sc_benchmark.cc memory info, timers, etc for benchmarking
2+
3+
#include "sc_benchmark.h"
4+
5+
#ifdef __WIN32
6+
#include <Windows.h>
7+
#else
8+
#include <sys/time.h>
9+
#include <ctime>
10+
#include <unistd.h>
11+
#endif
12+
13+
#include <iostream>
14+
#include <fstream>
15+
#include <iomanip>
16+
#include <string>
17+
#include <sstream>
18+
19+
/// mem values in kb, times in ms (granularity may be higher than 1ms)
20+
benchVals getMemAndTime( ) {
21+
benchVals vals;
22+
#ifdef __linux__
23+
// adapted from http://stackoverflow.com/questions/669438/how-to-get-memory-usage-at-run-time-in-c
24+
std::ifstream stat_stream("/proc/self/stat",std::ios_base::in);
25+
26+
// dummy vars for leading entries in stat that we don't care about
27+
std::string pid, comm, state, ppid, pgrp, session, tty_nr;
28+
std::string tpgid, flags, minflt, cminflt, majflt, cmajflt;
29+
std::string /*utime, stime,*/ cutime, cstime, priority, nice;
30+
std::string O, itrealvalue, starttime;
31+
32+
// the fields we want
33+
unsigned long utime, stime, vsize;
34+
long rss;
35+
36+
stat_stream >> pid >> comm >> state >> ppid >> pgrp >> session >> tty_nr
37+
>> tpgid >> flags >> minflt >> cminflt >> majflt >> cmajflt
38+
>> utime >> stime >> cutime >> cstime >> priority >> nice
39+
>> O >> itrealvalue >> starttime >> vsize >> rss; // don't care about the rest
40+
41+
long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages
42+
vals.physMemKB = rss * page_size_kb;
43+
vals.virtMemKB = ( vsize / 1024 ) - vals.physMemKB;
44+
vals.userMilliseconds = ( utime * 1000 ) / sysconf(_SC_CLK_TCK);
45+
vals.sysMilliseconds = ( stime * 1000 ) / sysconf(_SC_CLK_TCK);
46+
#elif defined(__APPLE__)
47+
// http://stackoverflow.com/a/1911863/382458
48+
#elif defined(__WIN32)
49+
// http://stackoverflow.com/a/282220/382458 and http://stackoverflow.com/a/64166/382458
50+
#else
51+
#warning Unknown platform!
52+
#endif // __linux__
53+
return vals;
54+
}
55+
56+
// --------------------- benchmark class ---------------------
57+
58+
benchmark::benchmark( std::string description, bool debugMessages, std::ostream& o_stream ): ostr( o_stream ),
59+
descr( description ), debug( debugMessages ), stopped( false ) {
60+
initialVals = getMemAndTime( );
61+
}
62+
63+
benchmark::~benchmark() {
64+
if( !stopped ) {
65+
stop( );
66+
if( debug ) {
67+
ostr << "benchmark::~benchmark(): stop was not called before destructor!" << std::endl;
68+
}
69+
out( );
70+
}
71+
}
72+
73+
void benchmark::stop( ) {
74+
if( stopped ) {
75+
std::cerr << "benchmark::stop(): tried to stop a benchmark that was already stopped!" << std::endl;
76+
} else {
77+
laterVals = getMemAndTime( );
78+
stopped = true;
79+
}
80+
}
81+
82+
benchVals benchmark::get( ) {
83+
if( !stopped ) {
84+
laterVals = getMemAndTime( );
85+
}
86+
benchVals delta;
87+
delta.physMemKB = laterVals.physMemKB - initialVals.physMemKB;
88+
delta.virtMemKB = laterVals.virtMemKB - initialVals.virtMemKB;
89+
delta.sysMilliseconds = laterVals.sysMilliseconds - initialVals.sysMilliseconds;
90+
delta.userMilliseconds = laterVals.userMilliseconds - initialVals.userMilliseconds;
91+
return delta;
92+
}
93+
94+
void benchmark::reset( ) {
95+
stopped = false;
96+
initialVals = getMemAndTime();
97+
}
98+
99+
std::string benchmark::str( ) {
100+
return str( get( ) );
101+
}
102+
103+
void benchmark::out() {
104+
ostr << str( ) << std::endl;
105+
}
106+
107+
std::string benchmark::str( const benchVals& bv ) {
108+
std::stringstream ss;
109+
ss << descr << " Physical memory: " << bv.physMemKB << "kb; Virtual memory: " << bv.virtMemKB;
110+
ss << "kb; User CPU time: " << bv.userMilliseconds << "ms; System CPU time: " << bv.sysMilliseconds << "ms";
111+
return ss.str();
112+
}
113+

src/base/sc_benchmark.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#ifndef SC_BENCHMARK_H
2+
#define SC_BENCHMARK_H
3+
/// \file sc_benchmark.h memory info, timers, etc for benchmarking
4+
5+
#include "scl_export.h"
6+
7+
#ifdef __cplusplus
8+
#include <iostream>
9+
#include <string>
10+
11+
extern "C" {
12+
#endif
13+
14+
typedef struct {
15+
long virtMemKB, physMemKB, userMilliseconds, sysMilliseconds;
16+
} benchVals;
17+
18+
/** return a benchVals struct with four current statistics for this process:
19+
* virtual and physical memory use in kb,
20+
* user and system cpu time in ms
21+
*
22+
* not yet implemented for OSX or Windows.
23+
*/
24+
SCL_BASE_EXPORT benchVals getMemAndTime( );
25+
26+
#ifdef __cplusplus
27+
}
28+
29+
30+
/** reports the difference in memory and cpu use between when the
31+
* constructor is called and when stop() or the destructor is called.
32+
*
33+
* if the destructor is called and stop() had not previously been
34+
* called, the results are printed to the ostream given in the
35+
* constructor, prefixed by the description.
36+
*
37+
* depends on getMemAndTime() above - may not work on all platforms.
38+
*/
39+
SCL_BASE_EXPORT class benchmark {
40+
protected:
41+
benchVals initialVals, laterVals;
42+
std::ostream& ostr;
43+
std::string descr;
44+
bool debug, stopped;
45+
public:
46+
benchmark( std::string description = "", bool debugMessages = true, std::ostream& o_stream = std::cout );
47+
48+
/// if 'stopped' is false, uses str(true) to print to ostream
49+
~benchmark( );
50+
void reset( );
51+
benchVals get( );
52+
void stop( );
53+
54+
/// converts data member 'laterVals' into a string and returns it
55+
std::string str( );
56+
57+
/// outputs result of str() on ostream 'ostr'
58+
void out( );
59+
60+
/// converts 'bv' into a string, prefixed by data member 'descr'
61+
std::string str( const benchVals& bv );
62+
};
63+
64+
65+
#endif //__cplusplus
66+
#endif //SC_BENCHMARK_H

src/test/p21read/p21read.cc

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ extern void SchemaInit( class Registry & );
2222
#include <errordesc.h>
2323
#include <algorithm>
2424
#include <string>
25+
#include "sc_benchmark.h"
2526
#ifdef HAVE_UNISTD_H
2627
# include <unistd.h>
2728
#endif
@@ -97,6 +98,7 @@ void printUse( const char * exe ) {
9798
std::cout << "p21read - read a STEP Part 21 exchange file using SCL, and write the data to another file." << std::endl;
9899
std::cout << "Syntax: " << exe << " [-i] [-s] infile [outfile]" << std::endl;
99100
std::cout << "Use '-i' to ignore a schema name mismatch." << std::endl;
101+
std::cout << "Use '-m' to turn off memory info." << std::endl;
100102
std::cout << "Use '-s' for strict interpretation (attributes that are \"missing and required\" will cause errors)." << std::endl;
101103
std::cout << "Use '-v' to print the version info below and exit." << std::endl;
102104
std::cout << "Use '--' as the last argument if a file name starts with a dash." << std::endl;
@@ -107,15 +109,21 @@ void printUse( const char * exe ) {
107109
int main( int argc, char * argv[] ) {
108110
bool ignoreErr = false;
109111
bool strict = false;
112+
bool memInfo = true;
110113
char c;
114+
double physMem, virtMem, preReadPhysMem, preReadVirtMem; //for memory monitoring
115+
111116
if( argc > 4 || argc < 2 ) {
112117
printUse( argv[0] );
113118
}
114-
while( ( c = sc_getopt( argc, argv, "isv" ) ) != -1 ) {
119+
while( ( c = sc_getopt( argc, argv, "imsv" ) ) != -1 ) {
115120
switch( c ) {
116121
case 'i':
117122
ignoreErr = true;
118123
break;
124+
case 'm':
125+
memInfo = false;
126+
break;
119127
case 's':
120128
strict = true;
121129
break;
@@ -128,7 +136,6 @@ int main( int argc, char * argv[] ) {
128136
}
129137
}
130138

131-
132139
///////////////////////////////////////////////////////////////////////////////
133140
// You have to initialize the schema before you do anything else.
134141
// This initializes all of the registry information for the schema you
@@ -142,31 +149,41 @@ int main( int argc, char * argv[] ) {
142149
STEPfile sfile( registry, instance_list, "", strict );
143150
char * flnm;
144151

145-
cout << "\nEXAMPLE : load file ..." << endl;
152+
benchmark stats( "p21 ReadExchangeFile()" );
153+
154+
cout << argv[0] << ": load file ..." << endl;
146155
if( argc >= ( optind + 1 ) ) {
147156
flnm = argv[optind];
148157
} else {
149158
flnm = ( char * )"testfile.step";
150159
}
151160
sfile.ReadExchangeFile( flnm );
152-
sfile.Error().PrintContents( cout );
161+
if( sfile.Error().severity() < SEVERITY_USERMSG ) {
162+
sfile.Error().PrintContents( cout );
163+
}
164+
165+
stats.stop();
166+
stats.out( );
153167

154-
if ( sfile.Error().severity() <= SEVERITY_INCOMPLETE )
168+
if ( sfile.Error().severity() <= SEVERITY_INCOMPLETE ) {
155169
exit(1);
170+
}
156171

157172
checkSchemaName( registry, sfile, ignoreErr );
158173

159174
Severity readSev = sfile.Error().severity(); //otherwise, errors from reading will be wiped out by sfile.WriteExchangeFile()
160175

161-
cout << "EXAMPLE : write file ..." << endl;
176+
cout << argv[0] << ": write file ..." << endl;
162177
if( argc == optind + 2 ) {
163178
flnm = argv[optind + 1];
164179
} else {
165180
flnm = ( char * )"file.out";
166181
}
167182
sfile.WriteExchangeFile( flnm );
168-
sfile.Error().PrintContents( cout );
169-
cout << flnm << " written" << endl;
183+
if( sfile.Error().severity() < SEVERITY_USERMSG ) {
184+
sfile.Error().PrintContents( cout );
185+
}
186+
cout << argv[0] << ": " << flnm << " written" << endl;
170187

171188
if( ( sfile.Error().severity() <= SEVERITY_INCOMPLETE ) || ( readSev <= SEVERITY_INCOMPLETE ) ) { //lower is worse
172189
exit( 1 );

0 commit comments

Comments
 (0)