static typename Builder::Object BuildJavaThreadJSObject(Builder& b) { typename Builder::RootedObject javaThread(b.context(), b.CreateObject()); b.DefineProperty(javaThread, "name", "Java Main Thread"); typename Builder::RootedArray samples(b.context(), b.CreateArray()); b.DefineProperty(javaThread, "samples", samples); int sampleId = 0; while (true) { int frameId = 0; typename Builder::RootedObject sample(b.context()); typename Builder::RootedArray frames(b.context()); while (true) { nsCString result; bool hasFrame = AndroidBridge::Bridge()->GetFrameNameJavaProfiling(0, sampleId, frameId, result); if (!hasFrame) { if (frames) { b.DefineProperty(sample, "frames", frames); } break; } if (!sample) { sample = b.CreateObject(); frames = b.CreateArray(); b.DefineProperty(sample, "frames", frames); b.ArrayPush(samples, sample); double sampleTime = AndroidBridge::Bridge()->GetSampleTimeJavaProfiling(0, sampleId); b.DefineProperty(sample, "time", sampleTime); } typename Builder::RootedObject frame(b.context(), b.CreateObject()); b.DefineProperty(frame, "location", result.BeginReading()); b.ArrayPush(frames, frame); frameId++; } if (frameId == 0) { break; } sampleId++; } return javaThread; }
typename Builder::Object ProfilerMarkerImagePayload::preparePayloadImp(Builder& b) { typename Builder::RootedObject data(b.context(), b.CreateObject()); prepareCommonProps("innerHTML", b, data); // TODO: Finish me //b.DefineProperty(data, "innerHTML", "<img src=''/>"); return data; }
template<typename Builder> typename Builder::Object IOMarkerPayload::preparePayloadImp(Builder& b) { typename Builder::RootedObject data(b.context(), b.CreateObject()); prepareCommonProps("io", b, data); b.DefineProperty(data, "source", mSource); return data; }
typename Builder::Object TableTicker::GetMetaJSCustomObject(Builder& b) { typename Builder::RootedObject meta(b.context(), b.CreateObject()); b.DefineProperty(meta, "version", 2); b.DefineProperty(meta, "interval", interval()); b.DefineProperty(meta, "stackwalk", mUseStackWalk); b.DefineProperty(meta, "jank", mJankOnly); b.DefineProperty(meta, "processType", XRE_GetProcessType()); TimeDuration delta = TimeStamp::Now() - sStartTime; b.DefineProperty(meta, "startTime", PR_Now()/1000.0 - delta.ToMilliseconds()); nsresult res; nsCOMPtr<nsIHttpProtocolHandler> http = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &res); if (!NS_FAILED(res)) { nsAutoCString string; res = http->GetPlatform(string); if (!NS_FAILED(res)) b.DefineProperty(meta, "platform", string.Data()); res = http->GetOscpu(string); if (!NS_FAILED(res)) b.DefineProperty(meta, "oscpu", string.Data()); res = http->GetMisc(string); if (!NS_FAILED(res)) b.DefineProperty(meta, "misc", string.Data()); } nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1"); if (runtime) { nsAutoCString string; res = runtime->GetXPCOMABI(string); if (!NS_FAILED(res)) b.DefineProperty(meta, "abi", string.Data()); res = runtime->GetWidgetToolkit(string); if (!NS_FAILED(res)) b.DefineProperty(meta, "toolkit", string.Data()); } nsCOMPtr<nsIXULAppInfo> appInfo = do_GetService("@mozilla.org/xre/app-info;1"); if (appInfo) { nsAutoCString string; res = appInfo->GetName(string); if (!NS_FAILED(res)) b.DefineProperty(meta, "product", string.Data()); } return meta; }
void TableTicker::BuildJSObject(Builder& b, typename Builder::ObjectHandle profile) { // Put shared library info b.DefineProperty(profile, "libs", GetSharedLibraryInfoString().c_str()); // Put meta data typename Builder::RootedObject meta(b.context(), GetMetaJSCustomObject(b)); b.DefineProperty(profile, "meta", meta); // Lists the samples for each ThreadProfile typename Builder::RootedArray threads(b.context(), b.CreateArray()); b.DefineProperty(profile, "threads", threads); SetPaused(true); { mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex); for (size_t i = 0; i < sRegisteredThreads->size(); i++) { // Thread not being profiled, skip it if (!sRegisteredThreads->at(i)->Profile()) continue; MutexAutoLock lock(*sRegisteredThreads->at(i)->Profile()->GetMutex()); typename Builder::RootedObject threadSamples(b.context(), b.CreateObject()); sRegisteredThreads->at(i)->Profile()->BuildJSObject(b, threadSamples); b.ArrayPush(threads, threadSamples); } } #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) if (ProfileJava()) { AndroidBridge::Bridge()->PauseJavaProfiling(); typename Builder::RootedObject javaThread(b.context(), BuildJavaThreadJSObject(b)); b.ArrayPush(threads, javaThread); AndroidBridge::Bridge()->UnpauseJavaProfiling(); } #endif SetPaused(false); // Send a event asking any subprocesses (plugins) to // give us their information SubprocessClosure<Builder> closure(&b, threads); nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); if (os) { nsRefPtr<ProfileSaveEvent> pse = new ProfileSaveEvent(SubProcessCallback<Builder>, &closure); os->NotifyObservers(pse, "profiler-subprocess", nullptr); } }
template<typename Builder> void ProfilerMarker::BuildJSObject(Builder& b, typename Builder::ArrayHandle markers) const { typename Builder::RootedObject marker(b.context(), b.CreateObject()); b.DefineProperty(marker, "name", GetMarkerName()); // TODO: Store the callsite for this marker if available: // if have location data // b.DefineProperty(marker, "location", ...); if (mPayload) { typename Builder::RootedObject markerData(b.context(), mPayload->PreparePayload(b)); b.DefineProperty(marker, "data", markerData); } b.ArrayPush(markers, marker); }
typename Builder::Object ProfilerMarkerTracing::preparePayloadImp(Builder& b) { typename Builder::RootedObject data(b.context(), b.CreateObject()); prepareCommonProps("tracing", b, data); if (GetCategory()) { b.DefineProperty(data, "category", GetCategory()); } if (GetMetaData() != TRACING_DEFAULT) { if (GetMetaData() == TRACING_INTERVAL_START) { b.DefineProperty(data, "interval", "start"); } else if (GetMetaData() == TRACING_INTERVAL_END) { b.DefineProperty(data, "interval", "end"); } } return data; }
template<typename Builder> void ProfilerMarkerPayload::prepareCommonProps(const char* aMarkerType, Builder& aBuilder, typename Builder::ObjectHandle aObject) { MOZ_ASSERT(aMarkerType); aBuilder.DefineProperty(aObject, "type", aMarkerType); if (!mStartTime.IsNull()) { aBuilder.DefineProperty(aObject, "startTime", profiler_time(mStartTime)); } if (!mEndTime.IsNull()) { aBuilder.DefineProperty(aObject, "endTime", profiler_time(mEndTime)); } if (mStack) { typename Builder::RootedObject stack(aBuilder.context(), aBuilder.CreateObject()); aBuilder.DefineProperty(aObject, "stack", stack); mStack->BuildJSObject(aBuilder, stack); } }
void ThreadProfile::BuildJSObject(Builder& b, typename Builder::ObjectHandle profile) { // Thread meta data if (XRE_GetProcessType() == GeckoProcessType_Plugin) { // TODO Add the proper plugin name b.DefineProperty(profile, "name", "Plugin"); } else { b.DefineProperty(profile, "name", mName); } b.DefineProperty(profile, "tid", static_cast<int>(mThreadId)); typename Builder::RootedArray samples(b.context(), b.CreateArray()); b.DefineProperty(profile, "samples", samples); typename Builder::RootedObject sample(b.context()); typename Builder::RootedArray frames(b.context()); typename Builder::RootedArray markers(b.context()); 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 'm': { if (sample) { if (!markers) { markers = b.CreateArray(); b.DefineProperty(sample, "marker", markers); } entry.getMarker()->BuildJSObject(b, markers); } } break; case 'r': { if (sample) { b.DefineProperty(sample, "responsiveness", entry.mTagFloat); } } break; case 'p': { if (sample) { b.DefineProperty(sample, "power", entry.mTagFloat); } } break; case 'f': { if (sample) { b.DefineProperty(sample, "frameNumber", entry.mTagLine); } } break; case 't': { if (sample) { b.DefineProperty(sample, "time", entry.mTagFloat); } } break; case 's': sample = b.CreateObject(); b.DefineProperty(sample, "name", tagStringData); frames = b.CreateArray(); b.DefineProperty(sample, "frames", frames); b.ArrayPush(samples, sample); // Created lazily markers = nullptr; // Fall though to create a label for the 's' tag case 'c': case 'l': { if (sample) { typename Builder::RootedObject frame(b.context(), b.CreateObject()); 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); readAheadPos = (readPos + incBy) % mEntrySize; if (readAheadPos != mLastFlushPos && mEntries[readAheadPos].mTagName == 'n') { b.DefineProperty(frame, "line", mEntries[readAheadPos].mTagLine); incBy++; } } b.ArrayPush(frames, frame); } } } readPos = (readPos + incBy) % mEntrySize; } }