20 #define DOLLAR_VERSION "1.2.0" 32 inline void csv( std::ostream &cout ) {}
33 inline void tsv( std::ostream &cout ) {}
34 inline void text( std::ostream &cout ) {}
35 inline void chrome( std::ostream &cout ) {}
36 inline void markdown( std::ostream &cout ) {}
37 inline void pause(
bool paused ) {}
38 inline bool is_paused() {}
39 inline void clear() {}
66 #ifndef DOLLAR_MAX_TRACES 67 #define DOLLAR_MAX_TRACES 512 70 #ifndef DOLLAR_CPUMETER_WIDTH 71 #define DOLLAR_CPUMETER_WIDTH 10 74 #define DOLLAR_GLUE(a,b) a##b 75 #define DOLLAR_JOIN(a,b) DOLLAR_GLUE(a,b) 76 #define DOLLAR_UNIQUE(sym) DOLLAR_JOIN(sym, __LINE__) 77 #define DOLLAR_STRINGIFY(x) #x 78 #define DOLLAR_TOSTRING(x) DOLLAR_STRINGIFY(x) 81 #define DOLLAR(name) dollar::sampler DOLLAR_UNIQUE(dollar_sampler_)(name); 82 #define $ dollar::sampler DOLLAR_UNIQUE(dollar_sampler_)(std::string(__FUNCTION__) + " (" __FILE__ ":" DOLLAR_TOSTRING(__LINE__) ")" ); 84 #define DOLLAR(name) dollar::sampler DOLLAR_UNIQUE(dollar_sampler_)(name); 85 #define $ dollar::sampler DOLLAR_UNIQUE(dollar_sampler_)(std::string(__PRETTY_FUNCTION__) + " (" __FILE__ ":" DOLLAR_TOSTRING(__LINE__) ")" ); 90 template <
typename T >
91 inline T* singleton() {
96 # ifdef DOLLAR_USE_OMP 97 static auto const epoch = omp_get_wtime();
98 return omp_get_wtime() - epoch;
100 static auto const epoch = std::chrono::steady_clock::now();
101 return std::chrono::duration_cast< std::chrono::microseconds >( std::chrono::steady_clock::now() - epoch ).count() / 1000000.0;
104 inline std::vector< std::string > tokenize(
const std::string &
self,
const std::string &delimiters ) {
105 unsigned char map [256] = {};
106 for(
const unsigned char &ch : delimiters ) {
109 std::vector< std::string > tokens(1);
110 for(
const unsigned char &ch :
self ) {
111 if( !map[ch] ) tokens.back().push_back(
char(ch) );
112 else if( tokens.back().size() ) tokens.push_back( std::string() );
114 while( tokens.size() && !tokens.back().size() ) tokens.pop_back();
117 template<
typename info>
121 std::vector<Node> children;
123 Node(
const std::string &name, info *value = 0 ) : name(name), value(value)
126 void tree_printer( std::string indent,
bool leaf, std::ostream &out )
const {
128 out << indent <<
"+-" << name << std::endl;
131 out << indent <<
"|-" << name << std::endl;
134 for(
auto end = children.size(), it = end - end; it < end; ++it ) {
135 children[it].tree_printer( indent, it == (end - 1), out );
138 void tree_printer( std::ostream &out = std::cout )
const {
139 tree_printer(
"",
true, out );
141 Node&tree_recreate_branch(
const std::vector<std::string> &names ) {
142 auto *where = &(*this);
143 for(
auto &name : names ) {
145 for(
auto &it : where->children ) {
146 if( it.name == name ) {
153 where->children.push_back(
Node(name) );
154 where = &where->children.back();
159 template<
typename FN0,
typename FN1,
typename FN2>
160 void tree_walker(
const FN0 &method,
const FN1 &pre_children,
const FN2 &post_chilren )
const {
161 if( children.empty() ) {
164 pre_children( *
this );
165 for(
auto &child : children ) {
166 child.tree_walker( method, pre_children, post_chilren );
168 post_chilren( *
this );
174 std::vector<std::string> stack;
182 double current = 0, total = 0;
194 info(
const std::string &title ) : title(title)
198 std::ostream &operator<<( std::ostream &os,
const info &k ) {
199 os <<
"title:" << tokenize(k.title,
";").back() << std::endl;
200 os <<
"paused:" << k.paused << std::endl;
201 os <<
"hits:" << k.hits << std::endl;
202 os <<
"current:" << k.current << std::endl;
203 os <<
"total:" << k.total << std::endl;
204 os <<
"pid:" << k.pid << std::endl;
205 os <<
"tid:" << k.tid << std::endl;
211 stack.reserve( DOLLAR_MAX_TRACES );
214 info &in(
const std::string &title ) {
216 auto pid = _getpid();
220 auto tid = std::this_thread::get_id();
225 stack.push_back( stack.empty() ? title : stack.back() +
";" + title );
227 auto &
id = stack.back();
229 if( counters.find(
id ) == counters.end() ) {
230 counters[ id ] =
info ( stack.back() );
233 auto &sample = counters[ id ];
236 sample.current = -dollar::now();
244 void out(
info &sample ) {
245 sample.current += dollar::now();
246 sample.total += ( sample.paused ? 0.f : sample.current );
250 template<
bool for_chrome>
251 void print( std::ostream &out,
const char *tab =
",",
const char *feed =
"\r\n" )
const {
252 auto inital_matches = [](
const std::string &text,
const std::string &abc ) ->
unsigned {
254 for(
auto end = (std::min)(text.size(), abc.size()), it = end - end; it < end; ++it, ++c ) {
255 if( text[it] != abc[it] )
break;
259 auto starts_with = [&](
const std::string &text,
const std::string &abc ) ->
bool {
260 return inital_matches( text, abc ) == abc.size();
267 while( !copy.stack.empty() ) {
268 auto ¤t = copy.counters[ stack.back() ];
275 std::vector< std::pair<std::string, info *> > az_tree;
277 for(
auto &it : copy.counters ) {
278 auto &
info = it.second;
279 az_tree.emplace_back(
info.title, &
info );
282 std::sort( az_tree.begin(), az_tree.end() );
283 std::reverse( az_tree.begin(), az_tree.end() );
286 for(
size_t i = 0; i < az_tree.size(); ++i ) {
287 for(
size_t j = i + 1; j < az_tree.size(); ++j ) {
288 if( starts_with( az_tree[ i ].first, az_tree[ j ].first ) ) {
289 az_tree[ j ].second->total -= az_tree[ i ].second->total;
297 for(
auto &it : copy.counters ) {
298 total += it.second.total;
301 std::vector<std::string> list;
304 static unsigned char pos = 0;
308 dummy.pid = _getpid();
310 dummy.pid = getpid();
312 dummy.tid = std::this_thread::get_id();
313 Node<info> root( std::string() +
"\\|/-"[(++pos)%4], &dummy );
314 for(
auto it = copy.counters.begin(), end = copy.counters.end(); it != end; ++it ) {
315 auto &
info = it->second;
316 list.push_back(
info.title );
318 auto split = tokenize(
info.title,
";" );
320 auto &node = root.tree_recreate_branch( split );
323 std::stringstream ss;
324 root.tree_printer( ss );
325 list = tokenize( ss.str(),
"\r\n" );
326 static size_t maxlen = 0;
327 for(
auto &it : list ) {
328 maxlen = (std::max)(maxlen, it.size());
330 for(
auto &it : list ) {
331 if( maxlen > it.size() ) it += std::string( maxlen - it.size(),
' ' );
332 else if( maxlen < it.size() ) it.resize( maxlen );
339 for(
auto &cp : copy.counters ) {
340 cp.second.title = tokenize( cp.second.title,
";" ).back();
341 for(
auto &ch : cp.second.title ) {
342 if( ch ==
'\\' ) ch =
'/';
347 for(
auto &cp : copy.counters ) {
348 cp.second.title = list[++x];
349 for(
auto &ch : cp.second.title ) {
350 if( ch ==
'\\' ) ch =
'/';
356 std::string format, sep, graph, buffer(1024,
'\0');
358 for(
auto &it : std::vector<std::string>{
"%4d.",
"%s",
"[%s]",
"%5.2f%% CPU",
"(%9.3fms)",
"%5d hits",feed } ) {
363 for(
auto &it : copy.counters ) {
364 auto &
info = it.second;
365 double cpu =
info.total * 100.0 / total;
366 int width(cpu*DOLLAR_CPUMETER_WIDTH/100);
367 graph = std::string( width,
'=' ) + std::string( DOLLAR_CPUMETER_WIDTH - width,
'.' );
369 sprintf_s( &buffer[0], 1024,
373 format.c_str(), ++i, it.second.title.c_str(), graph.c_str(), cpu, (float)(
info.total * 1000),
info.hits );
379 out <<
"[" << std::endl;
385 auto get_color = [](
float pct ) {
386 return pct <= 16 ?
"good":
391 double timestamp = 0;
394 auto &
info = *node.value;
395 double cpu =
info.total * 100.0 / total;
396 out <<
"{\"name\": \"" <<
info.title <<
"\"," 397 "\"cat\": \"" <<
"CPU,DOLLAR" <<
"\"," 398 "\"ph\": \"" <<
'X' <<
"\"," 399 "\"pid\": " <<
info.pid <<
"," 400 "\"tid\": " <<
info.tid <<
"," 401 "\"ts\": " << (
unsigned int)(timestamp * 1000 * 1000) <<
"," 402 "\"dur\": " << (
unsigned int)(
info.total * 1000 * 1000) <<
"," 403 "\"cname\": \"" << get_color(cpu) <<
"\"" "," <<
405 timestamp +=
info.total;
408 auto &
info = *node.value;
409 double cpu =
info.total * 100.0 / total;
410 out <<
"{\"name\": \"" <<
info.title <<
"\"," 411 "\"cat\": \"" <<
"CPU,DOLLAR" <<
"\"," 412 "\"ph\": \"" <<
'B' <<
"\"," 413 "\"pid\": " <<
info.pid <<
"," 414 "\"tid\": " <<
info.tid <<
"," 415 "\"ts\": " << (
unsigned int)(timestamp * 1000 * 1000) <<
"," 417 timestamp +=
info.total;
420 auto &
info = *node.value;
421 double cpu =
info.total * 100.0 / total;
422 out <<
"{\"name\": \"" <<
info.title <<
"\"," 423 "\"cat\": \"" <<
"CPU,DOLLAR" <<
"\"," 424 "\"ph\": \"" <<
'E' <<
"\"," 425 "\"pid\": " <<
info.pid <<
"," 426 "\"tid\": " <<
info.tid <<
"," 427 "\"ts\": " << (
unsigned int)((timestamp +
info.total) * 1000 * 1000) <<
"," 428 "\"cname\": \"" << get_color(cpu) <<
"\"" "," <<
430 timestamp +=
info.total;
435 void pause(
bool paused_ ) {
439 bool is_paused()
const {
445 auto num_unfinished_scopes = stack.size();
447 stack.resize( num_unfinished_scopes );
451 private: std::map< std::string, info > counters;
462 explicit sampler(
const std::string &title ) {
463 handle = &singleton<profiler>()->in( title );
467 singleton<profiler>()->out( *handle );
471 inline void csv( std::ostream &os ) {
472 singleton<profiler>()->print<0>(os,
",");
475 inline void tsv( std::ostream &os ) {
476 singleton<profiler>()->print<0>(os,
"\t");
479 inline void markdown( std::ostream &os ) {
480 singleton<profiler>()->print<0>(os,
"|");
483 inline void text( std::ostream &os ) {
484 singleton<profiler>()->print<0>(os,
" ");
487 inline void chrome( std::ostream &os ) {
488 singleton<profiler>()->print<1>(os,
"");
491 inline void pause(
bool paused ) {
492 singleton<profiler>()->pause( paused );
495 inline bool is_paused() {
496 return singleton<profiler>()->is_paused();
499 inline void clear() {
500 singleton<profiler>()->clear();
506 #ifdef DOLLAR_BUILD_DEMO 512 void x(
int counter ) { $
513 while( counter-- > 0 ) { $
514 std::this_thread::sleep_for( std::chrono::microseconds(
int(0.00125 * 1000000) ) );
517 void c(
int counter ) { $
518 while( counter-- > 0 ) { $
519 std::this_thread::sleep_for( std::chrono::microseconds(
int(0.00125 * 1000000) ) );
522 void y(
int counter ) { $
523 while( counter-- > 0 ) { $
524 std::this_thread::sleep_for( std::chrono::microseconds(
int(0.00125 * 1000000) ) );
525 if( counter % 2 ) c(counter);
else x(counter);
528 void a(
int counter ) { $
529 while( counter-- > 0 ) { $
530 std::this_thread::sleep_for( std::chrono::microseconds(
int(0.00125 * 1000000) ) );
539 std::ofstream file(
"chrome.json");
540 dollar::chrome(file);
543 dollar::text(std::cout);
Definition: dollar.hpp:87
Definition: dollar.hpp:178
Definition: dollar.hpp:453
Definition: dollar.hpp:171
Definition: dollar.hpp:117