Line data Source code
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 : #ifndef ProfilerMarker_h
8 : #define ProfilerMarker_h
9 :
10 : #include "mozilla/UniquePtrExtensions.h"
11 :
12 : #include "ProfilerMarkerPayload.h"
13 :
14 : template<typename T>
15 : class ProfilerLinkedList;
16 : class SpliceableJSONWriter;
17 : class UniqueStacks;
18 :
19 0 : class ProfilerMarker
20 : {
21 : friend class ProfilerLinkedList<ProfilerMarker>;
22 :
23 : public:
24 0 : explicit ProfilerMarker(const char* aMarkerName,
25 : mozilla::UniquePtr<ProfilerMarkerPayload>
26 : aPayload = nullptr,
27 : double aTime = 0)
28 0 : : mMarkerName(strdup(aMarkerName))
29 0 : , mPayload(Move(aPayload))
30 0 : , mTime(aTime)
31 0 : {}
32 :
33 0 : void SetGeneration(uint32_t aGenID) { mGenID = aGenID; }
34 :
35 0 : bool HasExpired(uint32_t aGenID) const { return mGenID + 2 <= aGenID; }
36 :
37 0 : double GetTime() const { return mTime; }
38 :
39 0 : void StreamJSON(SpliceableJSONWriter& aWriter,
40 : const mozilla::TimeStamp& aProcessStartTime,
41 : UniqueStacks& aUniqueStacks) const
42 : {
43 : // Schema:
44 : // [name, time, data]
45 :
46 0 : aWriter.StartArrayElement();
47 : {
48 0 : aUniqueStacks.mUniqueStrings.WriteElement(aWriter, mMarkerName.get());
49 0 : aWriter.DoubleElement(mTime);
50 : // TODO: Store the callsite for this marker if available:
51 : // if have location data
52 : // b.NameValue(marker, "location", ...);
53 0 : if (mPayload) {
54 0 : aWriter.StartObjectElement();
55 : {
56 0 : mPayload->StreamPayload(aWriter, aProcessStartTime, aUniqueStacks);
57 : }
58 0 : aWriter.EndObject();
59 : }
60 : }
61 0 : aWriter.EndArray();
62 0 : }
63 :
64 : private:
65 : mozilla::UniqueFreePtr<char> mMarkerName;
66 : mozilla::UniquePtr<ProfilerMarkerPayload> mPayload;
67 : ProfilerMarker* mNext;
68 : double mTime;
69 : uint32_t mGenID;
70 : };
71 :
72 : template<typename T>
73 : class ProfilerLinkedList
74 : {
75 : public:
76 75 : ProfilerLinkedList()
77 : : mHead(nullptr)
78 75 : , mTail(nullptr)
79 75 : {}
80 :
81 0 : void insert(T* aElem)
82 : {
83 0 : if (!mTail) {
84 0 : mHead = aElem;
85 0 : mTail = aElem;
86 : } else {
87 0 : mTail->mNext = aElem;
88 0 : mTail = aElem;
89 : }
90 0 : aElem->mNext = nullptr;
91 0 : }
92 :
93 0 : T* popHead()
94 : {
95 0 : if (!mHead) {
96 0 : MOZ_ASSERT(false);
97 : return nullptr;
98 : }
99 :
100 0 : T* head = mHead;
101 :
102 0 : mHead = head->mNext;
103 0 : if (!mHead) {
104 0 : mTail = nullptr;
105 : }
106 :
107 0 : return head;
108 : }
109 :
110 1 : const T* peek() {
111 1 : return mHead;
112 : }
113 :
114 : private:
115 : T* mHead;
116 : T* mTail;
117 : };
118 :
119 : typedef ProfilerLinkedList<ProfilerMarker> ProfilerMarkerLinkedList;
120 :
121 : template<typename T>
122 : class ProfilerSignalSafeLinkedList
123 : {
124 : public:
125 75 : ProfilerSignalSafeLinkedList()
126 75 : : mSignalLock(false)
127 75 : {}
128 :
129 1 : ~ProfilerSignalSafeLinkedList()
130 : {
131 1 : if (mSignalLock) {
132 : // Some thread is modifying the list. We should only be released on that
133 : // thread.
134 0 : abort();
135 : }
136 :
137 1 : while (mList.peek()) {
138 0 : delete mList.popHead();
139 : }
140 1 : }
141 :
142 : // Insert an item into the list. Must only be called from the owning thread.
143 : // Must not be called while the list from accessList() is being accessed.
144 : // In the profiler, we ensure that by interrupting the profiled thread
145 : // (which is the one that owns this list and calls insert() on it) until
146 : // we're done reading the list from the signal handler.
147 0 : void insert(T* aElement)
148 : {
149 0 : MOZ_ASSERT(aElement);
150 :
151 0 : mSignalLock = true;
152 :
153 0 : mList.insert(aElement);
154 :
155 0 : mSignalLock = false;
156 0 : }
157 :
158 : // Called within signal, from any thread, possibly while insert() is in the
159 : // middle of modifying the list (on the owning thread). Will return null if
160 : // that is the case.
161 : // Function must be reentrant.
162 0 : ProfilerLinkedList<T>* accessList()
163 : {
164 0 : return mSignalLock ? nullptr : &mList;
165 : }
166 :
167 : private:
168 : ProfilerLinkedList<T> mList;
169 :
170 : // If this is set, then it's not safe to read the list because its contents
171 : // are being changed.
172 : mozilla::Atomic<bool> mSignalLock;
173 : };
174 :
175 : #endif // ProfilerMarker_h
|