void TelemetryImpl::RecordChromeHang(uint32_t duration, const Telemetry::HangStack &callStack, SharedLibraryInfo &moduleMap) { MOZ_ASSERT(sTelemetry); if (!sTelemetry->mCanRecord) { return; } MutexAutoLock hangReportMutex(sTelemetry->mHangReportsMutex); // Only report the modules which changed since the first hang report if (sTelemetry->mHangReports.Length()) { SharedLibraryInfo &firstModuleMap = sTelemetry->mHangReports[0].moduleMap; for (size_t i = 0; i < moduleMap.GetSize(); ++i) { if (firstModuleMap.Contains(moduleMap.GetEntry(i))) { moduleMap.RemoveEntries(i, i + 1); --i; } } } HangReport newReport = { duration, callStack, moduleMap }; sTelemetry->mHangReports.AppendElement(newReport); }
static void GetChromeHangReport(Telemetry::HangStack &callStack, SharedLibraryInfo &moduleMap) { MOZ_ASSERT(winMainThreadHandle); DWORD ret = ::SuspendThread(winMainThreadHandle); if (ret == -1) { callStack.Clear(); moduleMap.Clear(); return; } NS_StackWalk(ChromeStackWalker, 0, &callStack, reinterpret_cast<uintptr_t>(winMainThreadHandle)); ret = ::ResumeThread(winMainThreadHandle); if (ret == -1) { callStack.Clear(); moduleMap.Clear(); return; } moduleMap = SharedLibraryInfo::GetInfoForSelf(); moduleMap.SortByAddress(); // Remove all modules not referenced by a PC on the stack Telemetry::HangStack sortedStack = callStack; sortedStack.Sort(); size_t moduleIndex = 0; size_t stackIndex = 0; bool unreferencedModule = true; while (stackIndex < sortedStack.Length() && moduleIndex < moduleMap.GetSize()) { uintptr_t pc = sortedStack[stackIndex]; SharedLibrary& module = moduleMap.GetEntry(moduleIndex); uintptr_t moduleStart = module.GetStart(); uintptr_t moduleEnd = module.GetEnd() - 1; if (moduleStart <= pc && pc <= moduleEnd) { // If the current PC is within the current module, mark module as used unreferencedModule = false; ++stackIndex; } else if (pc > moduleEnd) { if (unreferencedModule) { // Remove module if no PCs within its address range moduleMap.RemoveEntries(moduleIndex, moduleIndex + 1); } else { // Module was referenced on stack, but current PC belongs to later module unreferencedModule = true; ++moduleIndex; } } else { // PC does not belong to any module ++stackIndex; } } // Clean up remaining unreferenced modules, i.e. module addresses > max(pc) if (moduleIndex + 1 < moduleMap.GetSize()) { moduleMap.RemoveEntries(moduleIndex + 1, moduleMap.GetSize()); } }
virtual const CodeModule* GetModuleAtIndex(unsigned int aIndex) const { const SharedLibrary& lib = mLibs.GetEntry(aIndex); mModule = new BasicCodeModule(lib.GetStart(), lib.GetEnd() - lib.GetStart(), lib.GetName(), lib.GetBreakpadId(), lib.GetName(), lib.GetBreakpadId(), ""); // Keep mModule valid until the next GetModuleAtIndex call. return mModule; }
std::string GetSharedLibraryInfoString() { SharedLibraryInfo info = SharedLibraryInfo::GetInfoForSelf(); if (info.GetSize() == 0) return "[]"; std::ostringstream os; os << "["; AddSharedLibraryInfoToStream(os, info.GetEntry(0)); for (size_t i = 1; i < info.GetSize(); i++) { os << ","; AddSharedLibraryInfoToStream(os, info.GetEntry(i)); } os << "]"; return os.str(); }