xref: /freebsd/contrib/llvm-project/compiler-rt/lib/ctx_profile/CtxInstrContextNode.h (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1 //===--- CtxInstrContextNode.h - Contextual Profile Node --------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //==============================================================================
9 //
10 // NOTE!
11 // llvm/lib/ProfileData/CtxInstrContextNode.h and
12 //   compiler-rt/lib/ctx_profile/CtxInstrContextNode.h
13 // must be exact copies of eachother
14 //
15 // compiler-rt creates these objects as part of the instrumentation runtime for
16 // contextual profiling. LLVM only consumes them to convert a contextual tree
17 // to a bitstream.
18 //
19 //==============================================================================
20 
21 /// The contextual profile is a directed tree where each node has one parent. A
22 /// node (ContextNode) corresponds to a function activation. The root of the
23 /// tree is at a function that was marked as entrypoint to the compiler. A node
24 /// stores counter values for edges and a vector of subcontexts. These are the
25 /// contexts of callees. The index in the subcontext vector corresponds to the
26 /// index of the callsite (as was instrumented via llvm.instrprof.callsite). At
27 /// that index we find a linked list, potentially empty, of ContextNodes. Direct
28 /// calls will have 0 or 1 values in the linked list, but indirect callsites may
29 /// have more.
30 ///
31 /// The ContextNode has a fixed sized header describing it - the GUID of the
32 /// function, the size of the counter and callsite vectors. It is also an
33 /// (intrusive) linked list for the purposes of the indirect call case above.
34 ///
35 /// Allocation is expected to happen on an Arena. The allocation lays out inline
36 /// the counter and subcontexts vectors. The class offers APIs to correctly
37 /// reference the latter.
38 ///
39 /// The layout is as follows:
40 ///
41 /// [[declared fields][counters vector][vector of ptrs to subcontexts]]
42 ///
43 /// See also documentation on the counters and subContexts members below.
44 ///
45 /// The structure of the ContextNode is known to LLVM, because LLVM needs to:
46 ///   (1) increment counts, and
47 ///   (2) form a GEP for the position in the subcontext list of a callsite
48 /// This means changes to LLVM contextual profile lowering and changes here
49 /// must be coupled.
50 /// Note: the header content isn't interesting to LLVM (other than its size)
51 ///
52 /// Part of contextual collection is the notion of "scratch contexts". These are
53 /// buffers that are "large enough" to allow for memory-safe acceses during
54 /// counter increments - meaning the counter increment code in LLVM doesn't need
55 /// to be concerned with memory safety. Their subcontexts never get populated,
56 /// though. The runtime code here produces and recognizes them.
57 
58 #ifndef LLVM_PROFILEDATA_CTXINSTRCONTEXTNODE_H
59 #define LLVM_PROFILEDATA_CTXINSTRCONTEXTNODE_H
60 
61 #include <stdint.h>
62 #include <stdlib.h>
63 
64 namespace llvm {
65 namespace ctx_profile {
66 using GUID = uint64_t;
67 
68 class ContextNode final {
69   const GUID Guid;
70   ContextNode *const Next;
71   const uint32_t NrCounters;
72   const uint32_t NrCallsites;
73 
74 public:
75   ContextNode(GUID Guid, uint32_t NrCounters, uint32_t NrCallsites,
76               ContextNode *Next = nullptr)
77       : Guid(Guid), Next(Next), NrCounters(NrCounters),
78         NrCallsites(NrCallsites) {}
79 
80   static inline size_t getAllocSize(uint32_t NrCounters, uint32_t NrCallsites) {
81     return sizeof(ContextNode) + sizeof(uint64_t) * NrCounters +
82            sizeof(ContextNode *) * NrCallsites;
83   }
84 
85   // The counters vector starts right after the static header.
86   uint64_t *counters() {
87     ContextNode *addr_after = &(this[1]);
88     return reinterpret_cast<uint64_t *>(addr_after);
89   }
90 
91   uint32_t counters_size() const { return NrCounters; }
92   uint32_t callsites_size() const { return NrCallsites; }
93 
94   const uint64_t *counters() const {
95     return const_cast<ContextNode *>(this)->counters();
96   }
97 
98   // The subcontexts vector starts right after the end of the counters vector.
99   ContextNode **subContexts() {
100     return reinterpret_cast<ContextNode **>(&(counters()[NrCounters]));
101   }
102 
103   ContextNode *const *subContexts() const {
104     return const_cast<ContextNode *>(this)->subContexts();
105   }
106 
107   GUID guid() const { return Guid; }
108   ContextNode *next() const { return Next; }
109 
110   size_t size() const { return getAllocSize(NrCounters, NrCallsites); }
111 
112   uint64_t entrycount() const { return counters()[0]; }
113 };
114 } // namespace ctx_profile
115 } // namespace llvm
116 #endif