summaryrefslogtreecommitdiffstats
path: root/tools/profiler/core/ProfileEntry.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/profiler/core/ProfileEntry.cpp')
-rw-r--r--tools/profiler/core/ProfileEntry.cpp881
1 files changed, 0 insertions, 881 deletions
diff --git a/tools/profiler/core/ProfileEntry.cpp b/tools/profiler/core/ProfileEntry.cpp
deleted file mode 100644
index 22d53a6f3..000000000
--- a/tools/profiler/core/ProfileEntry.cpp
+++ /dev/null
@@ -1,881 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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 <ostream>
-#include "platform.h"
-#include "mozilla/HashFunctions.h"
-
-#ifndef SPS_STANDALONE
-#include "nsThreadUtils.h"
-#include "nsXULAppAPI.h"
-
-// JS
-#include "jsapi.h"
-#include "jsfriendapi.h"
-#include "js/TrackedOptimizationInfo.h"
-#endif
-
-// Self
-#include "ProfileEntry.h"
-
-using mozilla::MakeUnique;
-using mozilla::UniquePtr;
-using mozilla::Maybe;
-using mozilla::Some;
-using mozilla::Nothing;
-using mozilla::JSONWriter;
-
-
-////////////////////////////////////////////////////////////////////////
-// BEGIN ProfileEntry
-
-ProfileEntry::ProfileEntry()
- : mTagData(nullptr)
- , mTagName(0)
-{ }
-
-// aTagData must not need release (i.e. be a string from the text segment)
-ProfileEntry::ProfileEntry(char aTagName, const char *aTagData)
- : mTagData(aTagData)
- , mTagName(aTagName)
-{ }
-
-ProfileEntry::ProfileEntry(char aTagName, ProfilerMarker *aTagMarker)
- : mTagMarker(aTagMarker)
- , mTagName(aTagName)
-{ }
-
-ProfileEntry::ProfileEntry(char aTagName, void *aTagPtr)
- : mTagPtr(aTagPtr)
- , mTagName(aTagName)
-{ }
-
-ProfileEntry::ProfileEntry(char aTagName, double aTagDouble)
- : mTagDouble(aTagDouble)
- , mTagName(aTagName)
-{ }
-
-ProfileEntry::ProfileEntry(char aTagName, uintptr_t aTagOffset)
- : mTagOffset(aTagOffset)
- , mTagName(aTagName)
-{ }
-
-ProfileEntry::ProfileEntry(char aTagName, Address aTagAddress)
- : mTagAddress(aTagAddress)
- , mTagName(aTagName)
-{ }
-
-ProfileEntry::ProfileEntry(char aTagName, int aTagInt)
- : mTagInt(aTagInt)
- , mTagName(aTagName)
-{ }
-
-ProfileEntry::ProfileEntry(char aTagName, char aTagChar)
- : mTagChar(aTagChar)
- , mTagName(aTagName)
-{ }
-
-bool ProfileEntry::is_ent_hint(char hintChar) {
- return mTagName == 'h' && mTagChar == hintChar;
-}
-
-bool ProfileEntry::is_ent_hint() {
- return mTagName == 'h';
-}
-
-bool ProfileEntry::is_ent(char tagChar) {
- return mTagName == tagChar;
-}
-
-void* ProfileEntry::get_tagPtr() {
- // No consistency checking. Oh well.
- return mTagPtr;
-}
-
-// END ProfileEntry
-////////////////////////////////////////////////////////////////////////
-
-class JSONSchemaWriter
-{
- JSONWriter& mWriter;
- uint32_t mIndex;
-
-public:
- explicit JSONSchemaWriter(JSONWriter& aWriter)
- : mWriter(aWriter)
- , mIndex(0)
- {
- aWriter.StartObjectProperty("schema");
- }
-
- void WriteField(const char* aName) {
- mWriter.IntProperty(aName, mIndex++);
- }
-
- ~JSONSchemaWriter() {
- mWriter.EndObject();
- }
-};
-
-#ifndef SPS_STANDALONE
-class StreamOptimizationTypeInfoOp : public JS::ForEachTrackedOptimizationTypeInfoOp
-{
- JSONWriter& mWriter;
- UniqueJSONStrings& mUniqueStrings;
- bool mStartedTypeList;
-
-public:
- StreamOptimizationTypeInfoOp(JSONWriter& aWriter, UniqueJSONStrings& aUniqueStrings)
- : mWriter(aWriter)
- , mUniqueStrings(aUniqueStrings)
- , mStartedTypeList(false)
- { }
-
- void readType(const char* keyedBy, const char* name,
- const char* location, Maybe<unsigned> lineno) override {
- if (!mStartedTypeList) {
- mStartedTypeList = true;
- mWriter.StartObjectElement();
- mWriter.StartArrayProperty("typeset");
- }
-
- mWriter.StartObjectElement();
- {
- mUniqueStrings.WriteProperty(mWriter, "keyedBy", keyedBy);
- if (name) {
- mUniqueStrings.WriteProperty(mWriter, "name", name);
- }
- if (location) {
- mUniqueStrings.WriteProperty(mWriter, "location", location);
- }
- if (lineno.isSome()) {
- mWriter.IntProperty("line", *lineno);
- }
- }
- mWriter.EndObject();
- }
-
- void operator()(JS::TrackedTypeSite site, const char* mirType) override {
- if (mStartedTypeList) {
- mWriter.EndArray();
- mStartedTypeList = false;
- } else {
- mWriter.StartObjectElement();
- }
-
- {
- mUniqueStrings.WriteProperty(mWriter, "site", JS::TrackedTypeSiteString(site));
- mUniqueStrings.WriteProperty(mWriter, "mirType", mirType);
- }
- mWriter.EndObject();
- }
-};
-
-// As mentioned in ProfileEntry.h, the JSON format contains many arrays whose
-// elements are laid out according to various schemas to help
-// de-duplication. This RAII class helps write these arrays by keeping track of
-// the last non-null element written and adding the appropriate number of null
-// elements when writing new non-null elements. It also automatically opens and
-// closes an array element on the given JSON writer.
-//
-// Example usage:
-//
-// // Define the schema of elements in this type of array: [FOO, BAR, BAZ]
-// enum Schema : uint32_t {
-// FOO = 0,
-// BAR = 1,
-// BAZ = 2
-// };
-//
-// AutoArraySchemaWriter writer(someJsonWriter, someUniqueStrings);
-// if (shouldWriteFoo) {
-// writer.IntElement(FOO, getFoo());
-// }
-// ... etc ...
-class MOZ_RAII AutoArraySchemaWriter
-{
- friend class AutoObjectWriter;
-
- SpliceableJSONWriter& mJSONWriter;
- UniqueJSONStrings* mStrings;
- uint32_t mNextFreeIndex;
-
-public:
- AutoArraySchemaWriter(SpliceableJSONWriter& aWriter, UniqueJSONStrings& aStrings)
- : mJSONWriter(aWriter)
- , mStrings(&aStrings)
- , mNextFreeIndex(0)
- {
- mJSONWriter.StartArrayElement();
- }
-
- // If you don't have access to a UniqueStrings, you had better not try and
- // write a string element down the line!
- explicit AutoArraySchemaWriter(SpliceableJSONWriter& aWriter)
- : mJSONWriter(aWriter)
- , mStrings(nullptr)
- , mNextFreeIndex(0)
- {
- mJSONWriter.StartArrayElement();
- }
-
- ~AutoArraySchemaWriter() {
- mJSONWriter.EndArray();
- }
-
- void FillUpTo(uint32_t aIndex) {
- MOZ_ASSERT(aIndex >= mNextFreeIndex);
- mJSONWriter.NullElements(aIndex - mNextFreeIndex);
- mNextFreeIndex = aIndex + 1;
- }
-
- void IntElement(uint32_t aIndex, uint32_t aValue) {
- FillUpTo(aIndex);
- mJSONWriter.IntElement(aValue);
- }
-
- void DoubleElement(uint32_t aIndex, double aValue) {
- FillUpTo(aIndex);
- mJSONWriter.DoubleElement(aValue);
- }
-
- void StringElement(uint32_t aIndex, const char* aValue) {
- MOZ_RELEASE_ASSERT(mStrings);
- FillUpTo(aIndex);
- mStrings->WriteElement(mJSONWriter, aValue);
- }
-};
-
-class StreamOptimizationAttemptsOp : public JS::ForEachTrackedOptimizationAttemptOp
-{
- SpliceableJSONWriter& mWriter;
- UniqueJSONStrings& mUniqueStrings;
-
-public:
- StreamOptimizationAttemptsOp(SpliceableJSONWriter& aWriter, UniqueJSONStrings& aUniqueStrings)
- : mWriter(aWriter),
- mUniqueStrings(aUniqueStrings)
- { }
-
- void operator()(JS::TrackedStrategy strategy, JS::TrackedOutcome outcome) override {
- enum Schema : uint32_t {
- STRATEGY = 0,
- OUTCOME = 1
- };
-
- AutoArraySchemaWriter writer(mWriter, mUniqueStrings);
- writer.StringElement(STRATEGY, JS::TrackedStrategyString(strategy));
- writer.StringElement(OUTCOME, JS::TrackedOutcomeString(outcome));
- }
-};
-
-class StreamJSFramesOp : public JS::ForEachProfiledFrameOp
-{
- void* mReturnAddress;
- UniqueStacks::Stack& mStack;
- unsigned mDepth;
-
-public:
- StreamJSFramesOp(void* aReturnAddr, UniqueStacks::Stack& aStack)
- : mReturnAddress(aReturnAddr)
- , mStack(aStack)
- , mDepth(0)
- { }
-
- unsigned depth() const {
- MOZ_ASSERT(mDepth > 0);
- return mDepth;
- }
-
- void operator()(const JS::ForEachProfiledFrameOp::FrameHandle& aFrameHandle) override {
- UniqueStacks::OnStackFrameKey frameKey(mReturnAddress, mDepth, aFrameHandle);
- mStack.AppendFrame(frameKey);
- mDepth++;
- }
-};
-#endif
-
-uint32_t UniqueJSONStrings::GetOrAddIndex(const char* aStr)
-{
- uint32_t index;
- StringKey key(aStr);
-
- auto it = mStringToIndexMap.find(key);
-
- if (it != mStringToIndexMap.end()) {
- return it->second;
- }
- index = mStringToIndexMap.size();
- mStringToIndexMap[key] = index;
- mStringTableWriter.StringElement(aStr);
- return index;
-}
-
-bool UniqueStacks::FrameKey::operator==(const FrameKey& aOther) const
-{
- return mLocation == aOther.mLocation &&
- mLine == aOther.mLine &&
- mCategory == aOther.mCategory &&
- mJITAddress == aOther.mJITAddress &&
- mJITDepth == aOther.mJITDepth;
-}
-
-bool UniqueStacks::StackKey::operator==(const StackKey& aOther) const
-{
- MOZ_ASSERT_IF(mPrefix == aOther.mPrefix, mPrefixHash == aOther.mPrefixHash);
- return mPrefix == aOther.mPrefix && mFrame == aOther.mFrame;
-}
-
-UniqueStacks::Stack::Stack(UniqueStacks& aUniqueStacks, const OnStackFrameKey& aRoot)
- : mUniqueStacks(aUniqueStacks)
- , mStack(aUniqueStacks.GetOrAddFrameIndex(aRoot))
-{
-}
-
-void UniqueStacks::Stack::AppendFrame(const OnStackFrameKey& aFrame)
-{
- // Compute the prefix hash and index before mutating mStack.
- uint32_t prefixHash = mStack.Hash();
- uint32_t prefix = mUniqueStacks.GetOrAddStackIndex(mStack);
- mStack.UpdateHash(prefixHash, prefix, mUniqueStacks.GetOrAddFrameIndex(aFrame));
-}
-
-uint32_t UniqueStacks::Stack::GetOrAddIndex() const
-{
- return mUniqueStacks.GetOrAddStackIndex(mStack);
-}
-
-uint32_t UniqueStacks::FrameKey::Hash() const
-{
- uint32_t hash = 0;
- if (!mLocation.IsEmpty()) {
-#ifdef SPS_STANDALONE
- hash = mozilla::HashString(mLocation.c_str());
-#else
- hash = mozilla::HashString(mLocation.get());
-#endif
- }
- if (mLine.isSome()) {
- hash = mozilla::AddToHash(hash, *mLine);
- }
- if (mCategory.isSome()) {
- hash = mozilla::AddToHash(hash, *mCategory);
- }
- if (mJITAddress.isSome()) {
- hash = mozilla::AddToHash(hash, *mJITAddress);
- if (mJITDepth.isSome()) {
- hash = mozilla::AddToHash(hash, *mJITDepth);
- }
- }
- return hash;
-}
-
-uint32_t UniqueStacks::StackKey::Hash() const
-{
- if (mPrefix.isNothing()) {
- return mozilla::HashGeneric(mFrame);
- }
- return mozilla::AddToHash(*mPrefixHash, mFrame);
-}
-
-UniqueStacks::Stack UniqueStacks::BeginStack(const OnStackFrameKey& aRoot)
-{
- return Stack(*this, aRoot);
-}
-
-UniqueStacks::UniqueStacks(JSContext* aContext)
- : mContext(aContext)
- , mFrameCount(0)
-{
- mFrameTableWriter.StartBareList();
- mStackTableWriter.StartBareList();
-}
-
-#ifdef SPS_STANDALONE
-uint32_t UniqueStacks::GetOrAddStackIndex(const StackKey& aStack)
-{
- uint32_t index;
- auto it = mStackToIndexMap.find(aStack);
-
- if (it != mStackToIndexMap.end()) {
- return it->second;
- }
-
- index = mStackToIndexMap.size();
- mStackToIndexMap[aStack] = index;
- StreamStack(aStack);
- return index;
-}
-#else
-uint32_t UniqueStacks::GetOrAddStackIndex(const StackKey& aStack)
-{
- uint32_t index;
- if (mStackToIndexMap.Get(aStack, &index)) {
- MOZ_ASSERT(index < mStackToIndexMap.Count());
- return index;
- }
-
- index = mStackToIndexMap.Count();
- mStackToIndexMap.Put(aStack, index);
- StreamStack(aStack);
- return index;
-}
-#endif
-
-#ifdef SPS_STANDALONE
-uint32_t UniqueStacks::GetOrAddFrameIndex(const OnStackFrameKey& aFrame)
-{
- uint32_t index;
- auto it = mFrameToIndexMap.find(aFrame);
- if (it != mFrameToIndexMap.end()) {
- MOZ_ASSERT(it->second < mFrameCount);
- return it->second;
- }
-
- // A manual count is used instead of mFrameToIndexMap.Count() due to
- // forwarding of canonical JIT frames above.
- index = mFrameCount++;
- mFrameToIndexMap[aFrame] = index;
- StreamFrame(aFrame);
- return index;
-}
-#else
-uint32_t UniqueStacks::GetOrAddFrameIndex(const OnStackFrameKey& aFrame)
-{
- uint32_t index;
- if (mFrameToIndexMap.Get(aFrame, &index)) {
- MOZ_ASSERT(index < mFrameCount);
- return index;
- }
-
- // If aFrame isn't canonical, forward it to the canonical frame's index.
- if (aFrame.mJITFrameHandle) {
- void* canonicalAddr = aFrame.mJITFrameHandle->canonicalAddress();
- if (canonicalAddr != *aFrame.mJITAddress) {
- OnStackFrameKey canonicalKey(canonicalAddr, *aFrame.mJITDepth, *aFrame.mJITFrameHandle);
- uint32_t canonicalIndex = GetOrAddFrameIndex(canonicalKey);
- mFrameToIndexMap.Put(aFrame, canonicalIndex);
- return canonicalIndex;
- }
- }
-
- // A manual count is used instead of mFrameToIndexMap.Count() due to
- // forwarding of canonical JIT frames above.
- index = mFrameCount++;
- mFrameToIndexMap.Put(aFrame, index);
- StreamFrame(aFrame);
- return index;
-}
-#endif
-
-uint32_t UniqueStacks::LookupJITFrameDepth(void* aAddr)
-{
- uint32_t depth;
-
- auto it = mJITFrameDepthMap.find(aAddr);
- if (it != mJITFrameDepthMap.end()) {
- depth = it->second;
- MOZ_ASSERT(depth > 0);
- return depth;
- }
- return 0;
-}
-
-void UniqueStacks::AddJITFrameDepth(void* aAddr, unsigned depth)
-{
- mJITFrameDepthMap[aAddr] = depth;
-}
-
-void UniqueStacks::SpliceFrameTableElements(SpliceableJSONWriter& aWriter)
-{
- mFrameTableWriter.EndBareList();
- aWriter.TakeAndSplice(mFrameTableWriter.WriteFunc());
-}
-
-void UniqueStacks::SpliceStackTableElements(SpliceableJSONWriter& aWriter)
-{
- mStackTableWriter.EndBareList();
- aWriter.TakeAndSplice(mStackTableWriter.WriteFunc());
-}
-
-void UniqueStacks::StreamStack(const StackKey& aStack)
-{
- enum Schema : uint32_t {
- PREFIX = 0,
- FRAME = 1
- };
-
- AutoArraySchemaWriter writer(mStackTableWriter, mUniqueStrings);
- if (aStack.mPrefix.isSome()) {
- writer.IntElement(PREFIX, *aStack.mPrefix);
- }
- writer.IntElement(FRAME, aStack.mFrame);
-}
-
-void UniqueStacks::StreamFrame(const OnStackFrameKey& aFrame)
-{
- enum Schema : uint32_t {
- LOCATION = 0,
- IMPLEMENTATION = 1,
- OPTIMIZATIONS = 2,
- LINE = 3,
- CATEGORY = 4
- };
-
- AutoArraySchemaWriter writer(mFrameTableWriter, mUniqueStrings);
-
-#ifndef SPS_STANDALONE
- if (!aFrame.mJITFrameHandle) {
-#else
- {
-#endif
-#ifdef SPS_STANDALONE
- writer.StringElement(LOCATION, aFrame.mLocation.c_str());
-#else
- writer.StringElement(LOCATION, aFrame.mLocation.get());
-#endif
- if (aFrame.mLine.isSome()) {
- writer.IntElement(LINE, *aFrame.mLine);
- }
- if (aFrame.mCategory.isSome()) {
- writer.IntElement(CATEGORY, *aFrame.mCategory);
- }
- }
-#ifndef SPS_STANDALONE
- else {
- const JS::ForEachProfiledFrameOp::FrameHandle& jitFrame = *aFrame.mJITFrameHandle;
-
- writer.StringElement(LOCATION, jitFrame.label());
-
- JS::ProfilingFrameIterator::FrameKind frameKind = jitFrame.frameKind();
- MOZ_ASSERT(frameKind == JS::ProfilingFrameIterator::Frame_Ion ||
- frameKind == JS::ProfilingFrameIterator::Frame_Baseline);
- writer.StringElement(IMPLEMENTATION,
- frameKind == JS::ProfilingFrameIterator::Frame_Ion
- ? "ion"
- : "baseline");
-
- if (jitFrame.hasTrackedOptimizations()) {
- writer.FillUpTo(OPTIMIZATIONS);
- mFrameTableWriter.StartObjectElement();
- {
- mFrameTableWriter.StartArrayProperty("types");
- {
- StreamOptimizationTypeInfoOp typeInfoOp(mFrameTableWriter, mUniqueStrings);
- jitFrame.forEachOptimizationTypeInfo(typeInfoOp);
- }
- mFrameTableWriter.EndArray();
-
- JS::Rooted<JSScript*> script(mContext);
- jsbytecode* pc;
- mFrameTableWriter.StartObjectProperty("attempts");
- {
- {
- JSONSchemaWriter schema(mFrameTableWriter);
- schema.WriteField("strategy");
- schema.WriteField("outcome");
- }
-
- mFrameTableWriter.StartArrayProperty("data");
- {
- StreamOptimizationAttemptsOp attemptOp(mFrameTableWriter, mUniqueStrings);
- jitFrame.forEachOptimizationAttempt(attemptOp, script.address(), &pc);
- }
- mFrameTableWriter.EndArray();
- }
- mFrameTableWriter.EndObject();
-
- if (JSAtom* name = js::GetPropertyNameFromPC(script, pc)) {
- char buf[512];
- JS_PutEscapedFlatString(buf, mozilla::ArrayLength(buf), js::AtomToFlatString(name), 0);
- mUniqueStrings.WriteProperty(mFrameTableWriter, "propertyName", buf);
- }
-
- unsigned line, column;
- line = JS_PCToLineNumber(script, pc, &column);
- mFrameTableWriter.IntProperty("line", line);
- mFrameTableWriter.IntProperty("column", column);
- }
- mFrameTableWriter.EndObject();
- }
- }
-#endif
-}
-
-struct ProfileSample
-{
- uint32_t mStack;
- Maybe<double> mTime;
- Maybe<double> mResponsiveness;
- Maybe<double> mRSS;
- Maybe<double> mUSS;
- Maybe<int> mFrameNumber;
- Maybe<double> mPower;
-};
-
-static void WriteSample(SpliceableJSONWriter& aWriter, ProfileSample& aSample)
-{
- enum Schema : uint32_t {
- STACK = 0,
- TIME = 1,
- RESPONSIVENESS = 2,
- RSS = 3,
- USS = 4,
- FRAME_NUMBER = 5,
- POWER = 6
- };
-
- AutoArraySchemaWriter writer(aWriter);
-
- writer.IntElement(STACK, aSample.mStack);
-
- if (aSample.mTime.isSome()) {
- writer.DoubleElement(TIME, *aSample.mTime);
- }
-
- if (aSample.mResponsiveness.isSome()) {
- writer.DoubleElement(RESPONSIVENESS, *aSample.mResponsiveness);
- }
-
- if (aSample.mRSS.isSome()) {
- writer.DoubleElement(RSS, *aSample.mRSS);
- }
-
- if (aSample.mUSS.isSome()) {
- writer.DoubleElement(USS, *aSample.mUSS);
- }
-
- if (aSample.mFrameNumber.isSome()) {
- writer.IntElement(FRAME_NUMBER, *aSample.mFrameNumber);
- }
-
- if (aSample.mPower.isSome()) {
- writer.DoubleElement(POWER, *aSample.mPower);
- }
-}
-
-void ProfileBuffer::StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId,
- double aSinceTime, JSContext* aContext,
- UniqueStacks& aUniqueStacks)
-{
- Maybe<ProfileSample> sample;
- int readPos = mReadPos;
- int currentThreadID = -1;
- Maybe<double> currentTime;
- UniquePtr<char[]> tagBuff = MakeUnique<char[]>(DYNAMIC_MAX_STRING);
-
- while (readPos != mWritePos) {
- ProfileEntry entry = mEntries[readPos];
- if (entry.mTagName == 'T') {
- currentThreadID = entry.mTagInt;
- currentTime.reset();
- int readAheadPos = (readPos + 1) % mEntrySize;
- if (readAheadPos != mWritePos) {
- ProfileEntry readAheadEntry = mEntries[readAheadPos];
- if (readAheadEntry.mTagName == 't') {
- currentTime = Some(readAheadEntry.mTagDouble);
- }
- }
- }
- if (currentThreadID == aThreadId && (currentTime.isNothing() || *currentTime >= aSinceTime)) {
- switch (entry.mTagName) {
- case 'r':
- if (sample.isSome()) {
- sample->mResponsiveness = Some(entry.mTagDouble);
- }
- break;
- case 'p':
- if (sample.isSome()) {
- sample->mPower = Some(entry.mTagDouble);
- }
- break;
- case 'R':
- if (sample.isSome()) {
- sample->mRSS = Some(entry.mTagDouble);
- }
- break;
- case 'U':
- if (sample.isSome()) {
- sample->mUSS = Some(entry.mTagDouble);
- }
- break;
- case 'f':
- if (sample.isSome()) {
- sample->mFrameNumber = Some(entry.mTagInt);
- }
- break;
- case 's':
- {
- // end the previous sample if there was one
- if (sample.isSome()) {
- WriteSample(aWriter, *sample);
- sample.reset();
- }
- // begin the next sample
- sample.emplace();
- sample->mTime = currentTime;
-
- // Seek forward through the entire sample, looking for frames
- // this is an easier approach to reason about than adding more
- // control variables and cases to the loop that goes through the buffer once
-
- UniqueStacks::Stack stack =
- aUniqueStacks.BeginStack(UniqueStacks::OnStackFrameKey("(root)"));
-
- int framePos = (readPos + 1) % mEntrySize;
- ProfileEntry frame = mEntries[framePos];
- while (framePos != mWritePos && frame.mTagName != 's' && frame.mTagName != 'T') {
- int incBy = 1;
- frame = mEntries[framePos];
-
- // Read ahead to the next tag, if it's a 'd' tag process it now
- const char* tagStringData = frame.mTagData;
- int readAheadPos = (framePos + 1) % mEntrySize;
- // Make sure the string is always null terminated if it fills up
- // DYNAMIC_MAX_STRING-2
- tagBuff[DYNAMIC_MAX_STRING-1] = '\0';
-
- if (readAheadPos != mWritePos && mEntries[readAheadPos].mTagName == 'd') {
- tagStringData = processDynamicTag(framePos, &incBy, tagBuff.get());
- }
-
- // Write one frame. It can have either
- // 1. only location - 'l' containing a memory address
- // 2. location and line number - 'c' followed by 'd's,
- // an optional 'n' and an optional 'y'
- // 3. a JIT return address - 'j' containing native code address
- if (frame.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)frame.mTagPtr;
- snprintf(tagBuff.get(), DYNAMIC_MAX_STRING, "%#llx", pc);
- stack.AppendFrame(UniqueStacks::OnStackFrameKey(tagBuff.get()));
- } else if (frame.mTagName == 'c') {
- UniqueStacks::OnStackFrameKey frameKey(tagStringData);
- readAheadPos = (framePos + incBy) % mEntrySize;
- if (readAheadPos != mWritePos &&
- mEntries[readAheadPos].mTagName == 'n') {
- frameKey.mLine = Some((unsigned) mEntries[readAheadPos].mTagInt);
- incBy++;
- }
- readAheadPos = (framePos + incBy) % mEntrySize;
- if (readAheadPos != mWritePos &&
- mEntries[readAheadPos].mTagName == 'y') {
- frameKey.mCategory = Some((unsigned) mEntries[readAheadPos].mTagInt);
- incBy++;
- }
- stack.AppendFrame(frameKey);
-#ifndef SPS_STANDALONE
- } else if (frame.mTagName == 'J') {
- // A JIT frame may expand to multiple frames due to inlining.
- void* pc = frame.mTagPtr;
- unsigned depth = aUniqueStacks.LookupJITFrameDepth(pc);
- if (depth == 0) {
- StreamJSFramesOp framesOp(pc, stack);
- JS::ForEachProfiledFrame(aContext, pc, framesOp);
- aUniqueStacks.AddJITFrameDepth(pc, framesOp.depth());
- } else {
- for (unsigned i = 0; i < depth; i++) {
- UniqueStacks::OnStackFrameKey inlineFrameKey(pc, i);
- stack.AppendFrame(inlineFrameKey);
- }
- }
-#endif
- }
- framePos = (framePos + incBy) % mEntrySize;
- }
-
- sample->mStack = stack.GetOrAddIndex();
- break;
- }
- }
- }
- readPos = (readPos + 1) % mEntrySize;
- }
- if (sample.isSome()) {
- WriteSample(aWriter, *sample);
- }
-}
-
-void ProfileBuffer::StreamMarkersToJSON(SpliceableJSONWriter& aWriter, int aThreadId,
- double aSinceTime, UniqueStacks& aUniqueStacks)
-{
- int readPos = mReadPos;
- int currentThreadID = -1;
- while (readPos != mWritePos) {
- ProfileEntry entry = mEntries[readPos];
- if (entry.mTagName == 'T') {
- currentThreadID = entry.mTagInt;
- } else if (currentThreadID == aThreadId && entry.mTagName == 'm') {
- const ProfilerMarker* marker = entry.getMarker();
- if (marker->GetTime() >= aSinceTime) {
- entry.getMarker()->StreamJSON(aWriter, aUniqueStacks);
- }
- }
- readPos = (readPos + 1) % mEntrySize;
- }
-}
-
-int ProfileBuffer::FindLastSampleOfThread(int aThreadId)
-{
- // We search backwards from mWritePos-1 to mReadPos.
- // Adding mEntrySize makes the result of the modulus positive.
- for (int readPos = (mWritePos + mEntrySize - 1) % mEntrySize;
- readPos != (mReadPos + mEntrySize - 1) % mEntrySize;
- readPos = (readPos + mEntrySize - 1) % mEntrySize) {
- ProfileEntry entry = mEntries[readPos];
- if (entry.mTagName == 'T' && entry.mTagInt == aThreadId) {
- return readPos;
- }
- }
-
- return -1;
-}
-
-void ProfileBuffer::DuplicateLastSample(int aThreadId)
-{
- int lastSampleStartPos = FindLastSampleOfThread(aThreadId);
- if (lastSampleStartPos == -1) {
- return;
- }
-
- MOZ_ASSERT(mEntries[lastSampleStartPos].mTagName == 'T');
-
- addTag(mEntries[lastSampleStartPos]);
-
- // Go through the whole entry and duplicate it, until we find the next one.
- for (int readPos = (lastSampleStartPos + 1) % mEntrySize;
- readPos != mWritePos;
- readPos = (readPos + 1) % mEntrySize) {
- switch (mEntries[readPos].mTagName) {
- case 'T':
- // We're done.
- return;
- case 't':
- // Copy with new time
- addTag(ProfileEntry('t', (mozilla::TimeStamp::Now() - sStartTime).ToMilliseconds()));
- break;
- case 'm':
- // Don't copy markers
- break;
- // Copy anything else we don't know about
- // L, B, S, c, s, d, l, f, h, r, t, p
- default:
- addTag(mEntries[readPos]);
- break;
- }
- }
-}
-
-// END ProfileBuffer
-////////////////////////////////////////////////////////////////////////
-
-
-////////////////////////////////////////////////////////////////////////
-// BEGIN ThreadProfile
-
-// END ThreadProfile
-////////////////////////////////////////////////////////////////////////