Flow.h (3258B)
1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef Flow_h 18 #define Flow_h 19 20 // We use a Flow for connecting markers over time. It's a 21 // global (cross-process) 64bit id that will connect any markers that have the 22 // same id until we see a terminating-flow with that id. 23 // 24 // With these semanatics we can derive a flow from a pointer by xoring it with 25 // gProcessUUID and using a terminating-flow when we're done with 26 // that pointer e.g. destructor. This doesn't ensure that the flow is globally 27 // unique but makes collisions unlikely enough that it mostly works. 28 29 // The following code for Flow is derived from Perfetto 30 31 #include <stdint.h> 32 #include "mozilla/ProfileBufferEntrySerialization.h" 33 34 extern uint64_t MFBT_DATA gProcessUUID; 35 36 // This class is used as a marker field type and is used in the marker schema. 37 // To create a Flow, use Flow::FromPointer, Flow::ProcessScoped or Flow::Global. 38 class Flow { 39 public: 40 // |aFlow| which is local within a given process (e.g. atomic counter xor'ed 41 // with feature-specific value). This value is xor'ed with processUUID 42 // to attempt to ensure that it's globally-unique. 43 static inline Flow ProcessScoped(uint64_t aFlowId) { 44 return Global(aFlowId ^ gProcessUUID); 45 } 46 47 // Same as above, but construct an id from a pointer. 48 // NOTE: After the object is destroyed, the value of |aPtr| can be reused for 49 // a different object (in particular if the object is allocated on a stack) 50 // but it needs to be emitted as terminating flow first. 51 static inline Flow FromPointer(void* aPtr) { 52 return ProcessScoped(reinterpret_cast<uintptr_t>(aPtr)); 53 } 54 55 // The caller is responsible for ensuring that it's 56 // globally-unique (e.g. by generating a random value). This should be used 57 // only for flow events which cross the process boundary (e.g. IPCs). 58 static inline Flow Global(uint64_t aFlowId) { return Flow(aFlowId); } 59 60 uint64_t Id() const { return mFlowId; } 61 62 static MFBT_API void Init(); 63 64 private: 65 explicit Flow(uint64_t aFlowId) : mFlowId(aFlowId) {} 66 const uint64_t mFlowId; 67 }; 68 69 template <> 70 struct mozilla::ProfileBufferEntryWriter::Serializer<Flow> { 71 static constexpr Length Bytes(const Flow& aFlow) { return sizeof(Flow); } 72 73 static void Write(ProfileBufferEntryWriter& aEW, const Flow& aFlow) { 74 aEW.WriteBytes(&aFlow, sizeof(Flow)); 75 } 76 }; 77 78 template <> 79 struct mozilla::ProfileBufferEntryReader::Deserializer<Flow> { 80 static void ReadInto(ProfileBufferEntryReader& aER, uint64_t& aFlow) { 81 aER.ReadBytes(&aFlow, sizeof(Flow)); 82 } 83 84 static Flow Read(ProfileBufferEntryReader& aER) { 85 uint64_t flow; 86 ReadInto(aER, flow); 87 return Flow::Global(flow); 88 } 89 }; 90 91 #endif // Flow_h