Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/tools/profiler/core/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 17 kB image not shown  

Quelle  ProfiledThreadData.cpp   Sprache: C

 
/* -*- 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 "platform.h"
#include "ProfileBuffer.h"

#include "mozilla/OriginAttributes.h"
#include "mozilla/Span.h"
#include "nsXULAppAPI.h"

#if defined(GP_OS_darwin)
#  include <pthread.h>
#endif

using namespace mozilla::literals::ProportionValue_literals;

ProfiledThreadData::ProfiledThreadData(
    const mozilla::profiler::ThreadRegistrationInfo& aThreadInfo)
    : mThreadInfo(aThreadInfo.Name(), aThreadInfo.ThreadId(),
                  aThreadInfo.IsMainThread(), aThreadInfo.RegisterTime()) {
  MOZ_COUNT_CTOR(ProfiledThreadData);
}

ProfiledThreadData::ProfiledThreadData(
    mozilla::profiler::ThreadRegistrationInfo&& aThreadInfo)
    : mThreadInfo(std::move(aThreadInfo)) {
  MOZ_COUNT_CTOR(ProfiledThreadData);
}

ProfiledThreadData::~ProfiledThreadData() {
  MOZ_COUNT_DTOR(ProfiledThreadData);
}

static void StreamTables(UniqueStacks&& aUniqueStacks, JSContext* aCx,
                         SpliceableJSONWriter& aWriter,
                         const mozilla::TimeStamp& aProcessStartTime,
                         mozilla::ProgressLogger aProgressLogger) {
  aWriter.StartObjectProperty("stackTable");
  {
    {
      JSONSchemaWriter schema(aWriter);
      schema.WriteField("prefix");
      schema.WriteField("frame");
    }

    aWriter.StartArrayProperty("data");
    {
      aProgressLogger.SetLocalProgress(1_pc, "Splicing stack table...");
      aUniqueStacks.SpliceStackTableElements(aWriter);
      aProgressLogger.SetLocalProgress(30_pc, "Spliced stack table");
    }
    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");
    {
      aProgressLogger.SetLocalProgress(30_pc, "Splicing frame table...");
      aUniqueStacks.SpliceFrameTableElements(aWriter);
      aProgressLogger.SetLocalProgress(60_pc, "Spliced frame table");
    }
    aWriter.EndArray();
  }
  aWriter.EndObject();

  aWriter.StartArrayProperty("stringTable");
  {
    aProgressLogger.SetLocalProgress(60_pc, "Splicing string table...");
    std::move(aUniqueStacks.UniqueStrings()).SpliceStringTableElements(aWriter);
    aProgressLogger.SetLocalProgress(90_pc, "Spliced string table");
  }
  aWriter.EndArray();
}

mozilla::NotNull<mozilla::UniquePtr<UniqueStacks>>
ProfiledThreadData::PrepareUniqueStacks(
    const ProfileBuffer& aBuffer, JSContext* aCx,
    mozilla::FailureLatch& aFailureLatch, ProfilerCodeAddressService* aService,
    mozilla::ProgressLogger aProgressLogger) {
  if (mJITFrameInfoForPreviousJSContexts &&
      mJITFrameInfoForPreviousJSContexts->HasExpired(
          aBuffer.BufferRangeStart())) {
    mJITFrameInfoForPreviousJSContexts = nullptr;
  }
  aProgressLogger.SetLocalProgress(1_pc, "Checked JIT frame info presence");

  // If we have an existing JITFrameInfo in mJITFrameInfoForPreviousJSContexts,
  // copy the data from it.
  JITFrameInfo jitFrameInfo =
      mJITFrameInfoForPreviousJSContexts
          ? JITFrameInfo(*mJITFrameInfoForPreviousJSContexts,
                         aProgressLogger.CreateSubLoggerTo(
                             "Retrieving JIT frame info...", 10_pc,
                             "Retrieved JIT frame info"))
          : JITFrameInfo();

  if (aCx && mBufferPositionWhenReceivedJSContext) {
    aBuffer.AddJITInfoForRange(
        *mBufferPositionWhenReceivedJSContext, mThreadInfo.ThreadId(), aCx,
        jitFrameInfo,
        aProgressLogger.CreateSubLoggerTo("Adding JIT info...", 90_pc,
                                          "Added JIT info"));
  } else {
    aProgressLogger.SetLocalProgress(90_pc, "No JIT info");
  }

  return mozilla::MakeNotNull<mozilla::UniquePtr<UniqueStacks>>(
      aFailureLatch, std::move(jitFrameInfo), aService);
}

void ProfiledThreadData::StreamJSON(
    const ProfileBuffer& aBuffer, JSContext* aCx, SpliceableJSONWriter& aWriter,
    const nsACString& aProcessName, const nsACString& aETLDplus1,
    const mozilla::TimeStamp& aProcessStartTime, double aSinceTime,
    ProfilerCodeAddressService* aService,
    mozilla::ProgressLogger aProgressLogger) {
  mozilla::NotNull<mozilla::UniquePtr<UniqueStacks>> uniqueStacks =
      PrepareUniqueStacks(aBuffer, aCx, aWriter.SourceFailureLatch(), aService,
                          aProgressLogger.CreateSubLoggerFromTo(
                              0_pc, "Preparing unique stacks...", 10_pc,
                              "Prepared Unique stacks"));

  aWriter.SetUniqueStrings(uniqueStacks->UniqueStrings());

  aWriter.Start();
  {
    StreamSamplesAndMarkers(
        mThreadInfo.Name(), mThreadInfo.ThreadId(), aBuffer, aWriter,
        aProcessName, aETLDplus1, aProcessStartTime, mThreadInfo.RegisterTime(),
        mUnregisterTime, aSinceTime, *uniqueStacks,
        aProgressLogger.CreateSubLoggerTo(
            90_pc,
            "ProfiledThreadData::StreamJSON: Streamed samples and markers"));

    StreamTables(std::move(*uniqueStacks), aCx, aWriter, aProcessStartTime,
                 aProgressLogger.CreateSubLoggerTo(
                     99_pc, "Streamed tables and trace logger"));
  }
  aWriter.End();

  aWriter.ResetUniqueStrings();
}

void ProfiledThreadData::StreamJSON(
    ThreadStreamingContext&& aThreadStreamingContext,
    SpliceableJSONWriter& aWriter, const nsACString& aProcessName,
    const nsACString& aETLDplus1, const mozilla::TimeStamp& aProcessStartTime,
    ProfilerCodeAddressService* aService,
    mozilla::ProgressLogger aProgressLogger) {
  aWriter.Start();
  {
    StreamSamplesAndMarkers(
        mThreadInfo.Name(), aThreadStreamingContext, aWriter, aProcessName,
        aETLDplus1, aProcessStartTime, mThreadInfo.RegisterTime(),
        mUnregisterTime,
        aProgressLogger.CreateSubLoggerFromTo(
            1_pc, "ProfiledThreadData::StreamJSON(context): Streaming...",
            90_pc,
            "ProfiledThreadData::StreamJSON(context): Streamed samples and "
            "markers"));

    StreamTables(
        std::move(*aThreadStreamingContext.mUniqueStacks),
        aThreadStreamingContext.mJSContext, aWriter, aProcessStartTime,
        aProgressLogger.CreateSubLoggerTo(
            "ProfiledThreadData::StreamJSON(context): Streaming tables...",
            99_pc, "ProfiledThreadData::StreamJSON(context): Streamed tables"));
  }
  aWriter.End();
}

// StreamSamplesDataCallback: (ProgressLogger) -> ProfilerThreadId
// StreamMarkersDataCallback: (ProgressLogger) -> void
// Returns the ProfilerThreadId returned by StreamSamplesDataCallback, which
// should be the thread id of the last sample that was processed (if any;
// otherwise it is left unspecified). This is mostly useful when the caller
// doesn't know where the sample comes from, e.g., when it's a backtrace in a
// marker.
template <typename StreamSamplesDataCallback,
          typename StreamMarkersDataCallback>
ProfilerThreadId DoStreamSamplesAndMarkers(
    const char* aName, SpliceableJSONWriter& aWriter,
    const nsACString& aProcessName, const nsACString& aETLDplus1,
    const mozilla::TimeStamp& aProcessStartTime,
    const mozilla::TimeStamp& aRegisterTime,
    const mozilla::TimeStamp& aUnregisterTime,
    mozilla::ProgressLogger aProgressLogger,
    StreamSamplesDataCallback&& aStreamSamplesDataCallback,
    StreamMarkersDataCallback&& aStreamMarkersDataCallback) {
  ProfilerThreadId processedThreadId;

  aWriter.StringProperty("processType",
                         mozilla::MakeStringSpan(XRE_GetProcessTypeString()));

  aWriter.StringProperty("name", mozilla::MakeStringSpan(aName));

  // Use given process name (if any), unless we're the parent process.
  if (XRE_IsParentProcess()) {
    aWriter.StringProperty("processName""Parent Process");
  } else if (!aProcessName.IsEmpty()) {
    aWriter.StringProperty("processName", aProcessName);
  }
  if (!aETLDplus1.IsEmpty()) {
    nsAutoCString originNoSuffix;
    mozilla::OriginAttributes attrs;
    if (!attrs.PopulateFromOrigin(aETLDplus1, originNoSuffix)) {
      aWriter.StringProperty("eTLD+1", aETLDplus1);
    } else {
      aWriter.StringProperty("eTLD+1", originNoSuffix);
      aWriter.BoolProperty("isPrivateBrowsing", attrs.IsPrivateBrowsing());
      aWriter.IntProperty("userContextId", attrs.mUserContextId);
    }
  }

  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");
#define RUNNING_TIME_FIELD(index, name, unit, jsonProperty) \
  schema.WriteField(#jsonProperty);
      PROFILER_FOR_EACH_RUNNING_TIME(RUNNING_TIME_FIELD)
#undef RUNNING_TIME_FIELD
    }

    aWriter.StartArrayProperty("data");
    {
      processedThreadId = std::forward<StreamSamplesDataCallback>(
          aStreamSamplesDataCallback)(aProgressLogger.CreateSubLoggerFromTo(
          1_pc, "Streaming samples...", 49_pc, "Streamed samples"));
    }
    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");
    {
      std::forward<StreamMarkersDataCallback>(aStreamMarkersDataCallback)(
          aProgressLogger.CreateSubLoggerFromTo(50_pc, "Streaming markers...",
                                                99_pc, "Streamed markers"));
    }
    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>(processedThreadId.ToNumber()));

  return processedThreadId;
}

ProfilerThreadId StreamSamplesAndMarkers(
    const char* aName, ProfilerThreadId aThreadId, const ProfileBuffer& aBuffer,
    SpliceableJSONWriter& aWriter, const nsACString& aProcessName,
    const nsACString& aETLDplus1, const mozilla::TimeStamp& aProcessStartTime,
    const mozilla::TimeStamp& aRegisterTime,
    const mozilla::TimeStamp& aUnregisterTime, double aSinceTime,
    UniqueStacks& aUniqueStacks, mozilla::ProgressLogger aProgressLogger) {
  return DoStreamSamplesAndMarkers(
      aName, aWriter, aProcessName, aETLDplus1, aProcessStartTime,
      aRegisterTime, aUnregisterTime, std::move(aProgressLogger),
      [&](mozilla::ProgressLogger aSubProgressLogger) {
        ProfilerThreadId processedThreadId = aBuffer.StreamSamplesToJSON(
            aWriter, aThreadId, aSinceTime, aUniqueStacks,
            std::move(aSubProgressLogger));
        return aThreadId.IsSpecified() ? aThreadId : processedThreadId;
      },
      [&](mozilla::ProgressLogger aSubProgressLogger) {
        aBuffer.StreamMarkersToJSON(aWriter, aThreadId, aProcessStartTime,
                                    aSinceTime, aUniqueStacks,
                                    std::move(aSubProgressLogger));
      });
}

void StreamSamplesAndMarkers(const char* aName,
                             ThreadStreamingContext& aThreadData,
                             SpliceableJSONWriter& aWriter,
                             const nsACString& aProcessName,
                             const nsACString& aETLDplus1,
                             const mozilla::TimeStamp& aProcessStartTime,
                             const mozilla::TimeStamp& aRegisterTime,
                             const mozilla::TimeStamp& aUnregisterTime,
                             mozilla::ProgressLogger aProgressLogger) {
  (void)DoStreamSamplesAndMarkers(
      aName, aWriter, aProcessName, aETLDplus1, aProcessStartTime,
      aRegisterTime, aUnregisterTime, std::move(aProgressLogger),
      [&](mozilla::ProgressLogger aSubProgressLogger) {
        aWriter.TakeAndSplice(
            aThreadData.mSamplesDataWriter.TakeChunkedWriteFunc());
        return aThreadData.mProfiledThreadData.Info().ThreadId();
      },
      [&](mozilla::ProgressLogger aSubProgressLogger) {
        aWriter.TakeAndSplice(
            aThreadData.mMarkersDataWriter.TakeChunkedWriteFunc());
      });
}

void ProfiledThreadData::NotifyAboutToLoseJSContext(
    JSContext* aContext, const mozilla::TimeStamp& aProcessStartTime,
    ProfileBuffer& aBuffer) {
  if (!mBufferPositionWhenReceivedJSContext) {
    return;
  }

  MOZ_RELEASE_ASSERT(aContext);

  if (mJITFrameInfoForPreviousJSContexts &&
      mJITFrameInfoForPreviousJSContexts->HasExpired(
          aBuffer.BufferRangeStart())) {
    mJITFrameInfoForPreviousJSContexts = nullptr;
  }

  mozilla::UniquePtr<JITFrameInfo> jitFrameInfo =
      mJITFrameInfoForPreviousJSContexts
          ? std::move(mJITFrameInfoForPreviousJSContexts)
          : mozilla::MakeUnique<JITFrameInfo>();

  aBuffer.AddJITInfoForRange(*mBufferPositionWhenReceivedJSContext,
                             mThreadInfo.ThreadId(), aContext, *jitFrameInfo,
                             mozilla::ProgressLogger{});

  mJITFrameInfoForPreviousJSContexts = std::move(jitFrameInfo);
  mBufferPositionWhenReceivedJSContext = mozilla::Nothing();
}

ThreadStreamingContext::ThreadStreamingContext(
    ProfiledThreadData& aProfiledThreadData, const ProfileBuffer& aBuffer,
    JSContext* aCx, mozilla::FailureLatch& aFailureLatch,
    ProfilerCodeAddressService* aService,
    mozilla::ProgressLogger aProgressLogger)
    : mProfiledThreadData(aProfiledThreadData),
      mJSContext(aCx),
      mSamplesDataWriter(aFailureLatch),
      mMarkersDataWriter(aFailureLatch),
      mUniqueStacks(mProfiledThreadData.PrepareUniqueStacks(
          aBuffer, aCx, aFailureLatch, aService,
          aProgressLogger.CreateSubLoggerFromTo(
              0_pc, "Preparing thread streaming context unique stacks...",
              99_pc, "Prepared thread streaming context Unique stacks"))) {
  if (aFailureLatch.Failed()) {
    return;
  }
  mSamplesDataWriter.SetUniqueStrings(mUniqueStacks->UniqueStrings());
  mSamplesDataWriter.StartBareList();
  mMarkersDataWriter.SetUniqueStrings(mUniqueStacks->UniqueStrings());
  mMarkersDataWriter.StartBareList();
}

void ThreadStreamingContext::FinalizeWriter() {
  mSamplesDataWriter.EndBareList();
  mMarkersDataWriter.EndBareList();
}

ProcessStreamingContext::ProcessStreamingContext(
    size_t aThreadCount, mozilla::FailureLatch& aFailureLatch,
    const mozilla::TimeStamp& aProcessStartTime, double aSinceTime)
    : mFailureLatch(aFailureLatch),
      mProcessStartTime(aProcessStartTime),
      mSinceTime(aSinceTime) {
  if (mFailureLatch.Failed()) {
    return;
  }
  if (!mTIDList.initCapacity(aThreadCount)) {
    mFailureLatch.SetFailure(
        "OOM in ProcessStreamingContext allocating TID list");
    return;
  }
  if (!mThreadStreamingContextList.initCapacity(aThreadCount)) {
    mFailureLatch.SetFailure(
        "OOM in ProcessStreamingContext allocating context list");
    mTIDList.clear();
    return;
  }
}

ProcessStreamingContext::~ProcessStreamingContext() {
  if (mFailureLatch.Failed()) {
    return;
  }
  MOZ_ASSERT(mTIDList.length() == mThreadStreamingContextList.length());
  MOZ_ASSERT(mTIDList.length() == mTIDList.capacity(),
             "Didn't pre-allocate exactly right");
}

void ProcessStreamingContext::AddThreadStreamingContext(
    ProfiledThreadData& aProfiledThreadData, const ProfileBuffer& aBuffer,
    JSContext* aCx, ProfilerCodeAddressService* aService,
    mozilla::ProgressLogger aProgressLogger) {
  if (mFailureLatch.Failed()) {
    return;
  }
  MOZ_ASSERT(mTIDList.length() == mThreadStreamingContextList.length());
  MOZ_ASSERT(mTIDList.length() < mTIDList.capacity(),
             "Didn't pre-allocate enough");
  mTIDList.infallibleAppend(aProfiledThreadData.Info().ThreadId());
  mThreadStreamingContextList.infallibleEmplaceBack(
      aProfiledThreadData, aBuffer, aCx, mFailureLatch, aService,
      aProgressLogger.CreateSubLoggerFromTo(
          1_pc, "Prepared streaming thread id", 100_pc,
          "Added thread streaming context"));
}

100%


¤ Dauer der Verarbeitung: 0.7 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.