summaryrefslogtreecommitdiffstats
path: root/mozglue/baseprofiler/core/ProfiledThreadData.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mozglue/baseprofiler/core/ProfiledThreadData.cpp')
-rw-r--r--mozglue/baseprofiler/core/ProfiledThreadData.cpp191
1 files changed, 191 insertions, 0 deletions
diff --git a/mozglue/baseprofiler/core/ProfiledThreadData.cpp b/mozglue/baseprofiler/core/ProfiledThreadData.cpp
new file mode 100644
index 0000000000..62cb994ae2
--- /dev/null
+++ b/mozglue/baseprofiler/core/ProfiledThreadData.cpp
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ProfiledThreadData.h"
+
+#include "BaseProfiler.h"
+#include "ProfileBuffer.h"
+
+#include "mozilla/BaseProfileJSONWriter.h"
+
+#if defined(GP_OS_darwin)
+# include <pthread.h>
+#endif
+
+namespace mozilla {
+namespace baseprofiler {
+
+ProfiledThreadData::ProfiledThreadData(ThreadInfo* aThreadInfo)
+ : mThreadInfo(aThreadInfo) {}
+
+ProfiledThreadData::~ProfiledThreadData() {}
+
+void ProfiledThreadData::StreamJSON(const ProfileBuffer& aBuffer,
+ SpliceableJSONWriter& aWriter,
+ const std::string& aProcessName,
+ const std::string& aETLDplus1,
+ const TimeStamp& aProcessStartTime,
+ double aSinceTime) {
+ UniqueStacks uniqueStacks;
+
+ aWriter.SetUniqueStrings(uniqueStacks.UniqueStrings());
+
+ aWriter.Start();
+ {
+ StreamSamplesAndMarkers(mThreadInfo->Name(), mThreadInfo->ThreadId(),
+ aBuffer, aWriter, aProcessName, aETLDplus1,
+ aProcessStartTime, mThreadInfo->RegisterTime(),
+ mUnregisterTime, aSinceTime, uniqueStacks);
+
+ aWriter.StartObjectProperty("stackTable");
+ {
+ {
+ JSONSchemaWriter schema(aWriter);
+ schema.WriteField("prefix");
+ schema.WriteField("frame");
+ }
+
+ aWriter.StartArrayProperty("data");
+ { uniqueStacks.SpliceStackTableElements(aWriter); }
+ aWriter.EndArray();
+ }
+ aWriter.EndObject();
+
+ aWriter.StartObjectProperty("frameTable");
+ {
+ {
+ JSONSchemaWriter schema(aWriter);
+ schema.WriteField("location");
+ schema.WriteField("relevantForJS");
+ schema.WriteField("innerWindowID");
+ schema.WriteField("implementation");
+ schema.WriteField("line");
+ schema.WriteField("column");
+ schema.WriteField("category");
+ schema.WriteField("subcategory");
+ }
+
+ aWriter.StartArrayProperty("data");
+ { uniqueStacks.SpliceFrameTableElements(aWriter); }
+ aWriter.EndArray();
+ }
+ aWriter.EndObject();
+
+ aWriter.StartArrayProperty("stringTable");
+ {
+ std::move(uniqueStacks.UniqueStrings())
+ .SpliceStringTableElements(aWriter);
+ }
+ aWriter.EndArray();
+ }
+ aWriter.End();
+
+ aWriter.ResetUniqueStrings();
+}
+
+BaseProfilerThreadId StreamSamplesAndMarkers(
+ const char* aName, BaseProfilerThreadId aThreadId,
+ const ProfileBuffer& aBuffer, SpliceableJSONWriter& aWriter,
+ const std::string& aProcessName, const std::string& aETLDplus1,
+ const TimeStamp& aProcessStartTime, const TimeStamp& aRegisterTime,
+ const TimeStamp& aUnregisterTime, double aSinceTime,
+ UniqueStacks& aUniqueStacks) {
+ BaseProfilerThreadId processedThreadId;
+
+ aWriter.StringProperty(
+ "processType",
+ "(unknown)" /* XRE_GeckoProcessTypeToString(XRE_GetProcessType()) */);
+
+ {
+ std::string name = aName;
+ // We currently need to distinguish threads output by Base Profiler from
+ // those in Gecko Profiler, as the frontend could get confused and lose
+ // tracks with the same name.
+ // TODO: As part of the profilers de-duplication, thread data from both
+ // profilers should end up in the same track, at which point this won't be
+ // necessary anymore. See meta bug 1557566.
+ name += " (pre-xul)";
+ aWriter.StringProperty("name", name);
+ }
+
+ // Use given process name (if any).
+ if (!aProcessName.empty()) {
+ aWriter.StringProperty("processName", aProcessName);
+ }
+ if (!aETLDplus1.empty()) {
+ aWriter.StringProperty("eTLD+1", aETLDplus1);
+ }
+
+ if (aRegisterTime) {
+ aWriter.DoubleProperty(
+ "registerTime", (aRegisterTime - aProcessStartTime).ToMilliseconds());
+ } else {
+ aWriter.NullProperty("registerTime");
+ }
+
+ if (aUnregisterTime) {
+ aWriter.DoubleProperty(
+ "unregisterTime",
+ (aUnregisterTime - aProcessStartTime).ToMilliseconds());
+ } else {
+ aWriter.NullProperty("unregisterTime");
+ }
+
+ aWriter.StartObjectProperty("samples");
+ {
+ {
+ JSONSchemaWriter schema(aWriter);
+ schema.WriteField("stack");
+ schema.WriteField("time");
+ schema.WriteField("eventDelay");
+ }
+
+ aWriter.StartArrayProperty("data");
+ {
+ processedThreadId = aBuffer.StreamSamplesToJSON(
+ aWriter, aThreadId, aSinceTime, aUniqueStacks);
+ }
+ aWriter.EndArray();
+ }
+ aWriter.EndObject();
+
+ aWriter.StartObjectProperty("markers");
+ {
+ {
+ JSONSchemaWriter schema(aWriter);
+ schema.WriteField("name");
+ schema.WriteField("startTime");
+ schema.WriteField("endTime");
+ schema.WriteField("phase");
+ schema.WriteField("category");
+ schema.WriteField("data");
+ }
+
+ aWriter.StartArrayProperty("data");
+ {
+ aBuffer.StreamMarkersToJSON(aWriter, aThreadId, aProcessStartTime,
+ aSinceTime, aUniqueStacks);
+ }
+ aWriter.EndArray();
+ }
+ aWriter.EndObject();
+
+ // Tech note: If `ToNumber()` returns a uint64_t, the conversion to int64_t is
+ // "implementation-defined" before C++20. This is acceptable here, because
+ // this is a one-way conversion to a unique identifier that's used to visually
+ // separate data by thread on the front-end.
+ aWriter.IntProperty(
+ "pid", static_cast<int64_t>(profiler_current_process_id().ToNumber()));
+ aWriter.IntProperty("tid",
+ static_cast<int64_t>(aThreadId.IsSpecified()
+ ? aThreadId.ToNumber()
+ : processedThreadId.ToNumber()));
+
+ return processedThreadId;
+}
+
+} // namespace baseprofiler
+} // namespace mozilla