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