1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
|
/*
* Copyright 2021 The Emscripten Authors. All rights reserved.
* Emscripten is available under two separate licenses, the MIT license and the
* University of Illinois/NCSA Open Source License. Both these licenses can be
* found in the LICENSE file.
*/
#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include "pthread_impl.h"
#include <emscripten/threading.h>
#include <emscripten/heap.h>
static bool enabled = false;
#ifndef NDEBUG
void _emscripten_thread_profiler_init(pthread_t thread) {
assert(thread);
if (!enabled) {
return;
}
thread->profilerBlock = emscripten_builtin_malloc(sizeof(thread_profiler_block));
memset(thread->profilerBlock, 0, sizeof(thread_profiler_block));
thread->profilerBlock->currentStatusStartTime = emscripten_get_now();
}
// Sets the current thread status, but only if it was in the given expected
// state before. This is used to allow high-level control flow "override" the
// thread status before low-level (futex wait) operations set it.
static void set_status_conditional(int expectedStatus, int newStatus) {
if (!enabled) {
return;
}
pthread_t thread = pthread_self();
if (!thread) return; // AudioWorklets do not have a pthread block, but if user calls emscripten_futex_wait() in an AudioWorklet, it will call here via emscripten_set_current_thread_status().
int prevStatus = thread->profilerBlock->threadStatus;
if (prevStatus != newStatus && (prevStatus == expectedStatus || expectedStatus == -1)) {
double now = emscripten_get_now();
double startState = thread->profilerBlock->currentStatusStartTime;
double duration = now - startState;
thread->profilerBlock->timeSpentInStatus[prevStatus] += duration;
thread->profilerBlock->threadStatus = newStatus;
thread->profilerBlock->currentStatusStartTime = now;
}
}
void emscripten_conditional_set_current_thread_status(int expectedStatus, int newStatus) {
set_status_conditional(expectedStatus, newStatus);
}
void emscripten_set_current_thread_status(int newStatus) {
set_status_conditional(-1, newStatus);
}
void _emscripten_thread_profiler_enable() {
enabled = true;
_emscripten_thread_profiler_init(pthread_self());
emscripten_set_thread_name(pthread_self(), "Browser main thread");
}
#endif
void emscripten_set_thread_name(pthread_t thread, const char* name) {
if (!enabled) {
return;
}
strncpy(thread->profilerBlock->name, name, EM_THREAD_NAME_MAX-1);
}
|