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