diff --git a/csvexport/src/csvexport.cpp b/csvexport/src/csvexport.cpp index 3464db6d..0a0ad308 100644 --- a/csvexport/src/csvexport.cpp +++ b/csvexport/src/csvexport.cpp @@ -3,45 +3,47 @@ #endif #include -#include -#include -#include #include #include +#include +#include #include -#include #include +#include +#include -#include "../../server/TracyFileRead.hpp" -#include "../../server/TracyWorker.hpp" #include "../../getopt/getopt.h" #include "../../public/common/TracyVersion.hpp" +#include "../../server/TracyFileRead.hpp" +#include "../../server/TracyWorker.hpp" #include "GitRef.hpp" -void print_usage_exit(int e) +static void print_usage_exit( int e ) { - fprintf(stderr, "tracy-csvexport %i.%i.%i / %s\n\n", tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch, tracy::GitRef); - fprintf(stderr, "Extract statistics from a trace to a CSV format\n"); - fprintf(stderr, "Usage:\n"); - fprintf(stderr, " extract [OPTION...] \n"); - fprintf(stderr, "\n"); - fprintf(stderr, " -h, --help Print usage\n"); - fprintf(stderr, " -V, --version Show version information\n"); - fprintf(stderr, " -f, --filter arg Filter zone names (default: "")\n"); - fprintf(stderr, " -s, --sep arg CSV separator (default: ,)\n"); - fprintf(stderr, " -c, --case Case sensitive filtering\n"); - fprintf(stderr, " -e, --self Get self times\n"); - fprintf(stderr, " -u, --unwrap Report each cpu zone event\n"); - fprintf(stderr, " -g, --gpu Report each gpu zone event\n" ); - fprintf(stderr, " -m, --messages Report only messages\n"); - fprintf(stderr, " -p, --plot Report plot data (only with -u)\n"); - fprintf(stderr, " -t, --truncated_mean[=arg] Report truncated mean (arg is the percentile. Default is 90)\n"); + fprintf( stderr, "tracy-csvexport %i.%i.%i / %s\n\n", tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch, tracy::GitRef ); + fprintf( stderr, "Extract statistics from a trace to a CSV format\n" ); + fprintf( stderr, "Usage:\n" ); + fprintf( stderr, " extract [OPTION...] \n" ); + fprintf( stderr, "\n" ); + fprintf( stderr, " -h, --help Print usage\n" ); + fprintf( stderr, " -V, --version Show version information\n" ); + fprintf( stderr, " -f, --filter arg Filter zone names (default: " + ")\n" ); + fprintf( stderr, " -s, --sep arg CSV separator (default: ,)\n" ); + fprintf( stderr, " -c, --case Case sensitive filtering\n" ); + fprintf( stderr, " -e, --self Get self times\n" ); + fprintf( stderr, " -u, --unwrap Report each cpu zone event\n" ); + fprintf( stderr, " -g, --gpu Report each gpu zone event\n" ); + fprintf( stderr, " -m, --messages Report only messages\n" ); + fprintf( stderr, " -p, --plot Report plot data (only with -u)\n" ); + fprintf( stderr, " -t, --truncated_mean[=arg] Report truncated mean (arg is the percentile. Default is 90)\n" ); - exit(e); + exit( e ); } -struct Args { +struct Args +{ const char* filter; const char* separator; const char* trace_file; @@ -54,37 +56,34 @@ struct Args { int truncated_mean_percentile; }; -Args parse_args(int argc, char** argv) +static Args parse_args( int argc, char** argv ) { - if (argc == 1) - { - print_usage_exit(1); - } + if( argc == 1 ) print_usage_exit( 1 ); - Args args = { "", ",", "", false, false, false, false, false, false, 0}; + Args args = { "", ",", "", false, false, false, false, false, false, 0 }; struct option long_opts[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { "filter", required_argument, NULL, 'f' }, - { "sep", required_argument, NULL, 's' }, - { "case", no_argument, NULL, 'c' }, - { "self", no_argument, NULL, 'e' }, - { "unwrap", no_argument, NULL, 'u' }, - { "gpu", no_argument, NULL, 'g' }, - { "messages", no_argument, NULL, 'm' }, - { "plot", no_argument, NULL, 'p' }, - { "truncated_mean", optional_argument, NULL, 't' }, - { NULL, 0, NULL, 0 } + { "help", no_argument, nullptr, 'h' }, + { "version", no_argument, nullptr, 'V' }, + { "filter", required_argument, nullptr, 'f' }, + { "sep", required_argument, nullptr, 's' }, + { "case", no_argument, nullptr, 'c' }, + { "self", no_argument, nullptr, 'e' }, + { "unwrap", no_argument, nullptr, 'u' }, + { "gpu", no_argument, nullptr, 'g' }, + { "messages", no_argument, nullptr, 'm' }, + { "plot", no_argument, nullptr, 'p' }, + { "truncated_mean", optional_argument, nullptr, 't' }, + { nullptr, 0, nullptr, 0 } }; int c; - while ((c = getopt_long(argc, argv, "hf:s:t:ceugmpV", long_opts, NULL)) != -1) + while( ( c = getopt_long( argc, argv, "hf:s:t:ceugmpV", long_opts, nullptr ) ) != -1 ) { - switch (c) + switch( c ) { case 'h': - print_usage_exit(0); + print_usage_exit( 0 ); break; case 'V': printf( "tracy-csvexport %i.%i.%i / %s\n", tracy::Version::Major, tracy::Version::Minor, tracy::Version::Patch, tracy::GitRef ); @@ -114,17 +113,17 @@ Args parse_args(int argc, char** argv) args.plot = true; break; case 't': - args.truncated_mean_percentile = std::clamp(optarg ? std::atoi(optarg) : 90, 1, 99); + args.truncated_mean_percentile = std::clamp( optarg ? atoi( optarg ) : 90, 1, 99 ); break; default: - print_usage_exit(1); + print_usage_exit( 1 ); break; } } - if (argc != optind + 1) + if( argc != optind + 1 ) { - print_usage_exit(1); + print_usage_exit( 1 ); } args.trace_file = argv[optind]; @@ -132,44 +131,34 @@ Args parse_args(int argc, char** argv) return args; } -bool is_substring( - const char* term, - const char* s, - bool case_sensitive = false -){ - auto new_term = std::string(term); - auto new_s = std::string(s); +static bool is_substring( const char* term, const char* s, bool case_sensitive = false ) +{ + auto new_term = std::string( term ); + auto new_s = std::string( s ); - if (!case_sensitive) { - std::transform( - new_term.begin(), - new_term.end(), - new_term.begin(), - [](unsigned char c){ return std::tolower(c); } - ); - - std::transform( - new_s.begin(), - new_s.end(), - new_s.begin(), - [](unsigned char c){ return std::tolower(c); } - ); + if( !case_sensitive ) + { + std::ranges::transform( new_term, new_term.begin(), []( unsigned char c ) { return tolower( c ); } ); + std::ranges::transform( new_s, new_s.begin(), []( unsigned char c ) { return tolower( c ); } ); } - return new_s.find(new_term) != std::string::npos; + return new_s.find( new_term ) != std::string::npos; } -const char* get_name(int32_t id, const tracy::Worker& worker) +static const char* get_name( int32_t id, const tracy::Worker& worker ) { - auto& srcloc = worker.GetSourceLocation(id); - return worker.GetString(srcloc.name.active ? srcloc.name : srcloc.function); + auto& srcloc = worker.GetSourceLocation( id ); + return worker.GetString( srcloc.name.active ? srcloc.name : srcloc.function ); } -template -std::string join(const T& v, const char* sep) { +template +static std::string join( const T& v, const char* sep ) +{ std::ostringstream s; - for (const auto& i : v) { - if (&i != &v[0]) { + for( const auto& i : v ) + { + if( &i != &v[0] ) + { s << sep; } s << i; @@ -178,57 +167,55 @@ std::string join(const T& v, const char* sep) { } // Returns {pN, truncated_mean} -std::pair percentile_and_truncated_mean(std::vector& data, const double p) +static std::pair percentile_and_truncated_mean( std::vector& data, const double p ) { - assert(p >= 0.0 && p <= 1.0); + assert( p >= 0.0 && p <= 1.0 ); - if (data.empty()) { - return {0, 0}; - } - - std::sort(data.begin(), data.end()); + if( data.empty() ) return { 0, 0 }; + std::ranges::sort( data ); const std::size_t n = data.size(); - const double idx = p * (static_cast(n) - 1.0); - const std::size_t idxLow = static_cast(std::floor(idx)); - const std::size_t idxHigh = std::min(idxLow + 1, n - 1); - const double frac = idx - static_cast(idxLow); + const double idx = p * ( static_cast( n ) - 1.0 ); + const std::size_t idxLow = static_cast( floor( idx ) ); + const std::size_t idxHigh = std::min( idxLow + 1, n - 1 ); + const double frac = idx - static_cast( idxLow ); - const double low = static_cast(data[idxLow]); - const double high = static_cast(data[idxHigh]); + const double low = static_cast( data[idxLow] ); + const double high = static_cast( data[idxHigh] ); // percentile value - const double pval_double = low + (high - low) * frac; - const int64_t pval_int = static_cast(std::llround(pval_double)); + const double pval_double = low + ( high - low ) * frac; + const int64_t pval_int = static_cast( llround( pval_double ) ); // Compute truncated mean: average of all values <= pval_double int64_t sum = 0; std::size_t count = 0; - for (std::size_t i = 0; i < n; ++i) { - if (static_cast(data[i]) <= pval_double) { + for( std::size_t i = 0; i < n; ++i ) + { + if( static_cast( data[i] ) <= pval_double ) + { sum += data[i]; ++count; - } else { + } + else + { break; // sorted, so we can stop once we hit > pval_double } } - if (count == 0) { + if( count == 0 ) + { // should not happen for p in [0,1] unless data empty, but keep defensive behaviour - return {pval_int, 0}; + return { pval_int, 0 }; } const int64_t truncated_mean = sum / count; - - return {pval_int, truncated_mean}; + return { pval_int, truncated_mean }; } - // From TracyView.cpp -int64_t GetZoneChildTimeFast( - const tracy::Worker& worker, - const tracy::ZoneEvent& zone -){ +static int64_t GetZoneChildTimeFast( const tracy::Worker& worker, const tracy::ZoneEvent& zone ) +{ int64_t time = 0; if( zone.HasChildren() ) { @@ -254,86 +241,84 @@ int64_t GetZoneChildTimeFast( return time; } -int main(int argc, char** argv) +int main( int argc, char** argv ) { #ifdef _WIN32 - if (!AttachConsole(ATTACH_PARENT_PROCESS)) + if( !AttachConsole( ATTACH_PARENT_PROCESS ) ) { AllocConsole(); - SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), 0x07); + SetConsoleMode( GetStdHandle( STD_OUTPUT_HANDLE ), 0x07 ); } #endif - Args args = parse_args(argc, argv); + Args args = parse_args( argc, argv ); - auto f = std::unique_ptr( - tracy::FileRead::Open(args.trace_file) - ); - if (!f) + auto f = std::unique_ptr( tracy::FileRead::Open( args.trace_file ) ); + if( !f ) { - fprintf(stderr, "Could not open file %s\n", args.trace_file); + fprintf( stderr, "Could not open file %s\n", args.trace_file ); return 1; } - auto worker = tracy::Worker(*f); + auto worker = tracy::Worker( *f ); - if (args.unwrapMessages) + if( args.unwrapMessages ) { const auto& msgs = worker.GetMessages(); - - if (msgs.size() > 0) + + if( !msgs.empty() ) { - std::vector columnsForMessages; - columnsForMessages = { - "MessageName", "total_ns" - }; - std::string headerForMessages = join(columnsForMessages, args.separator); - printf("%s\n", headerForMessages.data()); + std::vector columnsForMessages { + "MessageName", + "total_ns" + }; + std::string headerForMessages = join( columnsForMessages, args.separator ); + printf( "%s\n", headerForMessages.data() ); - for(auto& it : msgs) + for( auto& it : msgs ) { - std::vector values(columnsForMessages.size()); + std::vector values( columnsForMessages.size() ); - values[0] = worker.GetString(it->ref); - values[1] = std::to_string(it->time); + values[0] = worker.GetString( it->ref ); + values[1] = std::to_string( it->time ); - std::string row = join(values, args.separator); - printf("%s\n", row.data()); + std::string row = join( values, args.separator ); + printf( "%s\n", row.data() ); } } else { - printf("There are currently no messages!\n"); + printf( "There are currently no messages!\n" ); } - + return 0; } - while (!worker.AreSourceLocationZonesReady()) + while( !worker.AreSourceLocationZonesReady() ) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); } - if (args.show_gpu) + if( args.show_gpu ) { auto& gpu_slz = worker.GetGpuSourceLocationZones(); tracy::Vector gpu_slz_selected; gpu_slz_selected.reserve( gpu_slz.size() ); uint32_t total_cnt = 0; - for (auto it = gpu_slz.begin(); it != gpu_slz.end(); ++it) + for( auto it = gpu_slz.begin(); it != gpu_slz.end(); ++it ) { - if (it->second.total != 0) + if( it->second.total != 0 ) { ++total_cnt; - if (args.filter[0] == '\0') + if( args.filter[0] == '\0' ) { gpu_slz_selected.push_back_no_space_check( it ); } else { auto name = get_name( it->first, worker ); - if (is_substring( args.filter, name, args.case_sensitive)) + if( is_substring( args.filter, name, args.case_sensitive ) ) { gpu_slz_selected.push_back_no_space_check( it ); } @@ -341,14 +326,18 @@ int main(int argc, char** argv) } } - std::vector columns; - columns = {"name", "src_file", "Time from start of program", "GPU execution time"}; + std::vector columns { + "name", + "src_file", + "Time from start of program", + "GPU execution time" + }; - std::string header = join(columns, args.separator); - printf("%s\n", header.data()); + std::string header = join( columns, args.separator ); + printf( "%s\n", header.data() ); const auto last_time = worker.GetLastTime(); - for (auto& it : gpu_slz_selected) + for( auto& it : gpu_slz_selected ) { std::vector values( columns.size() ); @@ -358,7 +347,7 @@ int main(int argc, char** argv) values[1] = worker.GetString( srcloc.file ); const auto& zone_data = it->second; - for (const auto& zone_thread_data : zone_data.zones) + for( const auto& zone_thread_data : zone_data.zones ) { tracy::GpuEvent* gpu_event = zone_thread_data.Zone(); const auto start = gpu_event->GpuStart(); @@ -377,165 +366,157 @@ int main(int argc, char** argv) } auto& slz = worker.GetSourceLocationZones(); - tracy::Vector slz_selected; - slz_selected.reserve(slz.size()); + tracy::Vector slz_selected; + slz_selected.reserve( slz.size() ); uint32_t total_cnt = 0; - for(auto it = slz.begin(); it != slz.end(); ++it) + for( auto it = slz.begin(); it != slz.end(); ++it ) { - if(it->second.total != 0) + if( it->second.total != 0 ) { ++total_cnt; - if(args.filter[0] == '\0') + if( args.filter[0] == '\0' ) { - slz_selected.push_back_no_space_check(it); + slz_selected.push_back_no_space_check( it ); } else { - auto name = get_name(it->first, worker); - if(is_substring(args.filter, name, args.case_sensitive)) + auto name = get_name( it->first, worker ); + if( is_substring( args.filter, name, args.case_sensitive ) ) { - slz_selected.push_back_no_space_check(it); + slz_selected.push_back_no_space_check( it ); } } } } std::vector columns; - if (args.unwrap) + if( args.unwrap ) { - columns = { - "name", "src_file", "src_line", "ns_since_start", "exec_time_ns", "thread", "value" - }; + columns = { "name", "src_file", "src_line", "ns_since_start", "exec_time_ns", "thread", "value" }; } else { - columns = { - "name", "src_file", "src_line", "total_ns", "total_perc", - "counts", "mean_ns", "min_ns", "max_ns", "std_ns" - }; + columns = { "name", "src_file", "src_line", "total_ns", "total_perc", "counts", "mean_ns", "min_ns", "max_ns", "std_ns" }; - if(args.truncated_mean_percentile) + if( args.truncated_mean_percentile ) { - columns.push_back("percentile_ns"); - columns.push_back("truncated_mean_ns"); + columns.push_back( "percentile_ns" ); + columns.push_back( "truncated_mean_ns" ); } } - std::string header = join(columns, args.separator); - printf("%s\n", header.data()); + std::string header = join( columns, args.separator ); + printf( "%s\n", header.data() ); const auto last_time = worker.GetLastTime(); - for(auto& it : slz_selected) + for( auto& it : slz_selected ) { - std::vector values(columns.size()); + std::vector values( columns.size() ); - values[0] = get_name(it->first, worker); + values[0] = get_name( it->first, worker ); - const auto& srcloc = worker.GetSourceLocation(it->first); - values[1] = worker.GetString(srcloc.file); - values[2] = std::to_string(srcloc.line); + const auto& srcloc = worker.GetSourceLocation( it->first ); + values[1] = worker.GetString( srcloc.file ); + values[2] = std::to_string( srcloc.line ); const auto& zone_data = it->second; - if (args.unwrap) + if( args.unwrap ) { int i = 0; - for (const auto& zone_thread_data : zone_data.zones) { + for( const auto& zone_thread_data : zone_data.zones ) + { const auto zone_event = zone_thread_data.Zone(); const auto tId = zone_thread_data.Thread(); const auto start = zone_event->Start(); const auto end = zone_event->End(); - values[3] = std::to_string(start); + values[3] = std::to_string( start ); auto timespan = end - start; - if (args.self_time) { - timespan -= GetZoneChildTimeFast(worker, *zone_event); + if( args.self_time ) + { + timespan -= GetZoneChildTimeFast( worker, *zone_event ); } - values[4] = std::to_string(timespan); - values[5] = std::to_string(tId); - if (worker.HasZoneExtra(*zone_event)) { - const auto& text = worker.GetZoneExtra(*zone_event).text; - if (text.Active()) { - values[6] = worker.GetString(text); + values[4] = std::to_string( timespan ); + values[5] = std::to_string( tId ); + if( worker.HasZoneExtra( *zone_event ) ) + { + const auto& text = worker.GetZoneExtra( *zone_event ).text; + if( text.Active() ) + { + values[6] = worker.GetString( text ); } } - std::string row = join(values, args.separator); - printf("%s\n", row.data()); + std::string row = join( values, args.separator ); + printf( "%s\n", row.data() ); } } else { const auto time = args.self_time ? zone_data.selfTotal : zone_data.total; - values[3] = std::to_string(time); - values[4] = std::to_string(100. * time / last_time); + values[3] = std::to_string( time ); + values[4] = std::to_string( 100. * time / last_time ); const auto sz = zone_data.zones.size(); - values[5] = std::to_string(sz); + values[5] = std::to_string( sz ); const auto avg = time / sz; - values[6] = std::to_string(avg); + values[6] = std::to_string( avg ); const auto tmin = args.self_time ? zone_data.selfMin : zone_data.min; const auto tmax = args.self_time ? zone_data.selfMax : zone_data.max; - values[7] = std::to_string(tmin); - values[8] = std::to_string(tmax); + values[7] = std::to_string( tmin ); + values[8] = std::to_string( tmax ); - const auto ss = zone_data.sumSq - - 2. * zone_data.total * avg - + avg * avg * sz; + const auto ss = zone_data.sumSq - 2. * zone_data.total * avg + avg * avg * sz; double std = 0; - if( sz > 1 ) - std = sqrt(ss / (sz - 1)); - values[9] = std::to_string(std); + if( sz > 1 ) std = sqrt( ss / ( sz - 1 ) ); + values[9] = std::to_string( std ); - if(args.truncated_mean_percentile) + if( args.truncated_mean_percentile ) { std::vector samples; samples.reserve( zone_data.zones.size() ); - for(const auto& zone_thread_data : zone_data.zones) + for( const auto& zone_thread_data : zone_data.zones ) { const auto zone_event = zone_thread_data.Zone(); auto timespan = zone_event->End() - zone_event->Start(); - if(args.self_time) - timespan -= GetZoneChildTimeFast( worker, *zone_event ); + if( args.self_time ) timespan -= GetZoneChildTimeFast( worker, *zone_event ); samples.push_back( timespan ); } - std::pair pN = percentile_and_truncated_mean(samples, args.truncated_mean_percentile / 100.0); - values[10] = std::to_string(pN.first); - values[11] = std::to_string(pN.second); + std::pair pN = percentile_and_truncated_mean( samples, args.truncated_mean_percentile / 100.0 ); + values[10] = std::to_string( pN.first ); + values[11] = std::to_string( pN.second ); } - std::string row = join(values, args.separator); - printf("%s\n", row.data()); + std::string row = join( values, args.separator ); + printf( "%s\n", row.data() ); } } - if(args.plot && args.unwrap) + if( args.plot && args.unwrap ) { - while (!worker.IsBackgroundDone()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - std::lock_guard lock(worker.GetDataLock()); + while( !worker.IsBackgroundDone() ) std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); + std::lock_guard lock( worker.GetDataLock() ); auto& plots = worker.GetPlots(); - for(const auto& plot : plots) + for( const auto& plot : plots ) { - std::vector values(columns.size()); - values[0] = worker.GetString(plot->name); + std::vector values( columns.size() ); + values[0] = worker.GetString( plot->name ); - for(const auto& val : plot->data) + for( const auto& val : plot->data ) { - if (args.unwrap) + if( args.unwrap ) { - values[3] = std::to_string(val.time.Val()); - values[6] = std::to_string(val.val); + values[3] = std::to_string( val.time.Val() ); + values[6] = std::to_string( val.val ); } - std::string row = join(values, args.separator); - printf("%s\n", row.data()); + std::string row = join( values, args.separator ); + printf( "%s\n", row.data() ); } } }