mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 707308 - Add Dynamic profiling labels. r=jmuizel,ehsan
--HG-- extra : rebase_source : 1a72148342e7a71de62230ac2ca3a283724e4bbd
This commit is contained in:
parent
eac4d6b53f
commit
1a3591793e
@ -68,6 +68,7 @@ using namespace mozilla;
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
static const int DYNAMIC_MAX_STRING = 512;
|
||||
|
||||
mozilla::ThreadLocal<ProfileStack *> tlsStack;
|
||||
mozilla::ThreadLocal<TableTicker *> tlsTicker;
|
||||
@ -121,6 +122,7 @@ private:
|
||||
friend class ThreadProfile;
|
||||
union {
|
||||
const char* mTagData;
|
||||
char mTagChars[sizeof(void*)];
|
||||
void* mTagPtr;
|
||||
double mTagFloat;
|
||||
Address mTagAddress;
|
||||
@ -226,6 +228,30 @@ public:
|
||||
mWritePos = mLastFlushPos;
|
||||
}
|
||||
|
||||
char* processDynamicTag(int readPos, int* tagsConsumed, char* tagBuff)
|
||||
{
|
||||
int readAheadPos = (readPos + 1) % mEntrySize;
|
||||
int tagBuffPos = 0;
|
||||
|
||||
// Read the string stored in mTagData until the null character is seen
|
||||
bool seenNullByte = false;
|
||||
while (readAheadPos != mLastFlushPos && !seenNullByte) {
|
||||
(*tagsConsumed)++;
|
||||
ProfileEntry readAheadEntry = mEntries[readAheadPos];
|
||||
for (size_t pos = 0; pos < sizeof(void*); pos++) {
|
||||
tagBuff[tagBuffPos] = readAheadEntry.mTagChars[pos];
|
||||
if (tagBuff[tagBuffPos] == '\0' || tagBuffPos == DYNAMIC_MAX_STRING-2) {
|
||||
seenNullByte = true;
|
||||
break;
|
||||
}
|
||||
tagBuffPos++;
|
||||
}
|
||||
if (!seenNullByte)
|
||||
readAheadPos = (readAheadPos + 1) % mEntrySize;
|
||||
}
|
||||
return tagBuff;
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, const ThreadProfile& profile);
|
||||
|
||||
JSObject *ToJSObject(JSContext *aCx)
|
||||
@ -241,11 +267,25 @@ public:
|
||||
|
||||
int readPos = mReadPos;
|
||||
while (readPos != mLastFlushPos) {
|
||||
// Number of tag consumed
|
||||
int incBy = 1;
|
||||
ProfileEntry entry = mEntries[readPos];
|
||||
|
||||
// Read ahead to the next tag, if it's a 'd' tag process it now
|
||||
const char* tagStringData = entry.mTagData;
|
||||
int readAheadPos = (readPos + 1) % mEntrySize;
|
||||
char tagBuff[DYNAMIC_MAX_STRING];
|
||||
// Make sure the string is always null terminated if it fills up DYNAMIC_MAX_STRING-2
|
||||
tagBuff[DYNAMIC_MAX_STRING-1] = '\0';
|
||||
|
||||
if (readAheadPos != mLastFlushPos && mEntries[readAheadPos].mTagName == 'd') {
|
||||
tagStringData = processDynamicTag(readPos, &incBy, tagBuff);
|
||||
}
|
||||
|
||||
switch (entry.mTagName) {
|
||||
case 's':
|
||||
sample = b.CreateObject();
|
||||
b.DefineProperty(sample, "name", (const char*)entry.mTagData);
|
||||
b.DefineProperty(sample, "name", tagStringData);
|
||||
frames = b.CreateArray();
|
||||
b.DefineProperty(sample, "frames", frames);
|
||||
b.ArrayPush(samples, sample);
|
||||
@ -255,18 +295,21 @@ public:
|
||||
{
|
||||
if (sample) {
|
||||
JSObject *frame = b.CreateObject();
|
||||
char tagBuff[1024];
|
||||
// Bug 753041
|
||||
// We need a double cast here to tell GCC that we don't want to sign
|
||||
// extend 32-bit addresses starting with 0xFXXXXXX.
|
||||
unsigned long long pc = (unsigned long long)(uintptr_t)entry.mTagPtr;
|
||||
snprintf(tagBuff, 1024, "%#llx", pc);
|
||||
b.DefineProperty(frame, "location", tagBuff);
|
||||
if (entry.mTagName == 'l') {
|
||||
// Bug 753041
|
||||
// We need a double cast here to tell GCC that we don't want to sign
|
||||
// extend 32-bit addresses starting with 0xFXXXXXX.
|
||||
unsigned long long pc = (unsigned long long)(uintptr_t)entry.mTagPtr;
|
||||
snprintf(tagBuff, DYNAMIC_MAX_STRING, "%#llx", pc);
|
||||
b.DefineProperty(frame, "location", tagBuff);
|
||||
} else {
|
||||
b.DefineProperty(frame, "location", tagStringData);
|
||||
}
|
||||
b.ArrayPush(frames, frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
readPos = (readPos + 1) % mEntrySize;
|
||||
readPos = (readPos + incBy) % mEntrySize;
|
||||
}
|
||||
|
||||
return profile;
|
||||
@ -560,11 +603,30 @@ void doSampleStackTrace(ProfileStack *aStack, ThreadProfile &aProfile, TickSampl
|
||||
// Sample
|
||||
// 's' tag denotes the start of a sample block
|
||||
// followed by 0 or more 'c' tags.
|
||||
aProfile.addTag(ProfileEntry('s', "(root)"));
|
||||
for (mozilla::sig_safe_t i = 0; i < aStack->mStackPointer; i++) {
|
||||
if (i == 0) {
|
||||
aProfile.addTag(ProfileEntry('s', aStack->mStack[i]));
|
||||
// First entry has tagName 's' (start)
|
||||
// Check for magic pointer bit 1 to indicate copy
|
||||
const char* sampleLabel = aStack->mStack[i].mLabel;
|
||||
if (aStack->mStack[i].isCopyLabel()) {
|
||||
// Store the string using 1 or more 'd' (dynamic) tags
|
||||
// that will happen to the preceding tag
|
||||
|
||||
aProfile.addTag(ProfileEntry('c', ""));
|
||||
// Add one to store the null termination
|
||||
size_t strLen = strlen(sampleLabel) + 1;
|
||||
for (size_t j = 0; j < strLen;) {
|
||||
// Store as many characters in the void* as the platform allows
|
||||
char text[sizeof(void*)];
|
||||
for (size_t pos = 0; pos < sizeof(void*) && j+pos < strLen; pos++) {
|
||||
text[pos] = sampleLabel[j+pos];
|
||||
}
|
||||
j += sizeof(void*);
|
||||
// Take '*((void**)(&text[0]))' to pass the char[] as a single void*
|
||||
aProfile.addTag(ProfileEntry('d', *((void**)(&text[0]))));
|
||||
}
|
||||
} else {
|
||||
aProfile.addTag(ProfileEntry('c', aStack->mStack[i]));
|
||||
aProfile.addTag(ProfileEntry('c', sampleLabel));
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_SPS_LEAF_DATA
|
||||
@ -657,6 +719,8 @@ std::ostream& operator<<(std::ostream& stream, const ProfileEntry& entry)
|
||||
unsigned long long pc = (unsigned long long)(uintptr_t)entry.mTagPtr;
|
||||
snprintf(tagBuff, 1024, "l-%#llx\n", pc);
|
||||
stream << tagBuff;
|
||||
} else if (entry.mTagName == 'd') {
|
||||
// TODO implement 'd' tag for text profile
|
||||
} else {
|
||||
stream << entry.mTagName << "-" << entry.mTagData << "\n";
|
||||
}
|
||||
|
@ -71,6 +71,11 @@
|
||||
#define SAMPLER_GET_RESPONSIVENESS() NULL
|
||||
#define SAMPLER_GET_FEATURES() NULL
|
||||
#define SAMPLE_LABEL(name_space, info)
|
||||
// Provide a default literal string to use if profiling is disabled
|
||||
// and a printf argument to be computed if profiling is enabled.
|
||||
// NOTE: This will store the formated string on the stack and consume
|
||||
// over 128 bytes on the stack.
|
||||
#define SAMPLE_LABEL_PRINTF(name_space, info, format, ...)
|
||||
#define SAMPLE_LABEL_FN(name_space, info)
|
||||
#define SAMPLE_MARKER(info)
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include "mozilla/ThreadLocal.h"
|
||||
#include "nscore.h"
|
||||
#include "jsapi.h"
|
||||
@ -50,6 +51,7 @@ extern bool stack_key_initialized;
|
||||
#define SAMPLER_APPEND_LINE_NUMBER(id) SAMPLER_APPEND_LINE_NUMBER_EXPAND(id, __LINE__)
|
||||
|
||||
#define SAMPLE_LABEL(name_space, info) mozilla::SamplerStackFrameRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info)
|
||||
#define SAMPLE_LABEL_PRINTF(name_space, info, format, ...) mozilla::SamplerStackFramePrintfRAII SAMPLER_APPEND_LINE_NUMBER(sampler_raii)(name_space "::" info, format, __VA_ARGS__)
|
||||
#define SAMPLE_MARKER(info) mozilla_sampler_add_marker(info)
|
||||
|
||||
/* we duplicate this code here to avoid header dependencies
|
||||
@ -124,7 +126,7 @@ LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
|
||||
|
||||
// Returns a handdle to pass on exit. This can check that we are popping the
|
||||
// correct callstack.
|
||||
inline void* mozilla_sampler_call_enter(const char *aInfo);
|
||||
inline void* mozilla_sampler_call_enter(const char *aInfo, void *aFrameAddress = NULL, bool aCopy = false);
|
||||
inline void mozilla_sampler_call_exit(void* handle);
|
||||
inline void mozilla_sampler_add_marker(const char *aInfo);
|
||||
|
||||
@ -154,8 +156,67 @@ private:
|
||||
void* mHandle;
|
||||
};
|
||||
|
||||
static const int SAMPLER_MAX_STRING = 128;
|
||||
class NS_STACK_CLASS SamplerStackFramePrintfRAII {
|
||||
public:
|
||||
// we only copy the strings at save time, so to take multiple parameters we'd need to copy them then.
|
||||
SamplerStackFramePrintfRAII(const char *aDefault, const char *aFormat, ...) {
|
||||
if (mozilla_sampler_is_active()) {
|
||||
va_list args;
|
||||
va_start(args, aFormat);
|
||||
char buff[SAMPLER_MAX_STRING];
|
||||
|
||||
// We have to use seperate printf's because we're using
|
||||
// the vargs.
|
||||
#if _MSC_VER
|
||||
_vsnprintf(buff, SAMPLER_MAX_STRING, aFormat, args);
|
||||
_snprintf(mDest, SAMPLER_MAX_STRING, "%s %s", aDefault, buff);
|
||||
#else
|
||||
vsnprintf(buff, SAMPLER_MAX_STRING, aFormat, args);
|
||||
snprintf(mDest, SAMPLER_MAX_STRING, "%s %s", aDefault, buff);
|
||||
#endif
|
||||
mHandle = mozilla_sampler_call_enter(mDest, this, true);
|
||||
va_end(args);
|
||||
} else {
|
||||
mHandle = mozilla_sampler_call_enter(aDefault);
|
||||
}
|
||||
}
|
||||
~SamplerStackFramePrintfRAII() {
|
||||
mozilla_sampler_call_exit(mHandle);
|
||||
}
|
||||
private:
|
||||
char mDest[SAMPLER_MAX_STRING];
|
||||
void* mHandle;
|
||||
};
|
||||
|
||||
} //mozilla
|
||||
|
||||
class StackEntry
|
||||
{
|
||||
public:
|
||||
// Encode the address and aCopy by dropping the last bit of aStackAddress
|
||||
// and storing aCopy there.
|
||||
static const void* EncodeStackAddress(const void* aStackAddress, bool aCopy) {
|
||||
aStackAddress = reinterpret_cast<const void*>(
|
||||
reinterpret_cast<uintptr_t>(aStackAddress) & ~0x1);
|
||||
if (!aCopy)
|
||||
aStackAddress = reinterpret_cast<const void*>(
|
||||
reinterpret_cast<uintptr_t>(aStackAddress) | 0x1);
|
||||
return aStackAddress;
|
||||
}
|
||||
|
||||
bool isCopyLabel() const volatile {
|
||||
return !((uintptr_t)mStackAddress & 0x1);
|
||||
}
|
||||
|
||||
const char* mLabel;
|
||||
// Tagged pointer. Less significant bit used to
|
||||
// track if mLabel needs a copy. Note that we don't
|
||||
// need the last bit of the stack address for proper ordering.
|
||||
// Last bit 1 = Don't copy, Last bit 0 = Copy.
|
||||
const void* mStackAddress;
|
||||
};
|
||||
|
||||
// the SamplerStack members are read by signal
|
||||
// handlers, so the mutation of them needs to be signal-safe.
|
||||
struct ProfileStack
|
||||
@ -191,7 +252,7 @@ public:
|
||||
clearMarkers();
|
||||
}
|
||||
if (aMarkerId < 0 ||
|
||||
static_cast<mozilla::sig_safe_t>(aMarkerId) >= mMarkerPointer) {
|
||||
static_cast<mozilla::sig_safe_t>(aMarkerId) >= mMarkerPointer) {
|
||||
return NULL;
|
||||
}
|
||||
return mMarkers[aMarkerId];
|
||||
@ -205,6 +266,11 @@ public:
|
||||
}
|
||||
|
||||
void push(const char *aName)
|
||||
{
|
||||
push(aName, NULL, false);
|
||||
}
|
||||
|
||||
void push(const char *aName, void *aStackAddress, bool aCopy)
|
||||
{
|
||||
if (size_t(mStackPointer) >= mozilla::ArrayLength(mStack)) {
|
||||
mDroppedStackEntries++;
|
||||
@ -213,7 +279,9 @@ public:
|
||||
|
||||
// Make sure we increment the pointer after the name has
|
||||
// been written such that mStack is always consistent.
|
||||
mStack[mStackPointer] = aName;
|
||||
mStack[mStackPointer].mLabel = aName;
|
||||
mStack[mStackPointer].mStackAddress = StackEntry::EncodeStackAddress(aStackAddress, aCopy);
|
||||
|
||||
// Prevent the optimizer from re-ordering these instructions
|
||||
STORE_SEQUENCER();
|
||||
mStackPointer++;
|
||||
@ -232,7 +300,7 @@ public:
|
||||
}
|
||||
|
||||
// Keep a list of active checkpoints
|
||||
char const * volatile mStack[1024];
|
||||
StackEntry volatile mStack[1024];
|
||||
// Keep a list of active markers to be applied to the next sample taken
|
||||
char const * volatile mMarkers[1024];
|
||||
volatile mozilla::sig_safe_t mStackPointer;
|
||||
@ -243,7 +311,7 @@ public:
|
||||
volatile mozilla::sig_safe_t mQueueClearMarker;
|
||||
};
|
||||
|
||||
inline void* mozilla_sampler_call_enter(const char *aInfo)
|
||||
inline void* mozilla_sampler_call_enter(const char *aInfo, void *aFrameAddress, bool aCopy)
|
||||
{
|
||||
// check if we've been initialized to avoid calling pthread_getspecific
|
||||
// with a null tlsStack which will return undefined results.
|
||||
@ -258,7 +326,7 @@ inline void* mozilla_sampler_call_enter(const char *aInfo)
|
||||
if (!stack) {
|
||||
return stack;
|
||||
}
|
||||
stack->push(aInfo);
|
||||
stack->push(aInfo, aFrameAddress, aCopy);
|
||||
|
||||
// The handle is meant to support future changes
|
||||
// but for now it is simply use to save a call to
|
||||
|
Loading…
Reference in New Issue
Block a user