2018-03-10 00:29:27 +00:00
# ifdef _WIN32
# include <windows.h>
2020-09-20 18:11:19 +00:00
# else
# include <unistd.h>
2018-03-10 00:29:27 +00:00
# endif
# include <chrono>
2018-03-10 01:25:29 +00:00
# include <inttypes.h>
2018-03-10 00:29:27 +00:00
# include <mutex>
2019-01-24 18:13:09 +00:00
# include <signal.h>
2018-03-10 01:25:29 +00:00
# include <stdint.h>
2018-03-10 00:29:27 +00:00
# include <stdio.h>
# include <stdlib.h>
2020-09-20 18:04:43 +00:00
# include <sys/stat.h>
2018-03-10 00:29:27 +00:00
2018-09-09 17:28:53 +00:00
# include "../../common/TracyProtocol.hpp"
2021-05-23 21:51:56 +00:00
# include "../../common/TracyStackFrames.hpp"
2018-03-10 00:29:27 +00:00
# include "../../server/TracyFileWrite.hpp"
# include "../../server/TracyMemory.hpp"
2019-06-18 18:43:28 +00:00
# include "../../server/TracyPrint.hpp"
2018-03-10 00:29:27 +00:00
# include "../../server/TracyWorker.hpp"
2021-01-26 23:32:38 +00:00
# ifdef _WIN32
# include ".. / .. / getopt / getopt.h"
# endif
2018-03-10 00:29:27 +00:00
2020-04-03 00:00:07 +00:00
2019-01-24 18:13:09 +00:00
bool disconnect = false ;
void SigInt ( int )
{
disconnect = true ;
}
2018-03-10 01:25:29 +00:00
2020-09-20 18:08:39 +00:00
[[noreturn]] void Usage ( )
2018-03-10 00:29:27 +00:00
{
2021-08-26 05:22:58 +00:00
printf ( " Usage: capture -o output.tracy [-a address] [-p port] [-f] [-s seconds] \n " ) ;
2018-03-10 00:29:27 +00:00
exit ( 1 ) ;
}
int main ( int argc , char * * argv )
{
# ifdef _WIN32
if ( ! AttachConsole ( ATTACH_PARENT_PROCESS ) )
{
AllocConsole ( ) ;
SetConsoleMode ( GetStdHandle ( STD_OUTPUT_HANDLE ) , 0x07 ) ;
}
# endif
2020-09-20 18:04:43 +00:00
bool overwrite = false ;
2020-09-23 14:38:20 +00:00
const char * address = " 127.0.0.1 " ;
2018-03-10 00:29:27 +00:00
const char * output = nullptr ;
2019-09-21 13:43:01 +00:00
int port = 8086 ;
2021-08-26 05:22:58 +00:00
int seconds = - 1 ;
2018-03-10 00:29:27 +00:00
int c ;
2021-08-26 05:22:58 +00:00
while ( ( c = getopt ( argc , argv , " a:o:p:fs: " ) ) ! = - 1 )
2018-03-10 00:29:27 +00:00
{
switch ( c )
{
case ' a ' :
address = optarg ;
break ;
case ' o ' :
output = optarg ;
break ;
2019-09-21 13:43:01 +00:00
case ' p ' :
port = atoi ( optarg ) ;
break ;
2020-09-20 18:04:43 +00:00
case ' f ' :
overwrite = true ;
break ;
2021-08-26 05:22:58 +00:00
case ' s ' :
seconds = atoi ( optarg ) ;
break ;
2018-03-10 00:29:27 +00:00
default :
Usage ( ) ;
break ;
}
}
if ( ! address | | ! output ) Usage ( ) ;
2020-09-20 18:04:43 +00:00
struct stat st ;
if ( stat ( output , & st ) = = 0 & & ! overwrite )
{
printf ( " Output file %s already exists! Use -f to force overwrite. \n " , output ) ;
return 4 ;
}
2020-09-20 18:11:19 +00:00
FILE * test = fopen ( output , " wb " ) ;
if ( ! test )
{
printf ( " Cannot open output file %s for writing! \n " , output ) ;
return 5 ;
}
fclose ( test ) ;
unlink ( output ) ;
2019-09-21 13:43:01 +00:00
printf ( " Connecting to %s:%i... " , address , port ) ;
2018-03-10 00:29:27 +00:00
fflush ( stdout ) ;
2019-09-21 13:43:01 +00:00
tracy : : Worker worker ( address , port ) ;
2019-02-12 10:13:53 +00:00
while ( ! worker . IsConnected ( ) )
2018-09-09 17:28:53 +00:00
{
const auto handshake = worker . GetHandshakeStatus ( ) ;
if ( handshake = = tracy : : HandshakeProtocolMismatch )
{
printf ( " \n The client you are trying to connect to uses incompatible protocol version. \n Make sure you are using the same Tracy version on both client and server. \n " ) ;
return 1 ;
}
2018-09-09 17:42:06 +00:00
if ( handshake = = tracy : : HandshakeNotAvailable )
{
printf ( " \n The client you are trying to connect to is no longer able to sent profiling data, \n because another server was already connected to it. \n You can do the following: \n \n 1. Restart the client application. \n 2. Rebuild the client application with on-demand mode enabled. \n " ) ;
return 2 ;
}
2019-02-12 10:13:53 +00:00
if ( handshake = = tracy : : HandshakeDropped )
{
printf ( " \n The client you are trying to connect to has disconnected during the initial \n connection handshake. Please check your network configuration. \n " ) ;
return 3 ;
}
2018-09-09 17:28:53 +00:00
}
2018-03-10 00:29:27 +00:00
while ( ! worker . HasData ( ) ) std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 100 ) ) ;
2019-06-18 18:43:28 +00:00
printf ( " \n Queue delay: %s \n Timer resolution: %s \n " , tracy : : TimeToString ( worker . GetDelay ( ) ) , tracy : : TimeToString ( worker . GetResolution ( ) ) ) ;
2018-03-10 00:29:27 +00:00
2020-04-03 00:00:07 +00:00
# ifdef _WIN32
signal ( SIGINT , SigInt ) ;
# else
struct sigaction sigint , oldsigint ;
2019-01-24 18:13:09 +00:00
memset ( & sigint , 0 , sizeof ( sigint ) ) ;
sigint . sa_handler = SigInt ;
sigaction ( SIGINT , & sigint , & oldsigint ) ;
2019-01-24 19:04:08 +00:00
# endif
2019-01-24 18:13:09 +00:00
2018-03-10 00:29:27 +00:00
auto & lock = worker . GetMbpsDataLock ( ) ;
2019-11-07 00:51:45 +00:00
const auto t0 = std : : chrono : : high_resolution_clock : : now ( ) ;
2018-03-10 00:29:27 +00:00
while ( worker . IsConnected ( ) )
{
2019-01-24 18:13:09 +00:00
if ( disconnect )
{
worker . Disconnect ( ) ;
disconnect = false ;
2021-08-26 05:22:58 +00:00
break ;
2019-01-24 18:13:09 +00:00
}
2018-03-10 00:29:27 +00:00
lock . lock ( ) ;
const auto mbps = worker . GetMbpsData ( ) . back ( ) ;
const auto compRatio = worker . GetCompRatio ( ) ;
2019-10-26 14:14:18 +00:00
const auto netTotal = worker . GetDataTransferred ( ) ;
2018-03-10 00:29:27 +00:00
lock . unlock ( ) ;
if ( mbps < 0.1f )
{
printf ( " \33 [2K \r \033 [36;1m%7.2f Kbps " , mbps * 1000.f ) ;
}
else
{
printf ( " \33 [2K \r \033 [36;1m%7.2f Mbps " , mbps ) ;
}
2019-11-10 18:20:57 +00:00
printf ( " \033 [0m / \033 [36;1m%5.1f%% \033 [0m= \033 [33;1m%7.2f Mbps \033 [0m| \033 [33mNet: \033 [32m%s \033 [0m| \033 [33mMem: \033 [31;1m%s \033 [0m | \033 [33mTime: %s \033 [0m " ,
2019-10-26 14:14:18 +00:00
compRatio * 100.f ,
mbps / compRatio ,
tracy : : MemSizeToString ( netTotal ) ,
2019-11-10 18:20:57 +00:00
tracy : : MemSizeToString ( tracy : : memUsage ) ,
2019-10-26 14:14:18 +00:00
tracy : : TimeToString ( worker . GetLastTime ( ) ) ) ;
2018-03-10 00:29:27 +00:00
fflush ( stdout ) ;
std : : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 100 ) ) ;
2021-08-26 05:22:58 +00:00
if ( seconds ! = - 1 )
{
const auto dur = std : : chrono : : high_resolution_clock : : now ( ) - t0 ;
if ( std : : chrono : : duration_cast < std : : chrono : : seconds > ( dur ) . count ( ) > = seconds )
{
disconnect = true ;
}
}
2018-03-10 00:29:27 +00:00
}
2019-11-07 00:51:45 +00:00
const auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
2018-03-10 00:29:27 +00:00
2019-01-14 22:52:38 +00:00
const auto & failure = worker . GetFailureType ( ) ;
if ( failure ! = tracy : : Worker : : Failure : : None )
{
2019-01-15 17:42:15 +00:00
printf ( " \n \033 [31;1mInstrumentation failure: %s \033 [0m " , tracy : : Worker : : GetFailureString ( failure ) ) ;
2020-10-06 12:50:55 +00:00
auto & fd = worker . GetFailureData ( ) ;
2021-10-10 12:52:30 +00:00
if ( ! fd . message . empty ( ) )
{
printf ( " \n Context: %s " , fd . message . c_str ( ) ) ;
}
2020-10-06 12:50:55 +00:00
if ( fd . callstack ! = 0 )
{
printf ( " \n \033 [1mFailure callstack: \033 [0m \n " ) ;
auto & cs = worker . GetCallstack ( fd . callstack ) ;
int fidx = 0 ;
int bidx = 0 ;
for ( auto & entry : cs )
{
auto frameData = worker . GetCallstackFrame ( entry ) ;
if ( ! frameData )
{
printf ( " %3i. %p \n " , fidx + + , ( void * ) worker . GetCanonicalPointer ( entry ) ) ;
}
else
{
const auto fsz = frameData - > size ;
for ( uint8_t f = 0 ; f < fsz ; f + + )
{
const auto & frame = frameData - > data [ f ] ;
auto txt = worker . GetString ( frame . name ) ;
if ( fidx = = 0 & & f ! = fsz - 1 )
{
auto test = tracy : : s_tracyStackFrames ;
bool match = false ;
do
{
if ( strcmp ( txt , * test ) = = 0 )
{
match = true ;
break ;
}
}
while ( * + + test ) ;
if ( match ) continue ;
}
bidx + + ;
if ( f = = fsz - 1 )
{
printf ( " %3i. " , fidx + + ) ;
}
else
{
printf ( " \033 [30;1minl. " ) ;
}
printf ( " \033 [0;36m%s " , txt ) ;
txt = worker . GetString ( frame . file ) ;
if ( frame . line = = 0 )
{
printf ( " \033 [33m(%s) " , txt ) ;
}
else
{
printf ( " \033 [33m(%s:% " PRIu32 " ) " , txt , frame . line ) ;
}
if ( frameData - > imageName . Active ( ) )
{
printf ( " \033 [35m %s \033 [0m \n " , worker . GetString ( frameData - > imageName ) ) ;
}
else
{
printf ( " \033 [0m \n " ) ;
}
}
}
}
}
2019-01-14 22:52:38 +00:00
}
2019-11-07 00:51:45 +00:00
printf ( " \n Frames: % " PRIu64 " \n Time span: %s \n Zones: %s \n Elapsed time: %s \n Saving trace... " ,
2020-01-31 00:43:24 +00:00
worker . GetFrameCount ( * worker . GetFramesBase ( ) ) , tracy : : TimeToString ( worker . GetLastTime ( ) ) , tracy : : RealToString ( worker . GetZoneCount ( ) ) ,
2019-11-07 00:51:45 +00:00
tracy : : TimeToString ( std : : chrono : : duration_cast < std : : chrono : : nanoseconds > ( t1 - t0 ) . count ( ) ) ) ;
2018-03-10 00:29:27 +00:00
fflush ( stdout ) ;
2018-03-28 23:11:54 +00:00
auto f = std : : unique_ptr < tracy : : FileWrite > ( tracy : : FileWrite : : Open ( output ) ) ;
2018-03-10 00:29:27 +00:00
if ( f )
{
2021-05-15 13:50:20 +00:00
worker . Write ( * f , false ) ;
2018-03-10 00:29:27 +00:00
printf ( " \033 [32;1mdone! \033 [0m \n " ) ;
2020-02-08 12:10:41 +00:00
f - > Finish ( ) ;
const auto stats = f - > GetCompressionStatistics ( ) ;
printf ( " Trace size %s (%.2f%% ratio) \n " , tracy : : MemSizeToString ( stats . second ) , 100.f * stats . second / stats . first ) ;
2018-03-10 00:29:27 +00:00
}
else
{
printf ( " \033 [31;1failed! \033 [0m \n " ) ;
}
return 0 ;
}