xref: /llvm-project/compiler-rt/lib/ctx_profile/CtxInstrProfiling.cpp (revision f32e5bdcefcff80f4296f8f4abedc37dcda36d53)
1a3e7a125SMircea Trofin //===- CtxInstrProfiling.cpp - contextual instrumented PGO ----------------===//
2a3e7a125SMircea Trofin //
3a3e7a125SMircea Trofin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a3e7a125SMircea Trofin // See https://llvm.org/LICENSE.txt for license information.
5a3e7a125SMircea Trofin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a3e7a125SMircea Trofin //
7a3e7a125SMircea Trofin //===----------------------------------------------------------------------===//
8a3e7a125SMircea Trofin 
9a3e7a125SMircea Trofin #include "CtxInstrProfiling.h"
10a3e7a125SMircea Trofin #include "sanitizer_common/sanitizer_allocator_internal.h"
11a3e7a125SMircea Trofin #include "sanitizer_common/sanitizer_common.h"
12a3e7a125SMircea Trofin #include "sanitizer_common/sanitizer_dense_map.h"
13ccf765cfSMircea Trofin #include "sanitizer_common/sanitizer_libc.h"
14a3e7a125SMircea Trofin #include "sanitizer_common/sanitizer_mutex.h"
15a3e7a125SMircea Trofin #include "sanitizer_common/sanitizer_placement_new.h"
16a3e7a125SMircea Trofin #include "sanitizer_common/sanitizer_thread_safety.h"
17ccf765cfSMircea Trofin #include "sanitizer_common/sanitizer_vector.h"
18a3e7a125SMircea Trofin 
19a3e7a125SMircea Trofin #include <assert.h>
20a3e7a125SMircea Trofin 
21a3e7a125SMircea Trofin using namespace __ctx_profile;
22a3e7a125SMircea Trofin 
23ccf765cfSMircea Trofin namespace {
24ccf765cfSMircea Trofin // Keep track of all the context roots we actually saw, so we can then traverse
25ccf765cfSMircea Trofin // them when the user asks for the profile in __llvm_ctx_profile_fetch
26ccf765cfSMircea Trofin __sanitizer::SpinMutex AllContextsMutex;
27ccf765cfSMircea Trofin SANITIZER_GUARDED_BY(AllContextsMutex)
28ccf765cfSMircea Trofin __sanitizer::Vector<ContextRoot *> AllContextRoots;
29ccf765cfSMircea Trofin 
30ccf765cfSMircea Trofin // utility to taint a pointer by setting the LSB. There is an assumption
31ccf765cfSMircea Trofin // throughout that the addresses of contexts are even (really, they should be
32ccf765cfSMircea Trofin // align(8), but "even"-ness is the minimum assumption)
33ccf765cfSMircea Trofin // "scratch contexts" are buffers that we return in certain cases - they are
34ccf765cfSMircea Trofin // large enough to allow for memory safe counter access, but they don't link
35ccf765cfSMircea Trofin // subcontexts below them (the runtime recognizes them and enforces that)
36ccf765cfSMircea Trofin ContextNode *markAsScratch(const ContextNode *Ctx) {
37ccf765cfSMircea Trofin   return reinterpret_cast<ContextNode *>(reinterpret_cast<uint64_t>(Ctx) | 1);
38ccf765cfSMircea Trofin }
39ccf765cfSMircea Trofin 
40ccf765cfSMircea Trofin // Used when getting the data from TLS. We don't *really* need to reset, but
41ccf765cfSMircea Trofin // it's a simpler system if we do.
42ccf765cfSMircea Trofin template <typename T> inline T consume(T &V) {
43ccf765cfSMircea Trofin   auto R = V;
44ccf765cfSMircea Trofin   V = {0};
45ccf765cfSMircea Trofin   return R;
46ccf765cfSMircea Trofin }
47ccf765cfSMircea Trofin 
48ccf765cfSMircea Trofin // We allocate at least kBuffSize Arena pages. The scratch buffer is also that
49ccf765cfSMircea Trofin // large.
50ccf765cfSMircea Trofin constexpr size_t kPower = 20;
51ccf765cfSMircea Trofin constexpr size_t kBuffSize = 1 << kPower;
52ccf765cfSMircea Trofin 
53ccf765cfSMircea Trofin // Highly unlikely we need more than kBuffSize for a context.
54ccf765cfSMircea Trofin size_t getArenaAllocSize(size_t Needed) {
55ccf765cfSMircea Trofin   if (Needed >= kBuffSize)
56ccf765cfSMircea Trofin     return 2 * Needed;
57ccf765cfSMircea Trofin   return kBuffSize;
58ccf765cfSMircea Trofin }
59ccf765cfSMircea Trofin 
60ccf765cfSMircea Trofin // verify the structural integrity of the context
61ccf765cfSMircea Trofin bool validate(const ContextRoot *Root) {
62ccf765cfSMircea Trofin   // all contexts should be laid out in some arena page. Go over each arena
63ccf765cfSMircea Trofin   // allocated for this Root, and jump over contained contexts based on
64ccf765cfSMircea Trofin   // self-reported sizes.
65ccf765cfSMircea Trofin   __sanitizer::DenseMap<uint64_t, bool> ContextStartAddrs;
66ccf765cfSMircea Trofin   for (const auto *Mem = Root->FirstMemBlock; Mem; Mem = Mem->next()) {
67ccf765cfSMircea Trofin     const auto *Pos = Mem->start();
68ccf765cfSMircea Trofin     while (Pos < Mem->pos()) {
69ccf765cfSMircea Trofin       const auto *Ctx = reinterpret_cast<const ContextNode *>(Pos);
70ccf765cfSMircea Trofin       if (!ContextStartAddrs.insert({reinterpret_cast<uint64_t>(Ctx), true})
71ccf765cfSMircea Trofin                .second)
72ccf765cfSMircea Trofin         return false;
73ccf765cfSMircea Trofin       Pos += Ctx->size();
74ccf765cfSMircea Trofin     }
75ccf765cfSMircea Trofin   }
76ccf765cfSMircea Trofin 
77ccf765cfSMircea Trofin   // Now traverse the contexts again the same way, but validate all nonull
78ccf765cfSMircea Trofin   // subcontext addresses appear in the set computed above.
79ccf765cfSMircea Trofin   for (const auto *Mem = Root->FirstMemBlock; Mem; Mem = Mem->next()) {
80ccf765cfSMircea Trofin     const auto *Pos = Mem->start();
81ccf765cfSMircea Trofin     while (Pos < Mem->pos()) {
82ccf765cfSMircea Trofin       const auto *Ctx = reinterpret_cast<const ContextNode *>(Pos);
83ccf765cfSMircea Trofin       for (uint32_t I = 0; I < Ctx->callsites_size(); ++I)
84ccf765cfSMircea Trofin         for (auto *Sub = Ctx->subContexts()[I]; Sub; Sub = Sub->next())
85ccf765cfSMircea Trofin           if (!ContextStartAddrs.find(reinterpret_cast<uint64_t>(Sub)))
86ccf765cfSMircea Trofin             return false;
87ccf765cfSMircea Trofin 
88ccf765cfSMircea Trofin       Pos += Ctx->size();
89ccf765cfSMircea Trofin     }
90ccf765cfSMircea Trofin   }
91ccf765cfSMircea Trofin   return true;
92ccf765cfSMircea Trofin }
93e4763ca8SMircea Trofin 
94e4763ca8SMircea Trofin inline ContextNode *allocContextNode(char *Place, GUID Guid,
95*f32e5bdcSMircea Trofin                                      uint32_t NumCounters,
96*f32e5bdcSMircea Trofin                                      uint32_t NumCallsites,
97e4763ca8SMircea Trofin                                      ContextNode *Next = nullptr) {
98e4763ca8SMircea Trofin   assert(reinterpret_cast<uint64_t>(Place) % ExpectedAlignment == 0);
99*f32e5bdcSMircea Trofin   return new (Place) ContextNode(Guid, NumCounters, NumCallsites, Next);
100e4763ca8SMircea Trofin }
101e4763ca8SMircea Trofin 
102e4763ca8SMircea Trofin void resetContextNode(ContextNode &Node) {
103e4763ca8SMircea Trofin   // FIXME(mtrofin): this is std::memset, which we can probably use if we
104e4763ca8SMircea Trofin   // drop/reduce the dependency on sanitizer_common.
105e4763ca8SMircea Trofin   for (uint32_t I = 0; I < Node.counters_size(); ++I)
106e4763ca8SMircea Trofin     Node.counters()[I] = 0;
107e4763ca8SMircea Trofin   for (uint32_t I = 0; I < Node.callsites_size(); ++I)
108e4763ca8SMircea Trofin     for (auto *Next = Node.subContexts()[I]; Next; Next = Next->next())
109e4763ca8SMircea Trofin       resetContextNode(*Next);
110e4763ca8SMircea Trofin }
111e4763ca8SMircea Trofin 
112e4763ca8SMircea Trofin void onContextEnter(ContextNode &Node) { ++Node.counters()[0]; }
113e4763ca8SMircea Trofin 
114ccf765cfSMircea Trofin } // namespace
115ccf765cfSMircea Trofin 
116ccf765cfSMircea Trofin // the scratch buffer - what we give when we can't produce a real context (the
117ccf765cfSMircea Trofin // scratch isn't "real" in that it's expected to be clobbered carelessly - we
118ccf765cfSMircea Trofin // don't read it). The other important thing is that the callees from a scratch
119ccf765cfSMircea Trofin // context also get a scratch context.
120ccf765cfSMircea Trofin // Eventually this can be replaced with per-function buffers, a'la the typical
121ccf765cfSMircea Trofin // (flat) instrumented FDO buffers. The clobbering aspect won't apply there, but
122ccf765cfSMircea Trofin // the part about determining the nature of the subcontexts does.
123ccf765cfSMircea Trofin __thread char __Buffer[kBuffSize] = {0};
124ccf765cfSMircea Trofin 
125ccf765cfSMircea Trofin #define TheScratchContext                                                      \
126ccf765cfSMircea Trofin   markAsScratch(reinterpret_cast<ContextNode *>(__Buffer))
127ccf765cfSMircea Trofin 
128ccf765cfSMircea Trofin // init the TLSes
129ccf765cfSMircea Trofin __thread void *volatile __llvm_ctx_profile_expected_callee[2] = {nullptr,
130ccf765cfSMircea Trofin                                                                  nullptr};
131ccf765cfSMircea Trofin __thread ContextNode **volatile __llvm_ctx_profile_callsite[2] = {0, 0};
132ccf765cfSMircea Trofin 
133ccf765cfSMircea Trofin __thread ContextRoot *volatile __llvm_ctx_profile_current_context_root =
134ccf765cfSMircea Trofin     nullptr;
135ccf765cfSMircea Trofin 
136265953ccSMircea Trofin Arena::Arena(uint32_t Size) : Size(Size) {
137265953ccSMircea Trofin   __sanitizer::internal_memset(start(), 0, Size);
138265953ccSMircea Trofin }
139265953ccSMircea Trofin 
140a3e7a125SMircea Trofin // FIXME(mtrofin): use malloc / mmap instead of sanitizer common APIs to reduce
141a3e7a125SMircea Trofin // the dependency on the latter.
142a3e7a125SMircea Trofin Arena *Arena::allocateNewArena(size_t Size, Arena *Prev) {
143a3e7a125SMircea Trofin   assert(!Prev || Prev->Next == nullptr);
144ccf765cfSMircea Trofin   Arena *NewArena = new (__sanitizer::InternalAlloc(
145ccf765cfSMircea Trofin       Size + sizeof(Arena), /*cache=*/nullptr, /*alignment=*/ExpectedAlignment))
146ccf765cfSMircea Trofin       Arena(Size);
147a3e7a125SMircea Trofin   if (Prev)
148a3e7a125SMircea Trofin     Prev->Next = NewArena;
149a3e7a125SMircea Trofin   return NewArena;
150a3e7a125SMircea Trofin }
151a3e7a125SMircea Trofin 
152a3e7a125SMircea Trofin void Arena::freeArenaList(Arena *&A) {
153a3e7a125SMircea Trofin   assert(A);
154a3e7a125SMircea Trofin   for (auto *I = A; I != nullptr;) {
155a3e7a125SMircea Trofin     auto *Current = I;
156a3e7a125SMircea Trofin     I = I->Next;
157a3e7a125SMircea Trofin     __sanitizer::InternalFree(Current);
158a3e7a125SMircea Trofin   }
159a3e7a125SMircea Trofin   A = nullptr;
160a3e7a125SMircea Trofin }
161ccf765cfSMircea Trofin 
162ccf765cfSMircea Trofin // If this is the first time we hit a callsite with this (Guid) particular
163ccf765cfSMircea Trofin // callee, we need to allocate.
164e4763ca8SMircea Trofin ContextNode *getCallsiteSlow(GUID Guid, ContextNode **InsertionPoint,
165*f32e5bdcSMircea Trofin                              uint32_t NumCounters, uint32_t NumCallsites) {
166*f32e5bdcSMircea Trofin   auto AllocSize = ContextNode::getAllocSize(NumCounters, NumCallsites);
167ccf765cfSMircea Trofin   auto *Mem = __llvm_ctx_profile_current_context_root->CurrentMem;
168ccf765cfSMircea Trofin   char *AllocPlace = Mem->tryBumpAllocate(AllocSize);
169ccf765cfSMircea Trofin   if (!AllocPlace) {
170ccf765cfSMircea Trofin     // if we failed to allocate on the current arena, allocate a new arena,
171ccf765cfSMircea Trofin     // and place it on __llvm_ctx_profile_current_context_root->CurrentMem so we
172ccf765cfSMircea Trofin     // find it from now on for other cases when we need to getCallsiteSlow.
173ccf765cfSMircea Trofin     // Note that allocateNewArena will link the allocated memory in the list of
174ccf765cfSMircea Trofin     // Arenas.
175ccf765cfSMircea Trofin     __llvm_ctx_profile_current_context_root->CurrentMem = Mem =
176ccf765cfSMircea Trofin         Mem->allocateNewArena(getArenaAllocSize(AllocSize), Mem);
177ccf765cfSMircea Trofin     AllocPlace = Mem->tryBumpAllocate(AllocSize);
178ccf765cfSMircea Trofin   }
179*f32e5bdcSMircea Trofin   auto *Ret = allocContextNode(AllocPlace, Guid, NumCounters, NumCallsites,
180ccf765cfSMircea Trofin                                *InsertionPoint);
181ccf765cfSMircea Trofin   *InsertionPoint = Ret;
182ccf765cfSMircea Trofin   return Ret;
183ccf765cfSMircea Trofin }
184ccf765cfSMircea Trofin 
185ccf765cfSMircea Trofin ContextNode *__llvm_ctx_profile_get_context(void *Callee, GUID Guid,
186*f32e5bdcSMircea Trofin                                             uint32_t NumCounters,
187*f32e5bdcSMircea Trofin                                             uint32_t NumCallsites) {
188ccf765cfSMircea Trofin   // fast "out" if we're not even doing contextual collection.
189ccf765cfSMircea Trofin   if (!__llvm_ctx_profile_current_context_root)
190ccf765cfSMircea Trofin     return TheScratchContext;
191ccf765cfSMircea Trofin 
192ccf765cfSMircea Trofin   // also fast "out" if the caller is scratch. We can see if it's scratch by
193ccf765cfSMircea Trofin   // looking at the interior pointer into the subcontexts vector that the caller
194ccf765cfSMircea Trofin   // provided, which, if the context is scratch, so is that interior pointer
195ccf765cfSMircea Trofin   // (because all the address calculations are using even values. Or more
196ccf765cfSMircea Trofin   // precisely, aligned - 8 values)
197ccf765cfSMircea Trofin   auto **CallsiteContext = consume(__llvm_ctx_profile_callsite[0]);
198ccf765cfSMircea Trofin   if (!CallsiteContext || isScratch(CallsiteContext))
199ccf765cfSMircea Trofin     return TheScratchContext;
200ccf765cfSMircea Trofin 
201ccf765cfSMircea Trofin   // if the callee isn't the expected one, return scratch.
202ccf765cfSMircea Trofin   // Signal handler(s) could have been invoked at any point in the execution.
203ccf765cfSMircea Trofin   // Should that have happened, and had it (the handler) be built with
204ccf765cfSMircea Trofin   // instrumentation, its __llvm_ctx_profile_get_context would have failed here.
205ccf765cfSMircea Trofin   // Its sub call graph would have then populated
206ccf765cfSMircea Trofin   // __llvm_ctx_profile_{expected_callee | callsite} at index 1.
207ccf765cfSMircea Trofin   // The normal call graph may be impacted in that, if the signal handler
208ccf765cfSMircea Trofin   // happened somewhere before we read the TLS here, we'd see the TLS reset and
209ccf765cfSMircea Trofin   // we'd also fail here. That would just mean we would loose counter values for
210ccf765cfSMircea Trofin   // the normal subgraph, this time around. That should be very unlikely, but if
211ccf765cfSMircea Trofin   // it happens too frequently, we should be able to detect discrepancies in
212ccf765cfSMircea Trofin   // entry counts (caller-callee). At the moment, the design goes on the
213ccf765cfSMircea Trofin   // assumption that is so unfrequent, though, that it's not worth doing more
214ccf765cfSMircea Trofin   // for that case.
215ccf765cfSMircea Trofin   auto *ExpectedCallee = consume(__llvm_ctx_profile_expected_callee[0]);
216ccf765cfSMircea Trofin   if (ExpectedCallee != Callee)
217ccf765cfSMircea Trofin     return TheScratchContext;
218ccf765cfSMircea Trofin 
219ccf765cfSMircea Trofin   auto *Callsite = *CallsiteContext;
220ccf765cfSMircea Trofin   // in the case of indirect calls, we will have all seen targets forming a
221ccf765cfSMircea Trofin   // linked list here. Find the one corresponding to this callee.
222ccf765cfSMircea Trofin   while (Callsite && Callsite->guid() != Guid) {
223ccf765cfSMircea Trofin     Callsite = Callsite->next();
224ccf765cfSMircea Trofin   }
225ccf765cfSMircea Trofin   auto *Ret = Callsite ? Callsite
226*f32e5bdcSMircea Trofin                        : getCallsiteSlow(Guid, CallsiteContext, NumCounters,
227*f32e5bdcSMircea Trofin                                          NumCallsites);
228*f32e5bdcSMircea Trofin   if (Ret->callsites_size() != NumCallsites ||
229*f32e5bdcSMircea Trofin       Ret->counters_size() != NumCounters)
230ccf765cfSMircea Trofin     __sanitizer::Printf("[ctxprof] Returned ctx differs from what's asked: "
231ccf765cfSMircea Trofin                         "Context: %p, Asked: %lu %u %u, Got: %lu %u %u \n",
232*f32e5bdcSMircea Trofin                         reinterpret_cast<void *>(Ret), Guid, NumCallsites,
233*f32e5bdcSMircea Trofin                         NumCounters, Ret->guid(), Ret->callsites_size(),
23458c77856SMircea Trofin                         Ret->counters_size());
235e4763ca8SMircea Trofin   onContextEnter(*Ret);
236ccf765cfSMircea Trofin   return Ret;
237ccf765cfSMircea Trofin }
238ccf765cfSMircea Trofin 
239ccf765cfSMircea Trofin // This should be called once for a Root. Allocate the first arena, set up the
240ccf765cfSMircea Trofin // first context.
241*f32e5bdcSMircea Trofin void setupContext(ContextRoot *Root, GUID Guid, uint32_t NumCounters,
242*f32e5bdcSMircea Trofin                   uint32_t NumCallsites) {
243ccf765cfSMircea Trofin   __sanitizer::GenericScopedLock<__sanitizer::SpinMutex> Lock(
244ccf765cfSMircea Trofin       &AllContextsMutex);
245ccf765cfSMircea Trofin   // Re-check - we got here without having had taken a lock.
246ccf765cfSMircea Trofin   if (Root->FirstMemBlock)
247ccf765cfSMircea Trofin     return;
248*f32e5bdcSMircea Trofin   const auto Needed = ContextNode::getAllocSize(NumCounters, NumCallsites);
249ccf765cfSMircea Trofin   auto *M = Arena::allocateNewArena(getArenaAllocSize(Needed));
250ccf765cfSMircea Trofin   Root->FirstMemBlock = M;
251ccf765cfSMircea Trofin   Root->CurrentMem = M;
252e4763ca8SMircea Trofin   Root->FirstNode = allocContextNode(M->tryBumpAllocate(Needed), Guid,
253*f32e5bdcSMircea Trofin                                      NumCounters, NumCallsites);
254ccf765cfSMircea Trofin   AllContextRoots.PushBack(Root);
255ccf765cfSMircea Trofin }
256ccf765cfSMircea Trofin 
257ccf765cfSMircea Trofin ContextNode *__llvm_ctx_profile_start_context(
258ccf765cfSMircea Trofin     ContextRoot *Root, GUID Guid, uint32_t Counters,
259ccf765cfSMircea Trofin     uint32_t Callsites) SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
260ccf765cfSMircea Trofin   if (!Root->FirstMemBlock) {
261ccf765cfSMircea Trofin     setupContext(Root, Guid, Counters, Callsites);
262ccf765cfSMircea Trofin   }
263ccf765cfSMircea Trofin   if (Root->Taken.TryLock()) {
264ccf765cfSMircea Trofin     __llvm_ctx_profile_current_context_root = Root;
265e4763ca8SMircea Trofin     onContextEnter(*Root->FirstNode);
266ccf765cfSMircea Trofin     return Root->FirstNode;
267ccf765cfSMircea Trofin   }
268ccf765cfSMircea Trofin   // If this thread couldn't take the lock, return scratch context.
269ccf765cfSMircea Trofin   __llvm_ctx_profile_current_context_root = nullptr;
270ccf765cfSMircea Trofin   return TheScratchContext;
271ccf765cfSMircea Trofin }
272ccf765cfSMircea Trofin 
273ccf765cfSMircea Trofin void __llvm_ctx_profile_release_context(ContextRoot *Root)
274ccf765cfSMircea Trofin     SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
275ccf765cfSMircea Trofin   if (__llvm_ctx_profile_current_context_root) {
276ccf765cfSMircea Trofin     __llvm_ctx_profile_current_context_root = nullptr;
277ccf765cfSMircea Trofin     Root->Taken.Unlock();
278ccf765cfSMircea Trofin   }
279ccf765cfSMircea Trofin }
280ccf765cfSMircea Trofin 
281ccf765cfSMircea Trofin void __llvm_ctx_profile_start_collection() {
282*f32e5bdcSMircea Trofin   size_t NumMemUnits = 0;
283ccf765cfSMircea Trofin   __sanitizer::GenericScopedLock<__sanitizer::SpinMutex> Lock(
284ccf765cfSMircea Trofin       &AllContextsMutex);
285ccf765cfSMircea Trofin   for (uint32_t I = 0; I < AllContextRoots.Size(); ++I) {
286ccf765cfSMircea Trofin     auto *Root = AllContextRoots[I];
287ccf765cfSMircea Trofin     __sanitizer::GenericScopedLock<__sanitizer::StaticSpinMutex> Lock(
288ccf765cfSMircea Trofin         &Root->Taken);
289ccf765cfSMircea Trofin     for (auto *Mem = Root->FirstMemBlock; Mem; Mem = Mem->next())
290*f32e5bdcSMircea Trofin       ++NumMemUnits;
291ccf765cfSMircea Trofin 
292e4763ca8SMircea Trofin     resetContextNode(*Root->FirstNode);
293ccf765cfSMircea Trofin   }
294*f32e5bdcSMircea Trofin   __sanitizer::Printf("[ctxprof] Initial NumMemUnits: %zu \n", NumMemUnits);
295ccf765cfSMircea Trofin }
296ccf765cfSMircea Trofin 
297e4763ca8SMircea Trofin bool __llvm_ctx_profile_fetch(void *Data,
298e4763ca8SMircea Trofin                               bool (*Writer)(void *W, const ContextNode &)) {
299ccf765cfSMircea Trofin   assert(Writer);
300ccf765cfSMircea Trofin   __sanitizer::GenericScopedLock<__sanitizer::SpinMutex> Lock(
301ccf765cfSMircea Trofin       &AllContextsMutex);
302ccf765cfSMircea Trofin 
303ccf765cfSMircea Trofin   for (int I = 0, E = AllContextRoots.Size(); I < E; ++I) {
304ccf765cfSMircea Trofin     auto *Root = AllContextRoots[I];
305ccf765cfSMircea Trofin     __sanitizer::GenericScopedLock<__sanitizer::StaticSpinMutex> TakenLock(
306ccf765cfSMircea Trofin         &Root->Taken);
307ccf765cfSMircea Trofin     if (!validate(Root)) {
308ccf765cfSMircea Trofin       __sanitizer::Printf("[ctxprof] Contextual Profile is %s\n", "invalid");
309ccf765cfSMircea Trofin       return false;
310ccf765cfSMircea Trofin     }
311ccf765cfSMircea Trofin     if (!Writer(Data, *Root->FirstNode))
312ccf765cfSMircea Trofin       return false;
313ccf765cfSMircea Trofin   }
314ccf765cfSMircea Trofin   return true;
315ccf765cfSMircea Trofin }
316ccf765cfSMircea Trofin 
317ccf765cfSMircea Trofin void __llvm_ctx_profile_free() {
318ccf765cfSMircea Trofin   __sanitizer::GenericScopedLock<__sanitizer::SpinMutex> Lock(
319ccf765cfSMircea Trofin       &AllContextsMutex);
320ccf765cfSMircea Trofin   for (int I = 0, E = AllContextRoots.Size(); I < E; ++I)
321ccf765cfSMircea Trofin     for (auto *A = AllContextRoots[I]->FirstMemBlock; A;) {
322ccf765cfSMircea Trofin       auto *C = A;
323ccf765cfSMircea Trofin       A = A->next();
324ccf765cfSMircea Trofin       __sanitizer::InternalFree(C);
325ccf765cfSMircea Trofin     }
326ccf765cfSMircea Trofin   AllContextRoots.Reset();
327ccf765cfSMircea Trofin }
328