mirror of
https://github.com/wolfpld/tracy.git
synced 2025-03-20 07:40:02 +08:00
Make sampling work on current Android (no su -c).
The `su -c` approach does not work on current Android. It seems that on current Android, access to /proc and /sys is restricted enough that in practice, developers profiling on Android are likely running the whole instrumented process as root anyway, so `su` shouldn't be needed. (In particular, note that access to /proc/$pid is limited to members of a `readproc` group).
This commit is contained in:
parent
d7059eca63
commit
ff6537abff
@ -625,6 +625,7 @@ static const char SchedSwitch[] = "events/sched/sched_switch/enable";
|
|||||||
static const char SchedWakeup[] = "events/sched/sched_wakeup/enable";
|
static const char SchedWakeup[] = "events/sched/sched_wakeup/enable";
|
||||||
static const char BufferSizeKb[] = "buffer_size_kb";
|
static const char BufferSizeKb[] = "buffer_size_kb";
|
||||||
static const char TracePipe[] = "trace_pipe";
|
static const char TracePipe[] = "trace_pipe";
|
||||||
|
static const char PayloadPath[] = "/data/tracy_systrace";
|
||||||
|
|
||||||
static std::atomic<bool> traceActive { false };
|
static std::atomic<bool> traceActive { false };
|
||||||
static Thread* s_threadSampling = nullptr;
|
static Thread* s_threadSampling = nullptr;
|
||||||
@ -633,6 +634,14 @@ static int s_numCpus = 0;
|
|||||||
static constexpr size_t RingBufSize = 64*1024;
|
static constexpr size_t RingBufSize = 64*1024;
|
||||||
static RingBuffer<RingBufSize>* s_ring = nullptr;
|
static RingBuffer<RingBufSize>* s_ring = nullptr;
|
||||||
|
|
||||||
|
#define TRACY_LOG_ERROR_ERRNO(msg) \
|
||||||
|
fprintf(stderr, "ERROR (%s:%d) " msg " (errno=%d, %s)\n", \
|
||||||
|
__FILE__, __LINE__, errno, strerror(errno))
|
||||||
|
|
||||||
|
#define TRACY_LOG_ERROR_ERRNO_FMT(fmt, ...) \
|
||||||
|
fprintf(stderr, "ERROR (%s:%d) " fmt " (errno=%d, %s)\n", \
|
||||||
|
__FILE__, __LINE__, __VA_ARGS__, errno, strerror(errno))
|
||||||
|
|
||||||
static int perf_event_open( struct perf_event_attr* hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags )
|
static int perf_event_open( struct perf_event_attr* hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags )
|
||||||
{
|
{
|
||||||
return syscall( __NR_perf_event_open, hw_event, pid, cpu, group_fd, flags );
|
return syscall( __NR_perf_event_open, hw_event, pid, cpu, group_fd, flags );
|
||||||
@ -674,6 +683,7 @@ static void SetupSampling( int64_t& samplingPeriod )
|
|||||||
const int fd = perf_event_open( &pe, -1, i, -1, 0 );
|
const int fd = perf_event_open( &pe, -1, i, -1, 0 );
|
||||||
if( fd == -1 )
|
if( fd == -1 )
|
||||||
{
|
{
|
||||||
|
TRACY_LOG_ERROR_ERRNO("perf_event_open failed");
|
||||||
for( int j=0; j<i; j++ ) s_ring[j].~RingBuffer<RingBufSize>();
|
for( int j=0; j<i; j++ ) s_ring[j].~RingBuffer<RingBufSize>();
|
||||||
tracy_free( s_ring );
|
tracy_free( s_ring );
|
||||||
return;
|
return;
|
||||||
@ -795,14 +805,25 @@ static void SetupSampling( int64_t& samplingPeriod )
|
|||||||
}, nullptr );
|
}, nullptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
// Writes buffer contents (given by address `buf` and size `buf_size`) to
|
||||||
static bool TraceWrite( const char* path, size_t psz, const char* val, size_t vsz )
|
// the specified file descriptor (`fd`). Handles the case of `write` writing
|
||||||
{
|
// fewer bytes than requested.
|
||||||
char tmp[256];
|
static bool WriteBufferToFd(int fd, const void* buf, ssize_t buf_size) {
|
||||||
sprintf( tmp, "su -c 'echo \"%s\" > %s%s'", val, BasePath, path );
|
const char* buf_ptr = static_cast<const char*>(buf);
|
||||||
return system( tmp ) == 0;
|
while( buf_size > 0 )
|
||||||
|
{
|
||||||
|
ssize_t write_retval = write( fd, buf_ptr, buf_size );
|
||||||
|
if( write_retval < 0 )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
buf_size -= write_retval;
|
||||||
|
buf_ptr += write_retval;
|
||||||
|
}
|
||||||
|
assert(buf_size == 0);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
static bool TraceWrite( const char* path, size_t psz, const char* val, size_t vsz )
|
static bool TraceWrite( const char* path, size_t psz, const char* val, size_t vsz )
|
||||||
{
|
{
|
||||||
char tmp[256];
|
char tmp[256];
|
||||||
@ -810,61 +831,48 @@ static bool TraceWrite( const char* path, size_t psz, const char* val, size_t vs
|
|||||||
memcpy( tmp + sizeof( BasePath ) - 1, path, psz );
|
memcpy( tmp + sizeof( BasePath ) - 1, path, psz );
|
||||||
|
|
||||||
int fd = open( tmp, O_WRONLY );
|
int fd = open( tmp, O_WRONLY );
|
||||||
if( fd < 0 ) return false;
|
if( fd < 0 ) {
|
||||||
|
TRACY_LOG_ERROR_ERRNO_FMT("failed to open %s for write", tmp);
|
||||||
for(;;)
|
return false;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!WriteBufferToFd(fd, val, vsz)) {
|
||||||
|
TRACY_LOG_ERROR_ERRNO_FMT("failed to write to %s", tmp);
|
||||||
|
close(fd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
|
// The whole idea of the payload in a separate on-disk binary seems to have
|
||||||
|
// been motivated by the need to run that code as root. However, on current
|
||||||
|
// versions of Android, it now seems necessary to run all of the sampling
|
||||||
|
// code as root anyway, which in practice means running the whole workload
|
||||||
|
// as root. It may thus be possible to drop all this and simply run the
|
||||||
|
// payload as part of our process.
|
||||||
void SysTraceInjectPayload()
|
void SysTraceInjectPayload()
|
||||||
{
|
{
|
||||||
int pipefd[2];
|
#if defined __aarch64__
|
||||||
if( pipe( pipefd ) == 0 )
|
const auto* payload_data = tracy_systrace_aarch64_data;
|
||||||
{
|
int payload_size = tracy_systrace_aarch64_size;
|
||||||
const auto pid = fork();
|
#elif defined __ARM_ARCH
|
||||||
if( pid == 0 )
|
const auto* payload_data = tracy_systrace_armv7_data;
|
||||||
{
|
int payload_size = tracy_systrace_armv7_size;
|
||||||
// child
|
|
||||||
close( pipefd[1] );
|
|
||||||
if( dup2( pipefd[0], STDIN_FILENO ) >= 0 )
|
|
||||||
{
|
|
||||||
close( pipefd[0] );
|
|
||||||
execlp( "su", "su", "-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
|
#else
|
||||||
write( pipefd[1], tracy_systrace_armv7_data, tracy_systrace_armv7_size );
|
#error No payload for target CPU architecture
|
||||||
#endif
|
#endif
|
||||||
close( pipefd[1] );
|
int fd = open(PayloadPath, O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU);
|
||||||
waitpid( pid, nullptr, 0 );
|
if (fd == -1) {
|
||||||
|
TRACY_LOG_ERROR_ERRNO_FMT("failed to open %s for write", PayloadPath);
|
||||||
system( "su -c 'chmod 700 /data/tracy_systrace'" );
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (!WriteBufferToFd(fd, payload_data, payload_size)) {
|
||||||
|
TRACY_LOG_ERROR_ERRNO_FMT("failed to write to %s", PayloadPath);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1168,9 +1176,12 @@ void SysTraceWorker( void* ptr )
|
|||||||
sched_param sp = { 4 };
|
sched_param sp = { 4 };
|
||||||
pthread_setschedparam( pthread_self(), SCHED_FIFO, &sp );
|
pthread_setschedparam( pthread_self(), SCHED_FIFO, &sp );
|
||||||
#if defined __ANDROID__ && ( defined __aarch64__ || defined __ARM_ARCH )
|
#if defined __ANDROID__ && ( defined __aarch64__ || defined __ARM_ARCH )
|
||||||
execlp( "su", "su", "-c", "/data/tracy_systrace", (char*)nullptr );
|
if (execl( PayloadPath, PayloadPath, nullptr ) == -1) {
|
||||||
|
TRACY_LOG_ERROR_ERRNO_FMT("failed to exec %s", PayloadPath);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
execlp( "cat", "cat", "/sys/kernel/debug/tracing/trace_pipe", (char*)nullptr );
|
||||||
#endif
|
#endif
|
||||||
execlp( "su", "su", "-c", "cat /sys/kernel/debug/tracing/trace_pipe", (char*)nullptr );
|
|
||||||
exit( 1 );
|
exit( 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1215,7 +1226,9 @@ static void ProcessTraceLines( int fd )
|
|||||||
{
|
{
|
||||||
auto next = (char*)memchr( line, '\n', end - line );
|
auto next = (char*)memchr( line, '\n', end - line );
|
||||||
if( !next ) break;
|
if( !next ) break;
|
||||||
|
|
||||||
HandleTraceLine( line );
|
HandleTraceLine( line );
|
||||||
|
|
||||||
line = ++next;
|
line = ++next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user