ProfilerBacktrace.cpp (5032B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "ProfilerBacktrace.h" 8 9 #include "ProfileBuffer.h" 10 #include "ProfiledThreadData.h" 11 #include "ThreadInfo.h" 12 13 #include "mozilla/BaseProfiler.h" 14 #include "mozilla/BaseProfileJSONWriter.h" 15 16 namespace mozilla { 17 namespace baseprofiler { 18 19 ProfilerBacktrace::ProfilerBacktrace( 20 const char* aName, 21 UniquePtr<ProfileChunkedBuffer> aProfileChunkedBufferStorage, 22 UniquePtr<ProfileBuffer> aProfileBufferStorageOrNull /* = nullptr */) 23 : mName(aName), 24 mOptionalProfileChunkedBufferStorage( 25 std::move(aProfileChunkedBufferStorage)), 26 mProfileChunkedBuffer(mOptionalProfileChunkedBufferStorage.get()), 27 mOptionalProfileBufferStorage(std::move(aProfileBufferStorageOrNull)), 28 mProfileBuffer(mOptionalProfileBufferStorage.get()) { 29 if (mProfileBuffer) { 30 MOZ_RELEASE_ASSERT(mProfileChunkedBuffer, 31 "If we take ownership of a ProfileBuffer, we must also " 32 "receive ownership of a ProfileChunkedBuffer"); 33 MOZ_RELEASE_ASSERT( 34 mProfileChunkedBuffer == &mProfileBuffer->UnderlyingChunkedBuffer(), 35 "If we take ownership of a ProfileBuffer, we must also receive " 36 "ownership of its ProfileChunkedBuffer"); 37 } 38 MOZ_ASSERT( 39 !mProfileChunkedBuffer || !mProfileChunkedBuffer->IsThreadSafe(), 40 "ProfilerBacktrace only takes a non-thread-safe ProfileChunkedBuffer"); 41 } 42 43 ProfilerBacktrace::ProfilerBacktrace( 44 const char* aName, 45 ProfileChunkedBuffer* aExternalProfileChunkedBufferOrNull /* = nullptr */, 46 ProfileBuffer* aExternalProfileBufferOrNull /* = nullptr */) 47 : mName(aName), 48 mProfileChunkedBuffer(aExternalProfileChunkedBufferOrNull), 49 mProfileBuffer(aExternalProfileBufferOrNull) { 50 if (!mProfileChunkedBuffer) { 51 if (mProfileBuffer) { 52 // We don't have a ProfileChunkedBuffer but we have a ProfileBuffer, use 53 // the latter's ProfileChunkedBuffer. 54 mProfileChunkedBuffer = &mProfileBuffer->UnderlyingChunkedBuffer(); 55 MOZ_ASSERT(!mProfileChunkedBuffer->IsThreadSafe(), 56 "ProfilerBacktrace only takes a non-thread-safe " 57 "ProfileChunkedBuffer"); 58 } 59 } else { 60 if (mProfileBuffer) { 61 MOZ_RELEASE_ASSERT( 62 mProfileChunkedBuffer == &mProfileBuffer->UnderlyingChunkedBuffer(), 63 "If we reference both ProfileChunkedBuffer and ProfileBuffer, they " 64 "must already be connected"); 65 } 66 MOZ_ASSERT(!mProfileChunkedBuffer->IsThreadSafe(), 67 "ProfilerBacktrace only takes a non-thread-safe " 68 "ProfileChunkedBuffer"); 69 } 70 } 71 72 ProfilerBacktrace::~ProfilerBacktrace() {} 73 74 BaseProfilerThreadId ProfilerBacktrace::StreamJSON( 75 SpliceableJSONWriter& aWriter, const TimeStamp& aProcessStartTime, 76 UniqueStacks& aUniqueStacks) { 77 BaseProfilerThreadId processedThreadId; 78 79 // Unlike ProfiledThreadData::StreamJSON, we don't need to call 80 // ProfileBuffer::AddJITInfoForRange because ProfileBuffer does not contain 81 // any JitReturnAddr entries. For synchronous samples, JIT frames get expanded 82 // at sample time. 83 if (mProfileBuffer) { 84 processedThreadId = StreamSamplesAndMarkers( 85 mName.c_str(), BaseProfilerThreadId{}, *mProfileBuffer, aWriter, "", "", 86 aProcessStartTime, 87 /* aRegisterTime */ TimeStamp(), 88 /* aUnregisterTime */ TimeStamp(), 89 /* aSinceTime */ 0, aUniqueStacks); 90 } else if (mProfileChunkedBuffer) { 91 ProfileBuffer profileBuffer(*mProfileChunkedBuffer); 92 processedThreadId = StreamSamplesAndMarkers( 93 mName.c_str(), BaseProfilerThreadId{}, profileBuffer, aWriter, "", "", 94 aProcessStartTime, 95 /* aRegisterTime */ TimeStamp(), 96 /* aUnregisterTime */ TimeStamp(), 97 /* aSinceTime */ 0, aUniqueStacks); 98 } 99 // If there are no buffers, the backtrace is empty and nothing is streamed. 100 101 return processedThreadId; 102 } 103 104 } // namespace baseprofiler 105 106 // static 107 template <typename Destructor> 108 UniquePtr<baseprofiler::ProfilerBacktrace, Destructor> 109 ProfileBufferEntryReader:: 110 Deserializer<UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>>::Read( 111 ProfileBufferEntryReader& aER) { 112 auto profileChunkedBuffer = aER.ReadObject<UniquePtr<ProfileChunkedBuffer>>(); 113 if (!profileChunkedBuffer) { 114 return nullptr; 115 } 116 MOZ_ASSERT( 117 !profileChunkedBuffer->IsThreadSafe(), 118 "ProfilerBacktrace only stores non-thread-safe ProfileChunkedBuffers"); 119 std::string name = aER.ReadObject<std::string>(); 120 return UniquePtr<baseprofiler::ProfilerBacktrace, Destructor>{ 121 new baseprofiler::ProfilerBacktrace(name.c_str(), 122 std::move(profileChunkedBuffer))}; 123 }; 124 125 } // namespace mozilla