mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 925111 - Enable Profiler to support config options during runtime. r=benwa, jld
This commit is contained in:
parent
62829542b3
commit
575461dbb9
@ -456,39 +456,93 @@ void Sampler::UnregisterCurrentThread()
|
||||
static struct sigaction old_sigstart_signal_handler;
|
||||
const int SIGSTART = SIGUSR2;
|
||||
|
||||
static void StartSignalHandler(int signal, siginfo_t* info, void* context) {
|
||||
static void freeArray(const char** array, int size) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
free((void*) array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t readCSVArray(char* csvList, const char** buffer) {
|
||||
uint32_t count;
|
||||
char* savePtr;
|
||||
int newlinePos = strlen(csvList) - 1;
|
||||
if (csvList[newlinePos] == '\n') {
|
||||
csvList[newlinePos] = '\0';
|
||||
}
|
||||
|
||||
char* item = strtok_r(csvList, ",", &savePtr);
|
||||
for (count = 0; item; item = strtok_r(NULL, ",", &savePtr)) {
|
||||
int length = strlen(item) + 1; // Include \0
|
||||
char* newBuf = (char*) malloc(sizeof(char) * length);
|
||||
buffer[count] = newBuf;
|
||||
strncpy(newBuf, item, length);
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// Currently support only the env variables
|
||||
// reported in read_profiler_env
|
||||
static void ReadProfilerVars(const char* fileName, const char** features,
|
||||
uint32_t* featureCount, const char** threadNames, uint32_t* threadCount) {
|
||||
FILE* file = fopen(fileName, "r");
|
||||
const int bufferSize = 1024;
|
||||
char line[bufferSize];
|
||||
char* feature;
|
||||
char* value;
|
||||
char* savePtr;
|
||||
|
||||
if (file) {
|
||||
while (fgets(line, bufferSize, file) != NULL) {
|
||||
feature = strtok_r(line, "=", &savePtr);
|
||||
value = strtok_r(NULL, "", &savePtr);
|
||||
|
||||
if (strncmp(feature, PROFILER_MODE, bufferSize) == 0) {
|
||||
set_profiler_mode(value);
|
||||
} else if (strncmp(feature, PROFILER_INTERVAL, bufferSize) == 0) {
|
||||
set_profiler_interval(value);
|
||||
} else if (strncmp(feature, PROFILER_ENTRIES, bufferSize) == 0) {
|
||||
set_profiler_entries(value);
|
||||
} else if (strncmp(feature, PROFILER_STACK, bufferSize) == 0) {
|
||||
set_profiler_scan(value);
|
||||
} else if (strncmp(feature, PROFILER_FEATURES, bufferSize) == 0) {
|
||||
*featureCount = readCSVArray(value, features);
|
||||
} else if (strncmp(feature, "threads", bufferSize) == 0) {
|
||||
*threadCount = readCSVArray(value, threadNames);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void StartSignalHandler(int signal, siginfo_t* info, void* context) {
|
||||
// XXX: Everything we do here is NOT async signal safe. We risk nasty things
|
||||
// like deadlocks but we typically only do this once so it tends to be ok.
|
||||
// See bug 909403
|
||||
const char* threadName = NULL;
|
||||
uint32_t threadCount = 0;
|
||||
char thread[256];
|
||||
|
||||
// TODO support selecting features from profiler.options
|
||||
const char* features[3] = {NULL, NULL, NULL};
|
||||
uint32_t featureCount = 0;
|
||||
features[0] = "leaf";
|
||||
featureCount++;
|
||||
features[1] = "js";
|
||||
featureCount++;
|
||||
const char* threadFeature = "threads";
|
||||
uint32_t threadCount = 0;
|
||||
|
||||
std::ifstream infile;
|
||||
infile.open("/data/local/tmp/profiler.options");
|
||||
if (infile.is_open()) {
|
||||
infile.getline(thread, 256);
|
||||
threadName = thread;
|
||||
threadCount = 1;
|
||||
features[featureCount] = threadFeature;
|
||||
featureCount++;
|
||||
printf_stderr("Profiling only %s\n", threadName);
|
||||
}
|
||||
infile.close();
|
||||
// Just allocate 10 features for now
|
||||
// FIXME: these don't really point to const chars*
|
||||
// So we free them later, but we don't want to change the const char**
|
||||
// declaration in profiler_start. Annoying but ok for now.
|
||||
const char* threadNames[10];
|
||||
const char* features[10];
|
||||
const char* profilerConfigFile = "/data/local/tmp/profiler.options";
|
||||
|
||||
ReadProfilerVars(profilerConfigFile, features, &featureCount, threadNames, &threadCount);
|
||||
MOZ_ASSERT(featureCount < 10);
|
||||
MOZ_ASSERT(threadCount < 10);
|
||||
|
||||
profiler_start(PROFILE_DEFAULT_ENTRY, 1,
|
||||
features, featureCount,
|
||||
&threadName, threadCount);
|
||||
threadNames, threadCount);
|
||||
|
||||
freeArray(threadNames, threadCount);
|
||||
freeArray(features, featureCount);
|
||||
}
|
||||
|
||||
void OS::RegisterStartHandler()
|
||||
|
@ -46,6 +46,13 @@ int sLastFrameNumber = 0;
|
||||
int sInitCount = 0; // Each init must have a matched shutdown.
|
||||
static bool sIsProfiling = false; // is raced on
|
||||
|
||||
// env variables to control the profiler
|
||||
const char* PROFILER_MODE = "MOZ_PROFILER_MODE";
|
||||
const char* PROFILER_INTERVAL = "MOZ_PROFILER_INTERVAL";
|
||||
const char* PROFILER_ENTRIES = "MOZ_PROFILER_ENTRIES";
|
||||
const char* PROFILER_STACK = "MOZ_PROFILER_STACK_SCAN";
|
||||
const char* PROFILER_FEATURES = "MOZ_PROFILING_FEATURES";
|
||||
|
||||
/* used to keep track of the last event that we sampled during */
|
||||
unsigned int sLastSampledEventGeneration = 0;
|
||||
|
||||
@ -252,68 +259,112 @@ static inline const char* name_UnwMode(UnwMode m)
|
||||
}
|
||||
}
|
||||
|
||||
bool set_profiler_mode(const char* mode) {
|
||||
if (mode) {
|
||||
if (0 == strcmp(mode, "pseudo")) {
|
||||
sUnwindMode = UnwPSEUDO;
|
||||
return true;
|
||||
}
|
||||
else if (0 == strcmp(mode, "native") && is_native_unwinding_avail()) {
|
||||
sUnwindMode = UnwNATIVE;
|
||||
return true;
|
||||
}
|
||||
else if (0 == strcmp(mode, "combined") && is_native_unwinding_avail()) {
|
||||
sUnwindMode = UnwCOMBINED;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set_profiler_interval(const char* interval) {
|
||||
if (interval) {
|
||||
errno = 0;
|
||||
long int n = strtol(interval, (char**)NULL, 10);
|
||||
if (errno == 0 && n >= 1 && n <= 1000) {
|
||||
sUnwindInterval = n;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set_profiler_entries(const char* entries) {
|
||||
if (entries) {
|
||||
errno = 0;
|
||||
long int n = strtol(entries, (char**)NULL, 10);
|
||||
if (errno == 0 && n > 0) {
|
||||
sProfileEntries = n;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool set_profiler_scan(const char* scanCount) {
|
||||
if (scanCount) {
|
||||
errno = 0;
|
||||
long int n = strtol(scanCount, (char**)NULL, 10);
|
||||
if (errno == 0 && n >= 0 && n <= 100) {
|
||||
sUnwindStackScan = n;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_native_unwinding_avail() {
|
||||
# if defined(HAVE_NATIVE_UNWIND)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Read env vars at startup, so as to set sUnwindMode and sInterval.
|
||||
void read_profiler_env_vars()
|
||||
{
|
||||
bool nativeAvail = false;
|
||||
# if defined(HAVE_NATIVE_UNWIND)
|
||||
nativeAvail = true;
|
||||
# endif
|
||||
|
||||
MOZ_ASSERT(sUnwindMode == UnwINVALID);
|
||||
MOZ_ASSERT(sUnwindInterval == 0);
|
||||
MOZ_ASSERT(sProfileEntries == 0);
|
||||
bool nativeAvail = is_native_unwinding_avail();
|
||||
|
||||
/* Set defaults */
|
||||
sUnwindMode = nativeAvail ? UnwCOMBINED : UnwPSEUDO;
|
||||
sUnwindInterval = 0; /* We'll have to look elsewhere */
|
||||
sProfileEntries = 0;
|
||||
|
||||
const char* strM = PR_GetEnv("MOZ_PROFILER_MODE");
|
||||
const char* strI = PR_GetEnv("MOZ_PROFILER_INTERVAL");
|
||||
const char* strE = PR_GetEnv("MOZ_PROFILER_ENTRIES");
|
||||
const char* strF = PR_GetEnv("MOZ_PROFILER_STACK_SCAN");
|
||||
const char* stackMode = PR_GetEnv(PROFILER_MODE);
|
||||
const char* interval = PR_GetEnv(PROFILER_INTERVAL);
|
||||
const char* entries = PR_GetEnv(PROFILER_ENTRIES);
|
||||
const char* scanCount = PR_GetEnv(PROFILER_STACK);
|
||||
|
||||
if (strM) {
|
||||
if (0 == strcmp(strM, "pseudo"))
|
||||
sUnwindMode = UnwPSEUDO;
|
||||
else if (0 == strcmp(strM, "native") && nativeAvail)
|
||||
sUnwindMode = UnwNATIVE;
|
||||
else if (0 == strcmp(strM, "combined") && nativeAvail)
|
||||
sUnwindMode = UnwCOMBINED;
|
||||
else goto usage;
|
||||
if (!set_profiler_mode(stackMode) ||
|
||||
!set_profiler_interval(interval) ||
|
||||
!set_profiler_entries(entries) ||
|
||||
!set_profiler_scan(scanCount)) {
|
||||
profiler_usage();
|
||||
} else {
|
||||
LOG( "SPS:");
|
||||
LOGF("SPS: Unwind mode = %s", name_UnwMode(sUnwindMode));
|
||||
LOGF("SPS: Sampling interval = %d ms (zero means \"platform default\")",
|
||||
(int)sUnwindInterval);
|
||||
LOGF("SPS: Entry store size = %d (zero means \"platform default\")",
|
||||
(int)sProfileEntries);
|
||||
LOGF("SPS: UnwindStackScan = %d (max dubious frames per unwind).",
|
||||
(int)sUnwindStackScan);
|
||||
LOG( "SPS: Use env var MOZ_PROFILER_MODE=help for further information.");
|
||||
LOG( "SPS:");
|
||||
}
|
||||
}
|
||||
|
||||
if (strI) {
|
||||
errno = 0;
|
||||
long int n = strtol(strI, (char**)NULL, 10);
|
||||
if (errno == 0 && n >= 1 && n <= 1000) {
|
||||
sUnwindInterval = n;
|
||||
}
|
||||
else goto usage;
|
||||
}
|
||||
|
||||
if (strE) {
|
||||
errno = 0;
|
||||
long int n = strtol(strE, (char**)NULL, 10);
|
||||
if (errno == 0 && n > 0) {
|
||||
sProfileEntries = n;
|
||||
}
|
||||
else goto usage;
|
||||
}
|
||||
|
||||
if (strF) {
|
||||
errno = 0;
|
||||
long int n = strtol(strF, (char**)NULL, 10);
|
||||
if (errno == 0 && n >= 0 && n <= 100) {
|
||||
sUnwindStackScan = n;
|
||||
}
|
||||
else goto usage;
|
||||
}
|
||||
|
||||
goto out;
|
||||
|
||||
usage:
|
||||
void profiler_usage() {
|
||||
LOG( "SPS: ");
|
||||
LOG( "SPS: Environment variable usage:");
|
||||
LOG( "SPS: ");
|
||||
@ -339,15 +390,15 @@ void read_profiler_env_vars()
|
||||
LOG( "SPS: Needs to be set to use Breakpad-based unwinding.");
|
||||
LOG( "SPS: ");
|
||||
LOGF("SPS: This platform %s native unwinding.",
|
||||
nativeAvail ? "supports" : "does not support");
|
||||
is_native_unwinding_avail() ? "supports" : "does not support");
|
||||
LOG( "SPS: ");
|
||||
|
||||
/* Re-set defaults */
|
||||
sUnwindMode = nativeAvail ? UnwCOMBINED : UnwPSEUDO;
|
||||
sUnwindMode = is_native_unwinding_avail() ? UnwCOMBINED : UnwPSEUDO;
|
||||
sUnwindInterval = 0; /* We'll have to look elsewhere */
|
||||
sProfileEntries = 0;
|
||||
sUnwindStackScan = 0;
|
||||
|
||||
out:
|
||||
LOG( "SPS:");
|
||||
LOGF("SPS: Unwind mode = %s", name_UnwMode(sUnwindMode));
|
||||
LOGF("SPS: Sampling interval = %d ms (zero means \"platform default\")",
|
||||
|
@ -240,7 +240,22 @@ class Thread {
|
||||
|
||||
/* Some values extracted at startup from environment variables, that
|
||||
control the behaviour of the breakpad unwinder. */
|
||||
extern const char* PROFILER_MODE;
|
||||
extern const char* PROFILER_INTERVAL;
|
||||
extern const char* PROFILER_ENTRIES;
|
||||
extern const char* PROFILER_STACK;
|
||||
extern const char* PROFILER_FEATURES;
|
||||
|
||||
void read_profiler_env_vars();
|
||||
void profiler_usage();
|
||||
|
||||
// Helper methods to expose modifying profiler behavior
|
||||
bool set_profiler_mode(const char*);
|
||||
bool set_profiler_interval(const char*);
|
||||
bool set_profiler_entries(const char*);
|
||||
bool set_profiler_scan(const char*);
|
||||
bool is_native_unwinding_avail();
|
||||
|
||||
typedef enum { UnwINVALID, UnwNATIVE, UnwPSEUDO, UnwCOMBINED } UnwMode;
|
||||
extern UnwMode sUnwindMode; /* what mode? */
|
||||
extern int sUnwindInterval; /* in milliseconds */
|
||||
|
Loading…
Reference in New Issue
Block a user