diff --git a/client/TracySysTrace.cpp b/client/TracySysTrace.cpp index 1972a345..b8e059fd 100644 --- a/client/TracySysTrace.cpp +++ b/client/TracySysTrace.cpp @@ -641,31 +641,13 @@ void SysTraceGetExternalName( uint64_t thread, const char*& threadName, const ch # include "TracyRingBuffer.hpp" # include "TracyThread.hpp" -# ifdef __ANDROID__ -# include "TracySysTracePayload.hpp" -# endif - -# ifdef __AVX2__ -# include -# endif - namespace tracy { -static const char BasePath[] = "/sys/kernel/debug/tracing/"; -static const char TracingOn[] = "tracing_on"; -static const char CurrentTracer[] = "current_tracer"; -static const char TraceOptions[] = "trace_options"; -static const char TraceClock[] = "trace_clock"; -static const char SchedSwitch[] = "events/sched/sched_switch/enable"; -static const char SchedWakeup[] = "events/sched/sched_wakeup/enable"; -static const char BufferSizeKb[] = "buffer_size_kb"; -static const char TracePipe[] = "trace_pipe"; - static std::atomic traceActive { false }; -static Thread* s_threadSampling = nullptr; static int s_numCpus = 0; static int s_numBuffers = 0; +static int s_ctxBufferIdx = 0; static constexpr size_t RingBufSize = 64*1024; static RingBuffer* s_ring = nullptr; @@ -683,7 +665,9 @@ enum TraceEventId EventCacheReference, EventCacheMiss, EventBranchRetired, - EventBranchMiss + EventBranchMiss, + EventContextSwitch, + EventWakeup, }; static void ProbePreciseIp( perf_event_attr& pe, unsigned long long config0, unsigned long long config1, pid_t pid ) @@ -745,12 +729,103 @@ static bool IsGenuineIntel() #endif } -static void SetupSampling( int64_t& samplingPeriod ) +static const char* ReadFile( const char* path ) +{ + int fd = open( path, O_RDONLY ); + if( fd < 0 ) return nullptr; + + static char tmp[64]; + const auto cnt = read( fd, tmp, 63 ); + close( fd ); + if( cnt < 0 ) return nullptr; + tmp[cnt] = '\0'; + return tmp; +} + +#ifdef __ANDROID__ +static const char* ReadFileElevated( const char* path ) +{ + // Explanation for "su root sh -c": there are 2 flavors of "su" in circulation + // on Android. The default Android su has the following syntax to run a command + // as root: + // su root 'command' + // and 'command' is exec'd not passed to a shell, so if shell interpretation is + // wanted, one needs to do: + // su root sh -c 'command' + // Besides that default Android 'su' command, some Android devices use a different + // su with a command-line interface closer to the familiar util-linux su found + // on Linux distributions. Fortunately, both the util-linux su and the one + // in https://github.com/topjohnwu/Magisk seem to be happy with the above + // `su root sh -c 'command'` command line syntax. + + int pipefd[2]; + if( pipe( pipefd ) == 0 ) + { + const auto pid = fork(); + if( pid == 0 ) + { + // child + close( pipefd[0] ); + dup2( open( "/dev/null", O_WRONLY ), STDERR_FILENO ); + if( dup2( pipefd[1], STDOUT_FILENO ) >= 0 ) + { + close( pipefd[1] ); + char tmp[1024]; + sprintf( tmp, "cat %s", path ); + execlp( "su", "su", "root", "sh", "-c", tmp, (char*)nullptr ); + exit( 1 ); + } + exit( 0 ); + } + else if( pid > 0 ) + { + // parent + close( pipefd[1] ); + static char tmp[64]; + const auto sz = read( pipefd[0], tmp, 63 ); + close( pipefd[0] ); + waitpid( pid, nullptr, 0 ); + if( sz <= 0 ) return nullptr; + tmp[sz] = '\0'; + return tmp; + } + else + { + return nullptr; + } + } + else + { + return nullptr; + } +} +#else +static const char* ReadFileElevated( const char* path ) +{ + return ReadFile( path ); +} +#endif + +bool SysTraceStart( int64_t& samplingPeriod ) { #ifndef CLOCK_MONOTONIC_RAW - return; + return false; #endif + int paranoidLevel = 2; + const auto paranoidLevelStr = ReadFile( "/proc/sys/kernel/perf_event_paranoid" ); + if( !paranoidLevelStr ) return false; + paranoidLevel = atoi( paranoidLevelStr ); + TracyDebug( "perf_event_paranoid: %i\n", paranoidLevel ); + + int switchId = -1, wakeupId = -1; + const auto switchIdStr = ReadFileElevated( "/sys/kernel/debug/tracing/events/sched/sched_switch/id" ); + if( switchIdStr ) switchId = atoi( switchIdStr ); + const auto wakeupIdStr = ReadFileElevated( "/sys/kernel/debug/tracing/events/sched/sched_wakeup/id" ); + if( wakeupIdStr ) wakeupId = atoi( wakeupIdStr ); + + TracyDebug( "sched_switch id: %i\nsched_wakeup id: %i\n", switchId, wakeupId ); + #ifdef TRACY_NO_SAMPLE_RETIREMENT const bool noRetirement = true; #else @@ -772,14 +847,28 @@ static void SetupSampling( int64_t& samplingPeriod ) const bool noBranch = noBranchEnv && noBranchEnv[0] == '1'; #endif +#ifdef TRACY_NO_CONTEXT_SWITCH + const bool noCtxSwitch = true; +#else + const char* noCtxSwitchEnv = GetEnvVar( "TRACY_NO_CONTEXT_SWITCH" ); + const bool noCtxSwitch = noCtxSwitchEnv && noCtxSwitchEnv[0] == '1'; +#endif + samplingPeriod = GetSamplingPeriod(); uint32_t currentPid = (uint32_t)getpid(); + const auto maxNumBuffers = s_numCpus * ( + 1 + // software sampling + 2 + // CPU cycles + instructions retired + 2 + // cache reference + miss + 2 + // branch retired + miss + 2 // context switches + wakeups + ); s_numCpus = (int)std::thread::hardware_concurrency(); - s_ring = (RingBuffer*)tracy_malloc( sizeof( RingBuffer ) * s_numCpus * 7 ); + s_ring = (RingBuffer*)tracy_malloc( sizeof( RingBuffer ) * maxNumBuffers ); s_numBuffers = 0; - // Stack traces + // software sampling perf_event_attr pe = {}; pe.type = PERF_TYPE_SOFTWARE; pe.size = sizeof( perf_event_attr ); @@ -801,15 +890,23 @@ static void SetupSampling( int64_t& samplingPeriod ) ProbePreciseIp( pe, currentPid ); for( int i=0; i(); - tracy_free( s_ring ); - return; + pe.exclude_kernel = 1; + ProbePreciseIp( pe, currentPid ); + fd = perf_event_open( &pe, currentPid, i, -1, PERF_FLAG_FD_CLOEXEC ); + if( fd == -1 ) + { + for( int j=0; j(); + tracy_free( s_ring ); + return false; + } + TracyDebug( " No access to kernel samples\n" ); } new( s_ring+s_numBuffers ) RingBuffer( fd, EventCallstack ); s_numBuffers++; + TracyDebug( " Core %i ok\n", i ); } // CPU cycles + instructions retired @@ -920,765 +1017,397 @@ static void SetupSampling( int64_t& samplingPeriod ) } } + s_ctxBufferIdx = s_numBuffers; - s_threadSampling = (Thread*)tracy_malloc( sizeof( Thread ) ); - new(s_threadSampling) Thread( [] (void*) { - ThreadExitHandler threadExitHandler; - SetThreadName( "Tracy Sampling" ); - InitRpmalloc(); - sched_param sp = { 5 }; - pthread_setschedparam( pthread_self(), SCHED_FIFO, &sp ); - for( int i=0; i tail ); - hadData = true; + new( s_ring+s_numBuffers ) RingBuffer( fd, EventContextSwitch, i ); + s_numBuffers++; + TracyDebug( " Core %i ok\n", i ); + } + } - const auto end = head - tail; - uint64_t pos = 0; - while( pos < end ) + if( wakeupId != -1 ) + { + pe.config = wakeupId; + + TracyDebug( "Setup wakeup capture\n" ); + for( int i=0; i 0 ) - { -#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) - t0 = ring.ConvertTimeToTsc( t0 ); -#endif - auto trace = (uint64_t*)tracy_malloc_fast( ( 1 + cnt ) * sizeof( uint64_t ) ); - ring.Read( trace+1, offset, sizeof( uint64_t ) * cnt ); - -#if defined __x86_64__ || defined _M_X64 - // remove non-canonical pointers - do - { - const auto test = (int64_t)trace[cnt]; - const auto m1 = test >> 63; - const auto m2 = test >> 47; - if( m1 == m2 ) break; - } - while( --cnt > 0 ); - for( uint64_t j=1; j> 63; - const auto m2 = test >> 47; - if( m1 != m2 ) trace[j] = 0; - } -#endif - - for( uint64_t j=1; j<=cnt; j++ ) - { - if( trace[j] >= (uint64_t)-4095 ) // PERF_CONTEXT_MAX - { - memmove( trace+j, trace+j+1, sizeof( uint64_t ) * ( cnt - j ) ); - cnt--; - } - } - - memcpy( trace, &cnt, sizeof( uint64_t ) ); - - TracyLfqPrepare( QueueType::CallstackSample ); - MemWrite( &item->callstackSampleFat.time, t0 ); - MemWrite( &item->callstackSampleFat.thread, tid ); - MemWrite( &item->callstackSampleFat.ptr, (uint64_t)trace ); - TracyLfqCommit; - } - } - else - { - // Layout: - // u64 ip - // u64 time - - uint64_t ip, t0; - ring.Read( &ip, offset, sizeof( uint64_t ) ); - offset += sizeof( uint64_t ); - ring.Read( &t0, offset, sizeof( uint64_t ) ); - -#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) - t0 = ring.ConvertTimeToTsc( t0 ); -#endif - QueueType type; - switch( id ) - { - case EventCpuCycles: - type = QueueType::HwSampleCpuCycle; - break; - case EventInstructionsRetired: - type = QueueType::HwSampleInstructionRetired; - break; - case EventCacheReference: - type = QueueType::HwSampleCacheReference; - break; - case EventCacheMiss: - type = QueueType::HwSampleCacheMiss; - break; - case EventBranchRetired: - type = QueueType::HwSampleBranchRetired; - break; - case EventBranchMiss: - type = QueueType::HwSampleBranchMiss; - break; - default: - assert( false ); - break; - } - - TracyLfqPrepare( type ); - MemWrite( &item->hwSample.ip, ip ); - MemWrite( &item->hwSample.time, t0 ); - TracyLfqCommit; - } - } - pos += hdr.size; + new( s_ring+s_numBuffers ) RingBuffer( fd, EventWakeup, i ); + s_numBuffers++; + TracyDebug( " Core %i ok\n", i ); } - assert( pos == end ); - ring.Advance( end ); } - if( !traceActive.load( std::memory_order_relaxed) ) break; - if( !hadData ) - { - std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); - } - } - - for( int i=0; i(); - tracy_free_fast( s_ring ); - }, nullptr ); -} - -#ifdef __ANDROID__ -static bool TraceWrite( const char* path, size_t psz, const char* val, size_t vsz ) -{ - // Explanation for "su root sh -c": there are 2 flavors of "su" in circulation - // on Android. The default Android su has the following syntax to run a command - // as root: - // su root 'command' - // and 'command' is exec'd not passed to a shell, so if shell interpretation is - // wanted, one needs to do: - // su root sh -c 'command' - // Besides that default Android 'su' command, some Android devices use a different - // su with a command-line interface closer to the familiar util-linux su found - // on Linux distributions. Fortunately, both the util-linux su and the one - // in https://github.com/topjohnwu/Magisk seem to be happy with the above - // `su root sh -c 'command'` command line syntax. - char tmp[256]; - sprintf( tmp, "su root sh -c 'echo \"%s\" > %s%s'", val, BasePath, path ); - return system( tmp ) == 0; -} -#else -static bool TraceWrite( const char* path, size_t psz, const char* val, size_t vsz ) -{ - char tmp[256]; - memcpy( tmp, BasePath, sizeof( BasePath ) - 1 ); - memcpy( tmp + sizeof( BasePath ) - 1, path, psz ); - - int fd = open( tmp, O_WRONLY ); - if( fd < 0 ) return false; - - for(;;) - { - ssize_t cnt = write( fd, val, vsz ); - if( cnt == (ssize_t)vsz ) - { - close( fd ); - return true; - } - if( cnt < 0 ) - { - close( fd ); - return false; - } - vsz -= cnt; - val += cnt; - } -} -#endif - -#ifdef __ANDROID__ -void SysTraceInjectPayload() -{ - int pipefd[2]; - if( pipe( pipefd ) == 0 ) - { - const auto pid = fork(); - if( pid == 0 ) - { - // child - close( pipefd[1] ); - if( dup2( pipefd[0], STDIN_FILENO ) >= 0 ) - { - close( pipefd[0] ); - execlp( "su", "su", "root", "sh", "-c", "cat > /data/tracy_systrace", (char*)nullptr ); - exit( 1 ); - } - } - else if( pid > 0 ) - { - // parent - close( pipefd[0] ); - -#ifdef __aarch64__ - write( pipefd[1], tracy_systrace_aarch64_data, tracy_systrace_aarch64_size ); -#else - write( pipefd[1], tracy_systrace_armv7_data, tracy_systrace_armv7_size ); -#endif - close( pipefd[1] ); - waitpid( pid, nullptr, 0 ); - - system( "su root sh -c 'chmod 700 /data/tracy_systrace'" ); } } -} -#endif -bool SysTraceStart( int64_t& samplingPeriod ) -{ -#ifndef CLOCK_MONOTONIC_RAW - return false; -#endif + TracyDebug( "Ringbuffers in use: %i\n", s_numBuffers ); - if( !TraceWrite( TracingOn, sizeof( TracingOn ), "0", 2 ) ) return false; - if( !TraceWrite( CurrentTracer, sizeof( CurrentTracer ), "nop", 4 ) ) return false; - TraceWrite( TraceOptions, sizeof( TraceOptions ), "norecord-cmd", 13 ); - TraceWrite( TraceOptions, sizeof( TraceOptions ), "norecord-tgid", 14 ); - TraceWrite( TraceOptions, sizeof( TraceOptions ), "noirq-info", 11 ); - TraceWrite( TraceOptions, sizeof( TraceOptions ), "noannotate", 11 ); -#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) - if( !TraceWrite( TraceClock, sizeof( TraceClock ), "x86-tsc", 8 ) ) return false; -#else - if( !TraceWrite( TraceClock, sizeof( TraceClock ), "mono_raw", 9 ) ) return false; -#endif - if( !TraceWrite( SchedSwitch, sizeof( SchedSwitch ), "1", 2 ) ) return false; - if( !TraceWrite( SchedWakeup, sizeof( SchedWakeup ), "1", 2 ) ) return false; - if( !TraceWrite( BufferSizeKb, sizeof( BufferSizeKb ), "4096", 5 ) ) return false; - -#if defined __ANDROID__ && ( defined __aarch64__ || defined __ARM_ARCH ) - SysTraceInjectPayload(); -#endif - - if( !TraceWrite( TracingOn, sizeof( TracingOn ), "1", 2 ) ) return false; traceActive.store( true, std::memory_order_relaxed ); - - SetupSampling( samplingPeriod ); - return true; } void SysTraceStop() { - TraceWrite( TracingOn, sizeof( TracingOn ), "0", 2 ); traceActive.store( false, std::memory_order_relaxed ); - if( s_threadSampling ) - { - s_threadSampling->~Thread(); - tracy_free( s_threadSampling ); - } -} - -static uint64_t ReadNumber( const char*& data ) -{ - auto ptr = data; - assert( *ptr >= '0' && *ptr <= '9' ); - uint64_t val = 0; - for(;;) - { - uint64_t q; - memcpy( &q, ptr, 8 ); - for( int i=0; i<8; i++ ) - { - const uint64_t v = ( q & 0xFF ) - '0'; - if( v > 9 ) - { - data = ptr + i; - return val; - } - val = val * 10 + v; - q >>= 8; - } - ptr += 8; - } -} - -static uint8_t ReadState( char state ) -{ - switch( state ) - { - case 'D': return 101; - case 'I': return 102; - case 'R': return 103; - case 'S': return 104; - case 'T': return 105; - case 't': return 106; - case 'W': return 107; - case 'X': return 108; - case 'Z': return 109; - default: return 100; - } -} - -#if defined __ANDROID__ && defined __ANDROID_API__ && __ANDROID_API__ < 18 -/*- - * Copyright (c) 2011 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Christos Zoulas. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -ssize_t getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) -{ - char *ptr, *eptr; - - if (*buf == NULL || *bufsiz == 0) { - *bufsiz = BUFSIZ; - if ((*buf = (char*)malloc(*bufsiz)) == NULL) - return -1; - } - - for (ptr = *buf, eptr = *buf + *bufsiz;;) { - int c = fgetc(fp); - if (c == -1) { - if (feof(fp)) - return ptr == *buf ? -1 : ptr - *buf; - else - return -1; - } - *ptr++ = c; - if (c == delimiter) { - *ptr = '\0'; - return ptr - *buf; - } - if (ptr + 2 >= eptr) { - char *nbuf; - size_t nbufsiz = *bufsiz * 2; - ssize_t d = ptr - *buf; - if ((nbuf = (char*)realloc(*buf, nbufsiz)) == NULL) - return -1; - *buf = nbuf; - *bufsiz = nbufsiz; - eptr = nbuf + nbufsiz; - ptr = nbuf + d; - } - } -} - -ssize_t getline(char **buf, size_t *bufsiz, FILE *fp) -{ - return getdelim(buf, bufsiz, '\n', fp); -} -#endif - -#ifdef __AVX2__ -static inline void AdvanceTo( const char*& line, char match ) -{ - __m256i m = _mm256_set1_epi8( match ); - auto ptr = line; - for(;;) - { - __m256i l = _mm256_loadu_si256( (const __m256i*)ptr ); - __m256i c = _mm256_cmpeq_epi8( l, m ); - auto b = uint32_t( _mm256_movemask_epi8( c ) ); - if( b != 0 ) - { - line = ptr + __builtin_ctz( b ); - return; - } - ptr += 32; - } -} -#else -static inline void AdvanceTo( const char*& line, char match ) -{ - auto ptr = line; - for(;;) - { - uint64_t l; - memcpy( &l, ptr, 8 ); - for( int i=0; i<8; i++ ) - { - if( ( l & 0xFF ) == uint8_t( match ) ) - { - line = ptr + i; - return; - } - l >>= 8; - } - ptr += 8; - } -} -#endif - -#ifdef __AVX2__ -static inline void AdvanceToNot( const char*& line, char match ) -{ - __m256i m = _mm256_set1_epi8( match ); - auto ptr = line; - for(;;) - { - __m256i l = _mm256_loadu_si256( (const __m256i*)ptr ); - __m256i c = _mm256_cmpeq_epi8( l, m ); - auto b = ~uint32_t( _mm256_movemask_epi8( c ) ); - if( b != 0 ) - { - line = ptr + __builtin_ctz( b ); - return; - } - ptr += 32; - } -} -#else -static inline void AdvanceToNot( const char*& line, char match ) -{ - auto ptr = line; - for(;;) - { - uint64_t l; - memcpy( &l, ptr, 8 ); - for( int i=0; i<8; i++ ) - { - if( ( l & 0xFF ) != uint8_t( match ) ) - { - line = ptr + i; - return; - } - l >>= 8; - } - ptr += 8; - } -} -#endif - -#ifdef __AVX2__ -template -static inline void AdvanceTo( const char*& line, const char* match ) -{ - auto first = uint8_t( match[0] ); - __m256i m = _mm256_set1_epi8( first ); - auto ptr = line; - for(;;) - { - __m256i l = _mm256_loadu_si256( (const __m256i*)ptr ); - __m256i c = _mm256_cmpeq_epi8( l, m ); - auto b = uint32_t( _mm256_movemask_epi8( c ) ); - while( b != 0 ) - { - auto bit = __builtin_ctz( b ); - auto test = ptr + bit; - if( memcmp( test + 1, match + 1, S - 1 ) == 0 ) - { - line = test; - return; - } - b ^= ( 1u << bit ); - } - ptr += 32; - } -} -#else -template -static inline void AdvanceTo( const char*& line, const char* match ) -{ - auto first = uint8_t( match[0] ); - auto ptr = line; - for(;;) - { - uint64_t l; - memcpy( &l, ptr, 8 ); - for( int i=0; i<8; i++ ) - { - if( ( l & 0xFF ) == first ) - { - if( memcmp( ptr + i + 1, match + 1, S - 1 ) == 0 ) - { - line = ptr + i; - return; - } - } - l >>= 8; - } - ptr += 8; - } -} -#endif - -static void HandleTraceLine( const char* line ) -{ - line += 23; - AdvanceTo( line, '[' ); - line++; - const auto cpu = (uint8_t)ReadNumber( line ); - line++; // ']' - AdvanceToNot( line, ' ' ); - -#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) - const auto time = ReadNumber( line ); -#else - const auto ts = ReadNumber( line ); - line++; // '.' - const auto tus = ReadNumber( line ); - const auto time = ts * 1000000000ll + tus * 1000ll; -#endif - - line += 2; // ': ' - if( memcmp( line, "sched_switch", 12 ) == 0 ) - { - line += 14; - - AdvanceTo<8>( line, "prev_pid" ); - line += 9; - - const auto oldPid = uint32_t( ReadNumber( line ) ); - line++; - - AdvanceTo<10>( line, "prev_state" ); - line += 11; - - const auto oldState = (uint8_t)ReadState( *line ); - line += 5; - - AdvanceTo<8>( line, "next_pid" ); - line += 9; - - const auto newPid = uint32_t( ReadNumber( line ) ); - - uint8_t reason = 100; - - TracyLfqPrepare( QueueType::ContextSwitch ); - MemWrite( &item->contextSwitch.time, time ); - MemWrite( &item->contextSwitch.oldThread, oldPid ); - MemWrite( &item->contextSwitch.newThread, newPid ); - MemWrite( &item->contextSwitch.cpu, cpu ); - MemWrite( &item->contextSwitch.reason, reason ); - MemWrite( &item->contextSwitch.state, oldState ); - TracyLfqCommit; - } - else if( memcmp( line, "sched_wakeup", 12 ) == 0 ) - { - line += 14; - - AdvanceTo<4>( line, "pid=" ); - line += 4; - - const auto pid = uint32_t( ReadNumber( line ) ); - - TracyLfqPrepare( QueueType::ThreadWakeup ); - MemWrite( &item->threadWakeup.time, time ); - MemWrite( &item->threadWakeup.thread, pid ); - TracyLfqCommit; - } -} - -#ifdef __ANDROID__ -static void ProcessTraceLines( int fd ) -{ - // Linux pipe buffer is 64KB, additional 1KB is for unfinished lines - char* buf = (char*)tracy_malloc( (64+1)*1024 ); - char* line = buf; - - for(;;) - { - if( !traceActive.load( std::memory_order_relaxed ) ) break; - - const auto rd = read( fd, line, 64*1024 ); - if( rd <= 0 ) break; - -#ifdef TRACY_ON_DEMAND - if( !GetProfiler().IsConnected() ) - { - if( rd < 64*1024 ) - { - assert( line[rd-1] == '\n' ); - line = buf; - std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); - } - else - { - const auto end = line + rd; - line = end - 1; - while( line > buf && *line != '\n' ) line--; - if( line > buf ) - { - line++; - const auto lsz = end - line; - memmove( buf, line, lsz ); - line = buf + lsz; - } - } - continue; - } -#endif - - const auto end = line + rd; - line = buf; - for(;;) - { - auto next = (char*)memchr( line, '\n', end - line ); - if( !next ) - { - const auto lsz = end - line; - memmove( buf, line, lsz ); - line = buf + lsz; - break; - } - HandleTraceLine( line ); - line = ++next; - } - if( rd < 64*1024 ) - { - std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); - } - } - - tracy_free( buf ); } void SysTraceWorker( void* ptr ) { ThreadExitHandler threadExitHandler; - SetThreadName( "Tracy SysTrace" ); - int pipefd[2]; - if( pipe( pipefd ) == 0 ) - { - const auto pid = fork(); - if( pid == 0 ) - { - // child - close( pipefd[0] ); - dup2( open( "/dev/null", O_WRONLY ), STDERR_FILENO ); - if( dup2( pipefd[1], STDOUT_FILENO ) >= 0 ) - { - close( pipefd[1] ); - sched_param sp = { 4 }; - pthread_setschedparam( pthread_self(), SCHED_FIFO, &sp ); -#if defined __ANDROID__ && ( defined __aarch64__ || defined __ARM_ARCH ) - execlp( "su", "su", "root", "sh", "-c", "/data/tracy_systrace", (char*)nullptr ); -#endif - execlp( "su", "su", "root", "sh", "-c", "cat /sys/kernel/debug/tracing/trace_pipe", (char*)nullptr ); - exit( 1 ); - } - } - else if( pid > 0 ) - { - // parent - close( pipefd[1] ); - sched_param sp = { 5 }; - pthread_setschedparam( pthread_self(), SCHED_FIFO, &sp ); - ProcessTraceLines( pipefd[0] ); - close( pipefd[0] ); - waitpid( pid, nullptr, 0 ); - } - } -} -#else -static void ProcessTraceLines( int fd ) -{ - // 32 bytes buffer space for wide unbound reads - char* buf = (char*)tracy_malloc( 64*1024 + 32 ); - - struct pollfd pfd; - pfd.fd = fd; - pfd.events = POLLIN | POLLERR; - - for(;;) - { - while( poll( &pfd, 1, 0 ) <= 0 ) - { - if( !traceActive.load( std::memory_order_relaxed ) ) break; - std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); - } - - const auto rd = read( fd, buf, 64*1024 ); - if( rd <= 0 ) break; - -#ifdef TRACY_ON_DEMAND - if( !GetProfiler().IsConnected() ) continue; -#endif - - auto line = buf; - const auto end = buf + rd; - for(;;) - { - auto next = (char*)memchr( line, '\n', end - line ); - if( !next ) break; - HandleTraceLine( line ); - line = ++next; - } - } - - tracy_free( buf ); -} - -void SysTraceWorker( void* ptr ) -{ - ThreadExitHandler threadExitHandler; - SetThreadName( "Tracy SysTrace" ); - char tmp[256]; - memcpy( tmp, BasePath, sizeof( BasePath ) - 1 ); - memcpy( tmp + sizeof( BasePath ) - 1, TracePipe, sizeof( TracePipe ) ); - - int fd = open( tmp, O_RDONLY ); - if( fd < 0 ) return; + SetThreadName( "Tracy Sampling" ); + InitRpmalloc(); sched_param sp = { 5 }; pthread_setschedparam( pthread_self(), SCHED_FIFO, &sp ); - ProcessTraceLines( fd ); - close( fd ); -} + for( int i=0; i tail ); + hadData = true; + + const auto end = head - tail; + uint64_t pos = 0; + while( pos < end ) + { + perf_event_header hdr; + ring.Read( &hdr, pos, sizeof( perf_event_header ) ); + if( hdr.type == PERF_RECORD_SAMPLE ) + { + auto offset = pos + sizeof( perf_event_header ); + const auto id = ring.GetId(); + assert( id != EventContextSwitch ); + if( id == EventCallstack ) + { + // Layout: + // u32 pid, tid + // u64 time + // u64 cnt + // u64 ip[cnt] + + uint32_t tid; + uint64_t t0; + uint64_t cnt; + + offset += sizeof( uint32_t ); + ring.Read( &tid, offset, sizeof( uint32_t ) ); + offset += sizeof( uint32_t ); + ring.Read( &t0, offset, sizeof( uint64_t ) ); + offset += sizeof( uint64_t ); + ring.Read( &cnt, offset, sizeof( uint64_t ) ); + offset += sizeof( uint64_t ); + + if( cnt > 0 ) + { +#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) + t0 = ring.ConvertTimeToTsc( t0 ); #endif + auto trace = (uint64_t*)tracy_malloc_fast( ( 1 + cnt ) * sizeof( uint64_t ) ); + ring.Read( trace+1, offset, sizeof( uint64_t ) * cnt ); + +#if defined __x86_64__ || defined _M_X64 + // remove non-canonical pointers + do + { + const auto test = (int64_t)trace[cnt]; + const auto m1 = test >> 63; + const auto m2 = test >> 47; + if( m1 == m2 ) break; + } + while( --cnt > 0 ); + for( uint64_t j=1; j> 63; + const auto m2 = test >> 47; + if( m1 != m2 ) trace[j] = 0; + } +#endif + + for( uint64_t j=1; j<=cnt; j++ ) + { + if( trace[j] >= (uint64_t)-4095 ) // PERF_CONTEXT_MAX + { + memmove( trace+j, trace+j+1, sizeof( uint64_t ) * ( cnt - j ) ); + cnt--; + } + } + + memcpy( trace, &cnt, sizeof( uint64_t ) ); + + TracyLfqPrepare( QueueType::CallstackSample ); + MemWrite( &item->callstackSampleFat.time, t0 ); + MemWrite( &item->callstackSampleFat.thread, tid ); + MemWrite( &item->callstackSampleFat.ptr, (uint64_t)trace ); + TracyLfqCommit; + } + } + else + { + // Layout: + // u64 ip + // u64 time + + uint64_t ip, t0; + ring.Read( &ip, offset, sizeof( uint64_t ) ); + offset += sizeof( uint64_t ); + ring.Read( &t0, offset, sizeof( uint64_t ) ); + +#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) + t0 = ring.ConvertTimeToTsc( t0 ); +#endif + QueueType type; + switch( id ) + { + case EventCpuCycles: + type = QueueType::HwSampleCpuCycle; + break; + case EventInstructionsRetired: + type = QueueType::HwSampleInstructionRetired; + break; + case EventCacheReference: + type = QueueType::HwSampleCacheReference; + break; + case EventCacheMiss: + type = QueueType::HwSampleCacheMiss; + break; + case EventBranchRetired: + type = QueueType::HwSampleBranchRetired; + break; + case EventBranchMiss: + type = QueueType::HwSampleBranchMiss; + break; + default: + assert( false ); + break; + } + + TracyLfqPrepare( type ); + MemWrite( &item->hwSample.ip, ip ); + MemWrite( &item->hwSample.time, t0 ); + TracyLfqCommit; + } + } + pos += hdr.size; + } + assert( pos == end ); + ring.Advance( end ); + } + if( !traceActive.load( std::memory_order_relaxed ) ) break; + + if( s_ctxBufferIdx != s_numBuffers ) + { + const auto ctxBufNum = s_numBuffers - s_ctxBufferIdx; + + int activeNum = 0; + bool active[512]; + uint32_t end[512]; + uint32_t pos[512]; + for( int i=0; i 0 ) + { + hadData = true; + while( activeNum > 0 ) + { + int sel = -1; + int64_t t0 = std::numeric_limits::max(); + for( int i=0; i= 0 || activeNum == 0 ); + if( sel >= 0 ) + { + auto& ring = s_ring[s_ctxBufferIdx + sel]; + auto rbPos = pos[sel]; + auto offset = rbPos; + perf_event_header hdr; + ring.Read( &hdr, offset, sizeof( perf_event_header ) ); + +#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) + t0 = ring.ConvertTimeToTsc( t0 ); +#endif + + if( ring.GetId() == EventContextSwitch ) + { + // Layout: + // u64 time + // u32 size + // u8 data[size] + // Data (not ABI stable, but has not changed since it was added, in 2009): + // u8 hdr[8] + // u8 prev_comm[16] + // u32 prev_pid + // u32 prev_prio + // u64 prev_state + // u8 next_comm[16] + // u32 next_pid + // u32 next_prio + + offset += sizeof( perf_event_header ) + sizeof( uint64_t ) + sizeof( uint32_t ) + 8 + 16; + + uint32_t prev_pid, next_pid; + uint64_t prev_state; + + ring.Read( &prev_pid, offset, sizeof( uint32_t ) ); + offset += sizeof( uint32_t ) + sizeof( uint32_t ); + ring.Read( &prev_state, offset, sizeof( uint64_t ) ); + offset += sizeof( uint64_t ) + 16; + ring.Read( &next_pid, offset, sizeof( uint32_t ) ); + + uint8_t reason = 100; + uint8_t state; + + if( prev_state & 0x0001 ) state = 104; + else if( prev_state & 0x0002 ) state = 101; + else if( prev_state & 0x0004 ) state = 105; + else if( prev_state & 0x0008 ) state = 106; + else if( prev_state & 0x0010 ) state = 108; + else if( prev_state & 0x0020 ) state = 109; + else if( prev_state & 0x0040 ) state = 110; + else if( prev_state & 0x0080 ) state = 102; + else state = 103; + + TracyLfqPrepare( QueueType::ContextSwitch ); + MemWrite( &item->contextSwitch.time, t0 ); + MemWrite( &item->contextSwitch.oldThread, prev_pid ); + MemWrite( &item->contextSwitch.newThread, next_pid ); + MemWrite( &item->contextSwitch.cpu, uint8_t( ring.GetCpu() ) ); + MemWrite( &item->contextSwitch.reason, reason ); + MemWrite( &item->contextSwitch.state, state ); + TracyLfqCommit; + } + else + { + assert( ring.GetId() == EventWakeup ); + + // Layout: + // u64 time + // u32 size + // u8 data[size] + // Data: + // u8 hdr[8] + // u8 comm[16] + // u32 pid + // u32 prio + // u64 target_cpu + + offset += sizeof( perf_event_header ) + sizeof( uint64_t ) + sizeof( uint32_t ) + 8 + 16; + + uint32_t pid; + ring.Read( &pid, offset, sizeof( uint32_t ) ); + + TracyLfqPrepare( QueueType::ThreadWakeup ); + MemWrite( &item->threadWakeup.time, t0 ); + MemWrite( &item->threadWakeup.thread, pid ); + TracyLfqCommit; + } + + rbPos += hdr.size; + if( rbPos == end[sel] ) + { + active[sel] = false; + activeNum--; + } + else + { + pos[sel] = rbPos; + } + } + } + for( int i=0; i(); + tracy_free_fast( s_ring ); +} void SysTraceGetExternalName( uint64_t thread, const char*& threadName, const char*& name ) { diff --git a/client/TracySysTracePayload.hpp b/client/TracySysTracePayload.hpp deleted file mode 100644 index 7c292f9d..00000000 --- a/client/TracySysTracePayload.hpp +++ /dev/null @@ -1,78 +0,0 @@ -// File: 'extra/systrace/tracy_systrace.armv7' (1149 bytes) -// File: 'extra/systrace/tracy_systrace.aarch64' (1650 bytes) - -// Exported using binary_to_compressed_c.cpp - -namespace tracy -{ - -static const unsigned int tracy_systrace_armv7_size = 1149; -static const unsigned int tracy_systrace_armv7_data[1152/4] = -{ - 0x464c457f, 0x00010101, 0x00000000, 0x00000000, 0x00280003, 0x00000001, 0x000001f0, 0x00000034, 0x00000000, 0x05000200, 0x00200034, 0x00280007, - 0x00000000, 0x00000006, 0x00000034, 0x00000034, 0x00000034, 0x000000e0, 0x000000e0, 0x00000004, 0x00000004, 0x00000003, 0x00000114, 0x00000114, - 0x00000114, 0x00000013, 0x00000013, 0x00000004, 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x000003fd, 0x000003fd, 0x00000005, - 0x00001000, 0x00000001, 0x000003fd, 0x000013fd, 0x000013fd, 0x00000080, 0x000000b3, 0x00000006, 0x00001000, 0x00000002, 0x00000400, 0x00001400, - 0x00001400, 0x0000007d, 0x000000b0, 0x00000006, 0x00000004, 0x6474e551, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000006, - 0x00000004, 0x70000001, 0x000003a4, 0x000003a4, 0x000003a4, 0x00000008, 0x00000008, 0x00000004, 0x00000004, 0x7379732f, 0x2f6d6574, 0x2f6e6962, - 0x6b6e696c, 0x00007265, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000012, 0x00000016, 0x00000000, - 0x00000000, 0x00000012, 0x6f6c6400, 0x006e6570, 0x4342494c, 0x62696c00, 0x732e6c64, 0x6c64006f, 0x006d7973, 0x00000001, 0x00000003, 0x00000001, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010001, 0x0000000d, 0x00000010, 0x00000000, 0x00050d63, 0x00020000, 0x00000008, - 0x00000000, 0x000014bc, 0x00000116, 0x000014c0, 0x00000216, 0xe52de004, 0xe59fe004, 0xe08fe00e, 0xe5bef008, 0x000012dc, 0xe28fc600, 0xe28cca01, - 0xe5bcf2dc, 0xe28fc600, 0xe28cca01, 0xe5bcf2d4, 0xe92d4ff0, 0xe28db01c, 0xe24dd024, 0xe24dd801, 0xe59f017c, 0xe3a01001, 0xe3a08001, 0xe08f0000, - 0xebfffff0, 0xe59f116c, 0xe1a04000, 0xe08f1001, 0xebffffef, 0xe59f1160, 0xe1a06000, 0xe1a00004, 0xe08f1001, 0xebffffea, 0xe59f1150, 0xe1a07000, - 0xe1a00004, 0xe08f1001, 0xebffffe5, 0xe59f1140, 0xe1a05000, 0xe1a00004, 0xe08f1001, 0xebffffe0, 0xe58d0004, 0xe1a00004, 0xe59f1128, 0xe08f1001, - 0xebffffdb, 0xe59f1120, 0xe1a0a000, 0xe1a00004, 0xe08f1001, 0xebffffd6, 0xe1a04000, 0xe59f010c, 0xe3a01000, 0xe3a09000, 0xe08f0000, 0xe12fff36, - 0xe1a06000, 0xe3700001, 0xca000001, 0xe3a00000, 0xe12fff37, 0xe3a00009, 0xe3a01001, 0xe1cd01bc, 0xe3a00008, 0xe1cd01b4, 0xe3090680, 0xe3400098, - 0xe3a02000, 0xe58d000c, 0xe28d0010, 0xe58d7000, 0xe58d6018, 0xe58d8010, 0xe58d9008, 0xe12fff35, 0xe3500000, 0xca00001d, 0xe28d7018, 0xe28d8010, - 0xe28d9020, 0xe1a00007, 0xe3a01001, 0xe3a02000, 0xe12fff35, 0xe3500000, 0xda00000a, 0xe1a00006, 0xe1a01009, 0xe3a02801, 0xe12fff3a, 0xe3500001, - 0xba00000e, 0xe1a02000, 0xe3a00001, 0xe1a01009, 0xe12fff34, 0xea000003, 0xe59d2004, 0xe28d0008, 0xe3a01000, 0xe12fff32, 0xe1a00008, 0xe3a01001, - 0xe3a02000, 0xe12fff35, 0xe3500001, 0xbaffffe4, 0xe59d1000, 0xe3a00000, 0xe12fff31, 0xe24bd01c, 0xe8bd8ff0, 0x00000198, 0x00000190, 0x00000181, - 0x00000172, 0x00000163, 0x00000159, 0x0000014a, 0x00000138, 0x7ffffe4c, 0x00000001, 0x6362696c, 0x006f732e, 0x6e65706f, 0x69786500, 0x6f700074, - 0x6e006c6c, 0x736f6e61, 0x7065656c, 0x61657200, 0x72770064, 0x00657469, 0x7379732f, 0x72656b2f, 0x2f6c656e, 0x75626564, 0x72742f67, 0x6e696361, - 0x72742f67, 0x5f656361, 0x65706970, 0x00000000, 0x00000003, 0x000014b0, 0x00000002, 0x00000010, 0x00000017, 0x000001b4, 0x00000014, 0x00000011, - 0x00000015, 0x00000000, 0x00000006, 0x00000128, 0x0000000b, 0x00000010, 0x00000005, 0x00000158, 0x0000000a, 0x0000001c, 0x6ffffef5, 0x00000174, - 0x00000001, 0x0000000d, 0x0000001e, 0x00000008, 0x6ffffffb, 0x00000001, 0x6ffffff0, 0x0000018c, 0x6ffffffe, 0x00000194, 0x6fffffff, 0x00000001, -}; - -static const unsigned int tracy_systrace_aarch64_size = 1650; -static const unsigned int tracy_systrace_aarch64_data[1652/4] = -{ - 0x464c457f, 0x00010102, 0x00000000, 0x00000000, 0x00b70003, 0x00000001, 0x000002e0, 0x00000000, 0x00000040, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00380040, 0x00400006, 0x00000000, 0x00000006, 0x00000005, 0x00000040, 0x00000000, 0x00000040, 0x00000000, 0x00000040, 0x00000000, - 0x00000150, 0x00000000, 0x00000150, 0x00000000, 0x00000008, 0x00000000, 0x00000003, 0x00000004, 0x00000190, 0x00000000, 0x00000190, 0x00000000, - 0x00000190, 0x00000000, 0x00000015, 0x00000000, 0x00000015, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000005, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000004e1, 0x00000000, 0x000004e1, 0x00000000, 0x00001000, 0x00000000, 0x00000001, 0x00000006, - 0x000004e8, 0x00000000, 0x000014e8, 0x00000000, 0x000014e8, 0x00000000, 0x0000018a, 0x00000000, 0x00000190, 0x00000000, 0x00001000, 0x00000000, - 0x00000002, 0x00000006, 0x000004e8, 0x00000000, 0x000014e8, 0x00000000, 0x000014e8, 0x00000000, 0x00000160, 0x00000000, 0x00000160, 0x00000000, - 0x00000008, 0x00000000, 0x6474e551, 0x00000006, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000008, 0x00000000, 0x7379732f, 0x2f6d6574, 0x2f6e6962, 0x6b6e696c, 0x34367265, 0x00000000, 0x00000001, 0x00000001, - 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00090003, 0x000002e0, 0x00000000, 0x00000000, 0x00000000, 0x00000010, 0x00000012, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x0000000a, 0x00000012, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x62696c00, 0x732e6c64, 0x6c64006f, 0x006d7973, 0x706f6c64, 0x4c006e65, - 0x00434249, 0x00000000, 0x00000000, 0x00000000, 0x00010001, 0x00000001, 0x00000010, 0x00000000, 0x00050d63, 0x00020000, 0x00000017, 0x00000000, - 0x00001668, 0x00000000, 0x00000402, 0x00000002, 0x00000000, 0x00000000, 0x00001670, 0x00000000, 0x00000402, 0x00000003, 0x00000000, 0x00000000, - 0xa9bf7bf0, 0xb0000010, 0xf9433211, 0x91198210, 0xd61f0220, 0xd503201f, 0xd503201f, 0xd503201f, 0xb0000010, 0xf9433611, 0x9119a210, 0xd61f0220, - 0xb0000010, 0xf9433a11, 0x9119c210, 0xd61f0220, 0xa9bb67fc, 0xa9015ff8, 0xa90257f6, 0xa9034ff4, 0xa9047bfd, 0x910103fd, 0xd14043ff, 0xd10083ff, - 0x90000000, 0x91124000, 0x52800021, 0x52800039, 0x97ffffec, 0x90000001, 0x91126021, 0xaa0003f7, 0x97ffffec, 0x90000001, 0xaa0003f8, 0x91127421, - 0xaa1703e0, 0x97ffffe7, 0x90000001, 0xaa0003f3, 0x91128821, 0xaa1703e0, 0x97ffffe2, 0x90000001, 0xaa0003f4, 0x91129c21, 0xaa1703e0, 0x97ffffdd, - 0x90000001, 0xaa0003f5, 0x9112c421, 0xaa1703e0, 0x97ffffd8, 0x90000001, 0xaa0003f6, 0x9112d821, 0xaa1703e0, 0x97ffffd3, 0xaa0003f7, 0x90000000, - 0x9112f000, 0x2a1f03e1, 0xd63f0300, 0x2a0003f8, 0x36f80060, 0x2a1f03e0, 0xd63f0260, 0x90000009, 0x3dc12120, 0x52800128, 0x79003be8, 0x52800108, - 0x910043e0, 0x52800021, 0x2a1f03e2, 0xb9001bf8, 0xb90013f9, 0x79002be8, 0x3d8003e0, 0xd63f0280, 0x7100001f, 0x5400036c, 0x910063e0, 0x52800021, - 0x2a1f03e2, 0xd63f0280, 0x7100001f, 0x5400018d, 0x910083e1, 0x52a00022, 0x2a1803e0, 0xd63f02c0, 0xf100041f, 0x540001eb, 0xaa0003e2, 0x910083e1, - 0x52800020, 0xd63f02e0, 0x14000004, 0x910003e0, 0xaa1f03e1, 0xd63f02a0, 0x910043e0, 0x52800021, 0x2a1f03e2, 0xd63f0280, 0x7100041f, 0x54fffceb, - 0x2a1f03e0, 0xd63f0260, 0x914043ff, 0x910083ff, 0xa9447bfd, 0xa9434ff4, 0xa94257f6, 0xa9415ff8, 0xa8c567fc, 0xd65f03c0, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00989680, 0x00000000, 0x6362696c, 0x006f732e, 0x6e65706f, 0x69786500, 0x6f700074, 0x6e006c6c, 0x736f6e61, 0x7065656c, - 0x61657200, 0x72770064, 0x00657469, 0x7379732f, 0x72656b2f, 0x2f6c656e, 0x75626564, 0x72742f67, 0x6e696361, 0x72742f67, 0x5f656361, 0x65706970, - 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000001, 0x00000000, 0x6ffffef5, 0x00000000, 0x000001a8, 0x00000000, 0x00000005, 0x00000000, - 0x00000228, 0x00000000, 0x00000006, 0x00000000, 0x000001c8, 0x00000000, 0x0000000a, 0x00000000, 0x0000001c, 0x00000000, 0x0000000b, 0x00000000, - 0x00000018, 0x00000000, 0x00000015, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00001650, 0x00000000, 0x00000002, 0x00000000, - 0x00000030, 0x00000000, 0x00000014, 0x00000000, 0x00000007, 0x00000000, 0x00000017, 0x00000000, 0x00000270, 0x00000000, 0x0000001e, 0x00000000, - 0x00000008, 0x00000000, 0x6ffffffb, 0x00000000, 0x00000001, 0x00000000, 0x6ffffffe, 0x00000000, 0x00000250, 0x00000000, 0x6fffffff, 0x00000000, - 0x00000001, 0x00000000, 0x6ffffff0, 0x00000000, 0x00000244, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x000002a0, 0x00000000, 0x000002a0, -}; - -}