mirror of
https://github.com/ARMSX2/ARMSX3.git
synced 2026-08-24 16:58:52 -07:00
Sample thread CPU time by tid on Android
get_cycles passes the pthread handle to pthread_getcpuclockid, which glibc answers with an error for a thread that has already exited -- the else branch below returns the last known value for exactly that case. bionic instead looks the handle up in its list of live threads and aborts the process when it is not there. m_thread is never cleared when a thread ends and the performance overlay samples every PPU, SPU and RSX thread on a timer, so one finished thread is enough to take the emulator down with it. Latent here rather than absent: it needs the overlay on and a thread to have gone. Record the kernel tid at initialize and build the per-thread clock id from it the way bionic does once its own lookup succeeds, so clock_gettime simply fails for a dead thread, which is what the surrounding code already expects. Cleared at finalize so a thread stops being sampled before it goes away. Other platforms keep the original path. Found and fixed by Zulux91 in PS3Native.
This commit is contained in:
+17
-2
@@ -2844,6 +2844,7 @@ void thread_base::initialize(void (*error_cb)())
|
||||
[[maybe_unused]] u64 new_tid = 0;
|
||||
#elif defined(ANDROID)
|
||||
const u64 new_tid = pthread_self();
|
||||
m_native_tid = static_cast<u32>(gettid());
|
||||
#else
|
||||
const u64 new_tid = reinterpret_cast<u64>(pthread_self());
|
||||
#endif
|
||||
@@ -2998,6 +2999,10 @@ u64 thread_base::finalize(thread_state result_state) noexcept
|
||||
// Avoid race with the destructor
|
||||
const u64 _self = m_thread;
|
||||
|
||||
#ifdef ANDROID
|
||||
m_native_tid = 0;
|
||||
#endif
|
||||
|
||||
// Set result state (errored or finalized)
|
||||
m_sync.fetch_op([&](u32& v)
|
||||
{
|
||||
@@ -3373,11 +3378,21 @@ u64 thread_base::get_cycles()
|
||||
clockid_t _clock;
|
||||
struct timespec thread_time;
|
||||
#ifdef ANDROID
|
||||
pthread_t thread_id = handle;
|
||||
const u32 native_tid = m_native_tid;
|
||||
|
||||
if (!handle || !native_tid)
|
||||
{
|
||||
return m_cycles;
|
||||
}
|
||||
|
||||
_clock = (~static_cast<clockid_t>(native_tid) << 3) | 6;
|
||||
|
||||
if (!clock_gettime(_clock, &thread_time))
|
||||
#else
|
||||
pthread_t thread_id = reinterpret_cast<pthread_t>(handle);
|
||||
#endif
|
||||
|
||||
if (!pthread_getcpuclockid(thread_id, &_clock) && !clock_gettime(_clock, &thread_time))
|
||||
#endif
|
||||
{
|
||||
cycles = static_cast<u64>(thread_time.tv_sec) * 1'000'000'000 + thread_time.tv_nsec;
|
||||
#endif
|
||||
|
||||
@@ -139,6 +139,10 @@ private:
|
||||
// Thread handle (platform-specific)
|
||||
atomic_t<u64> m_thread{0};
|
||||
|
||||
#ifdef ANDROID
|
||||
atomic_t<u32> m_native_tid{0};
|
||||
#endif
|
||||
|
||||
// Thread cycles
|
||||
atomic_t<u64> m_cycles{0};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user