Bug 808699 - Change the wire format for hang reports. r=vladan.

This commit is contained in:
Rafael Ávila de Espíndola 2012-11-20 09:45:14 -05:00
parent 8738532f96
commit 785eb3f43f
5 changed files with 133 additions and 138 deletions

View File

@ -35,13 +35,6 @@ public:
// The file name, /foo/bar/libxul.so for example.
std::string mName;
// The address it was loaded to.
// FIXME: remove this once chrome hang has switched to using offsets.
uintptr_t mStart;
// The size of this mapping. May or may not be the entire file.
// FIXME: remove this. It was only used as a sanity check.
size_t mMappingSize;
// Windows specific fields. On other platforms they are 0/empty.
int mPdbAge;
std::string mPdbSignature;
@ -65,10 +58,8 @@ private:
// Get the current list of loaded modules, filter and pair it to the provided
// stack. We let the caller collect the stack since different callers have
// different needs (current thread X main thread, stopping the thread, etc).
// FIXME: remove the aRelative option once chrome hang has switched to using
// offsets.
ProcessedStack
GetStackAndModules(const std::vector<uintptr_t> &aPCs, bool aRelative);
GetStackAndModules(const std::vector<uintptr_t> &aPCs);
} // namespace Telemetry
} // namespace mozilla

View File

@ -1221,137 +1221,135 @@ NS_IMETHODIMP
TelemetryImpl::GetChromeHangs(JSContext *cx, jsval *ret)
{
MutexAutoLock hangReportMutex(mHangReportsMutex);
JSObject *fullReportObj = JS_NewObject(cx, nullptr, nullptr, nullptr);
if (!fullReportObj) {
return NS_ERROR_FAILURE;
}
*ret = OBJECT_TO_JSVAL(fullReportObj);
JSObject *moduleArray = JS_NewArrayObject(cx, 0, nullptr);
if (!moduleArray) {
return NS_ERROR_FAILURE;
}
JSBool ok = JS_DefineProperty(cx, fullReportObj, "memoryMap",
OBJECT_TO_JSVAL(moduleArray),
NULL, NULL, JSPROP_ENUMERATE);
if (!ok) {
return NS_ERROR_FAILURE;
}
const uint32_t moduleCount = mHangReports.GetModuleCount();
for (size_t moduleIndex = 0; moduleIndex < moduleCount; ++moduleIndex) {
// Current module
const Telemetry::ProcessedStack::Module& module =
mHangReports.GetModule(moduleIndex);
JSObject *moduleInfoArray = JS_NewArrayObject(cx, 0, nullptr);
if (!moduleInfoArray) {
return NS_ERROR_FAILURE;
}
jsval val = OBJECT_TO_JSVAL(moduleInfoArray);
if (!JS_SetElement(cx, moduleArray, moduleIndex, &val)) {
return NS_ERROR_FAILURE;
}
unsigned index = 0;
// Module name
JSString *str = JS_NewStringCopyZ(cx, module.mName.c_str());
if (!str) {
return NS_ERROR_FAILURE;
}
val = STRING_TO_JSVAL(str);
if (!JS_SetElement(cx, moduleInfoArray, index++, &val)) {
return NS_ERROR_FAILURE;
}
// "PDB Age" identifier
val = INT_TO_JSVAL(module.mPdbAge);
if (!JS_SetElement(cx, moduleInfoArray, index++, &val)) {
return NS_ERROR_FAILURE;
}
// "PDB Signature" GUID
str = JS_NewStringCopyZ(cx, module.mPdbSignature.c_str());
if (!str) {
return NS_ERROR_FAILURE;
}
val = STRING_TO_JSVAL(str);
if (!JS_SetElement(cx, moduleInfoArray, index++, &val)) {
return NS_ERROR_FAILURE;
}
// Name of associated PDB file
str = JS_NewStringCopyZ(cx, module.mPdbName.c_str());
if (!str) {
return NS_ERROR_FAILURE;
}
val = STRING_TO_JSVAL(str);
if (!JS_SetElement(cx, moduleInfoArray, index++, &val)) {
return NS_ERROR_FAILURE;
}
}
JSObject *reportArray = JS_NewArrayObject(cx, 0, nullptr);
if (!reportArray) {
return NS_ERROR_FAILURE;
}
*ret = OBJECT_TO_JSVAL(reportArray);
ok = JS_DefineProperty(cx, fullReportObj, "stacks",
OBJECT_TO_JSVAL(reportArray),
NULL, NULL, JSPROP_ENUMERATE);
if (!ok) {
return NS_ERROR_FAILURE;
}
// Each hang report is an object in the 'chromeHangs' array
for (size_t i = 0; i < mHangReports.GetStackCount(); ++i) {
const CombinedStacks::Stack &stack = mHangReports.GetStack(i);
JSObject *reportObj = JS_NewObject(cx, NULL, NULL, NULL);
if (!reportObj) {
return NS_ERROR_FAILURE;
}
jsval reportObjVal = OBJECT_TO_JSVAL(reportObj);
if (!JS_SetElement(cx, reportArray, i, &reportObjVal)) {
JSObject *durationArray = JS_NewArrayObject(cx, 0, nullptr);
ok = JS_DefineProperty(cx, fullReportObj, "durations",
OBJECT_TO_JSVAL(durationArray),
NULL, NULL, JSPROP_ENUMERATE);
if (!ok) {
return NS_ERROR_FAILURE;
}
for (size_t i = 0, n = mHangReports.GetStackCount(); i < n; ++i) {
jsval duration = INT_TO_JSVAL(mHangReports.GetDuration(i));
if (!JS_SetElement(cx, durationArray, i, &duration)) {
return NS_ERROR_FAILURE;
}
// Record the hang duration (expressed in seconds)
JSBool ok = JS_DefineProperty(cx, reportObj, "duration",
INT_TO_JSVAL(mHangReports.GetDuration(i)),
NULL, NULL, JSPROP_ENUMERATE);
if (!ok) {
return NS_ERROR_FAILURE;
}
// Represent call stack PCs as strings
// (JS can't represent all 64-bit integer values)
// Represent call stack PCs as (module index, offset) pairs.
JSObject *pcArray = JS_NewArrayObject(cx, 0, nullptr);
if (!pcArray) {
return NS_ERROR_FAILURE;
}
ok = JS_DefineProperty(cx, reportObj, "stack", OBJECT_TO_JSVAL(pcArray),
NULL, NULL, JSPROP_ENUMERATE);
if (!ok) {
jsval pcArrayVal = OBJECT_TO_JSVAL(pcArray);
if (!JS_SetElement(cx, reportArray, i, &pcArrayVal)) {
return NS_ERROR_FAILURE;
}
const CombinedStacks::Stack& stack = mHangReports.GetStack(i);
const uint32_t pcCount = stack.size();
for (size_t pcIndex = 0; pcIndex < pcCount; ++pcIndex) {
nsAutoCString pcString;
const Telemetry::ProcessedStack::Frame &Frame = stack[pcIndex];
pcString.AppendPrintf("0x%p", Frame.mOffset);
JSString *str = JS_NewStringCopyZ(cx, pcString.get());
if (!str) {
const Telemetry::ProcessedStack::Frame& frame = stack[pcIndex];
JSObject *framePair = JS_NewArrayObject(cx, 0, nullptr);
if (!framePair) {
return NS_ERROR_FAILURE;
}
jsval v = STRING_TO_JSVAL(str);
if (!JS_SetElement(cx, pcArray, pcIndex, &v)) {
int modIndex = (std::numeric_limits<uint16_t>::max() == frame.mModIndex) ?
-1 : frame.mModIndex;
jsval modIndexVal = INT_TO_JSVAL(modIndex);
if (!JS_SetElement(cx, framePair, 0, &modIndexVal)) {
return NS_ERROR_FAILURE;
}
}
// Record memory map info
JSObject *moduleArray = JS_NewArrayObject(cx, 0, nullptr);
if (!moduleArray) {
return NS_ERROR_FAILURE;
}
ok = JS_DefineProperty(cx, reportObj, "memoryMap",
OBJECT_TO_JSVAL(moduleArray),
NULL, NULL, JSPROP_ENUMERATE);
if (!ok) {
return NS_ERROR_FAILURE;
}
const uint32_t moduleCount = (i == 0) ? mHangReports.GetModuleCount() : 0;
for (size_t moduleIndex = 0; moduleIndex < moduleCount; ++moduleIndex) {
// Current module
const Telemetry::ProcessedStack::Module &module =
mHangReports.GetModule(moduleIndex);
JSObject *moduleInfoArray = JS_NewArrayObject(cx, 0, nullptr);
if (!moduleInfoArray) {
jsval mOffsetVal = INT_TO_JSVAL(frame.mOffset);
if (!JS_SetElement(cx, framePair, 1, &mOffsetVal)) {
return NS_ERROR_FAILURE;
}
jsval val = OBJECT_TO_JSVAL(moduleInfoArray);
if (!JS_SetElement(cx, moduleArray, moduleIndex, &val)) {
return NS_ERROR_FAILURE;
}
// Start address
nsAutoCString addressString;
addressString.AppendPrintf("0x%p", module.mStart);
JSString *str = JS_NewStringCopyZ(cx, addressString.get());
if (!str) {
return NS_ERROR_FAILURE;
}
val = STRING_TO_JSVAL(str);
if (!JS_SetElement(cx, moduleInfoArray, 0, &val)) {
return NS_ERROR_FAILURE;
}
// Module name
str = JS_NewStringCopyZ(cx, module.mName.c_str());
if (!str) {
return NS_ERROR_FAILURE;
}
val = STRING_TO_JSVAL(str);
if (!JS_SetElement(cx, moduleInfoArray, 1, &val)) {
return NS_ERROR_FAILURE;
}
// Module size in memory
val = INT_TO_JSVAL(int32_t(module.mMappingSize));
if (!JS_SetElement(cx, moduleInfoArray, 2, &val)) {
return NS_ERROR_FAILURE;
}
// "PDB Age" identifier
val = INT_TO_JSVAL(module.mPdbAge);
if (!JS_SetElement(cx, moduleInfoArray, 3, &val)) {
return NS_ERROR_FAILURE;
}
// "PDB Signature" GUID
str = JS_NewStringCopyZ(cx, module.mPdbSignature.c_str());
if (!str) {
return NS_ERROR_FAILURE;
}
val = STRING_TO_JSVAL(str);
if (!JS_SetElement(cx, moduleInfoArray, 4, &val)) {
return NS_ERROR_FAILURE;
}
// Name of associated PDB file
str = JS_NewStringCopyZ(cx, module.mPdbName.c_str());
if (!str) {
return NS_ERROR_FAILURE;
}
val = STRING_TO_JSVAL(str);
if (!JS_SetElement(cx, moduleInfoArray, 5, &val)) {
jsval framePairVal = OBJECT_TO_JSVAL(framePair);
if (!JS_SetElement(cx, pcArray, pcIndex, &framePairVal)) {
return NS_ERROR_FAILURE;
}
}
@ -1763,8 +1761,6 @@ void ProcessedStack::Clear() {
bool ProcessedStack::Module::operator==(const Module& aOther) const {
return mName == aOther.mName &&
mStart == aOther.mStart &&
mMappingSize == aOther.mMappingSize &&
mPdbAge == aOther.mPdbAge &&
mPdbSignature == aOther.mPdbSignature &&
mPdbName == aOther.mPdbName;
@ -1790,7 +1786,8 @@ static bool CompareByIndex(const StackFrame &a, const StackFrame &b)
}
#endif
ProcessedStack GetStackAndModules(const std::vector<uintptr_t> &aPCs, bool aRelative)
ProcessedStack
GetStackAndModules(const std::vector<uintptr_t>& aPCs)
{
std::vector<StackFrame> rawStack;
for (std::vector<uintptr_t>::const_iterator i = aPCs.begin(),
@ -1828,8 +1825,7 @@ ProcessedStack GetStackAndModules(const std::vector<uintptr_t> &aPCs, bool aRela
// If the current PC is within the current module, mark
// module as used
moduleReferenced = true;
if (aRelative)
rawStack[stackIndex].mPC -= moduleStart;
rawStack[stackIndex].mPC -= moduleStart;
rawStack[stackIndex].mModIndex = moduleIndex;
} else {
// PC does not belong to any module. It is probably from
@ -1870,8 +1866,6 @@ ProcessedStack GetStackAndModules(const std::vector<uintptr_t> &aPCs, bool aRela
const SharedLibrary &info = rawModules.GetEntry(i);
ProcessedStack::Module module = {
info.GetName(),
info.GetStart(),
info.GetEnd() - info.GetStart(),
#ifdef XP_WIN
info.GetPdbAge(),
"", // mPdbSignature

View File

@ -222,17 +222,19 @@ let ChromeHangs = {
document.getElementById("hide-symbols").classList.add("hidden");
let hangs = Telemetry.chromeHangs;
if (hangs.length == 0) {
let stacks = hangs.stacks;
if (stacks.length == 0) {
showEmptySectionMessage("chrome-hangs-section");
return;
}
this.renderMemoryMap(hangsDiv);
for (let i = 0; i < hangs.length; ++i) {
let currentHang = hangs[i];
this.renderHangHeader(hangsDiv, i + 1, currentHang.duration);
this.renderStack(hangsDiv, currentHang.stack)
let durations = hangs.durations;
for (let i = 0; i < stacks.length; ++i) {
let stack = stacks[i];
this.renderHangHeader(hangsDiv, i + 1, durations[i]);
this.renderStack(hangsDiv, stack)
}
},
@ -279,8 +281,9 @@ let ChromeHangs = {
aDiv.appendChild(document.createTextNode(this.memoryMapTitle));
aDiv.appendChild(document.createElement("br"));
let singleMemoryMap = Telemetry.chromeHangs[0].memoryMap;
for (let currentModule of singleMemoryMap) {
let hangs = Telemetry.chromeHangs;
let memoryMap = hangs.memoryMap;
for (let currentModule of memoryMap) {
aDiv.appendChild(document.createTextNode(currentModule.join(" ")));
aDiv.appendChild(document.createElement("br"));
}
@ -295,16 +298,21 @@ let ChromeHangs = {
let symbolServerURI =
getPref(PREF_SYMBOL_SERVER_URI, DEFAULT_SYMBOL_SERVER_URI);
let chromeHangsJSON = JSON.stringify(Telemetry.chromeHangs);
let hangs = Telemetry.chromeHangs;
let memoryMap = hangs.memoryMap;
let stacks = hangs.stacks;
let request = {"memoryMap" : memoryMap, "stacks" : stacks,
"version" : 2};
let requestJSON = JSON.stringify(request);
this.symbolRequest = XMLHttpRequest();
this.symbolRequest.open("POST", symbolServerURI, true);
this.symbolRequest.setRequestHeader("Content-type", "application/json");
this.symbolRequest.setRequestHeader("Content-length", chromeHangsJSON.length);
this.symbolRequest.setRequestHeader("Content-length", requestJSON.length);
this.symbolRequest.setRequestHeader("Connection", "close");
this.symbolRequest.onreadystatechange = this.handleSymbolResponse.bind(this);
this.symbolRequest.send(chromeHangsJSON);
this.symbolRequest.send(requestJSON);
},
/**
@ -335,9 +343,11 @@ let ChromeHangs = {
}
let hangs = Telemetry.chromeHangs;
let stacks = hangs.stacks;
let durations = hangs.durations;
for (let i = 0; i < jsonResponse.length; ++i) {
let stack = jsonResponse[i];
let hangDuration = hangs[i].duration;
let hangDuration = durations[i];
this.renderHangHeader(hangsDiv, i + 1, hangDuration);
for (let symbol of stack) {

View File

@ -96,7 +96,7 @@ bool ValidWriteAssert(bool ok)
std::vector<uintptr_t> rawStack;
NS_StackWalk(RecordStackWalker, 0, reinterpret_cast<void*>(&rawStack), 0);
Telemetry::ProcessedStack stack = Telemetry::GetStackAndModules(rawStack, true);
Telemetry::ProcessedStack stack = Telemetry::GetStackAndModules(rawStack);
nsPrintfCString nameAux("%s%s", sProfileDirectory,
"/Telemetry.LateWriteTmpXXXXXX");

View File

@ -138,7 +138,7 @@ GetChromeHangReport(Telemetry::ProcessedStack &aStack)
ret = ::ResumeThread(winMainThreadHandle);
if (ret == -1)
return;
aStack = Telemetry::GetStackAndModules(rawStack, false);
aStack = Telemetry::GetStackAndModules(rawStack);
}
#endif