13cab2bb3Spatrick /*===- InstrProfilingValue.c - Support library for PGO instrumentation ----===*\
23cab2bb3Spatrick |*
33cab2bb3Spatrick |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick |* See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick |*
73cab2bb3Spatrick \*===----------------------------------------------------------------------===*/
83cab2bb3Spatrick
9d89ec533Spatrick #include <assert.h>
103cab2bb3Spatrick #include <limits.h>
113cab2bb3Spatrick #include <stdio.h>
123cab2bb3Spatrick #include <stdlib.h>
133cab2bb3Spatrick #include <string.h>
143cab2bb3Spatrick
153cab2bb3Spatrick #include "InstrProfiling.h"
163cab2bb3Spatrick #include "InstrProfilingInternal.h"
173cab2bb3Spatrick #include "InstrProfilingUtil.h"
183cab2bb3Spatrick
193cab2bb3Spatrick #define INSTR_PROF_VALUE_PROF_DATA
203cab2bb3Spatrick #define INSTR_PROF_COMMON_API_IMPL
21d89ec533Spatrick #define INSTR_PROF_VALUE_PROF_MEMOP_API
223cab2bb3Spatrick #include "profile/InstrProfData.inc"
233cab2bb3Spatrick
243cab2bb3Spatrick static int hasStaticCounters = 1;
253cab2bb3Spatrick static int OutOfNodesWarnings = 0;
263cab2bb3Spatrick static int hasNonDefaultValsPerSite = 0;
273cab2bb3Spatrick #define INSTR_PROF_MAX_VP_WARNS 10
28d89ec533Spatrick #define INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE 24
293cab2bb3Spatrick #define INSTR_PROF_VNODE_POOL_SIZE 1024
303cab2bb3Spatrick
313cab2bb3Spatrick #ifndef _MSC_VER
323cab2bb3Spatrick /* A shared static pool in addition to the vnodes statically
333cab2bb3Spatrick * allocated by the compiler. */
343cab2bb3Spatrick COMPILER_RT_VISIBILITY ValueProfNode
353cab2bb3Spatrick lprofValueProfNodes[INSTR_PROF_VNODE_POOL_SIZE] COMPILER_RT_SECTION(
363cab2bb3Spatrick COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME);
373cab2bb3Spatrick #endif
383cab2bb3Spatrick
393cab2bb3Spatrick COMPILER_RT_VISIBILITY uint32_t VPMaxNumValsPerSite =
403cab2bb3Spatrick INSTR_PROF_DEFAULT_NUM_VAL_PER_SITE;
413cab2bb3Spatrick
lprofSetupValueProfiler(void)42*810390e3Srobert COMPILER_RT_VISIBILITY void lprofSetupValueProfiler(void) {
433cab2bb3Spatrick const char *Str = 0;
443cab2bb3Spatrick Str = getenv("LLVM_VP_MAX_NUM_VALS_PER_SITE");
453cab2bb3Spatrick if (Str && Str[0]) {
463cab2bb3Spatrick VPMaxNumValsPerSite = atoi(Str);
473cab2bb3Spatrick hasNonDefaultValsPerSite = 1;
483cab2bb3Spatrick }
493cab2bb3Spatrick if (VPMaxNumValsPerSite > INSTR_PROF_MAX_NUM_VAL_PER_SITE)
503cab2bb3Spatrick VPMaxNumValsPerSite = INSTR_PROF_MAX_NUM_VAL_PER_SITE;
513cab2bb3Spatrick }
523cab2bb3Spatrick
lprofSetMaxValsPerSite(uint32_t MaxVals)533cab2bb3Spatrick COMPILER_RT_VISIBILITY void lprofSetMaxValsPerSite(uint32_t MaxVals) {
543cab2bb3Spatrick VPMaxNumValsPerSite = MaxVals;
553cab2bb3Spatrick hasNonDefaultValsPerSite = 1;
563cab2bb3Spatrick }
573cab2bb3Spatrick
583cab2bb3Spatrick /* This method is only used in value profiler mock testing. */
593cab2bb3Spatrick COMPILER_RT_VISIBILITY void
__llvm_profile_set_num_value_sites(__llvm_profile_data * Data,uint32_t ValueKind,uint16_t NumValueSites)603cab2bb3Spatrick __llvm_profile_set_num_value_sites(__llvm_profile_data *Data,
613cab2bb3Spatrick uint32_t ValueKind, uint16_t NumValueSites) {
623cab2bb3Spatrick *((uint16_t *)&Data->NumValueSites[ValueKind]) = NumValueSites;
633cab2bb3Spatrick }
643cab2bb3Spatrick
653cab2bb3Spatrick /* This method is only used in value profiler mock testing. */
663cab2bb3Spatrick COMPILER_RT_VISIBILITY const __llvm_profile_data *
__llvm_profile_iterate_data(const __llvm_profile_data * Data)673cab2bb3Spatrick __llvm_profile_iterate_data(const __llvm_profile_data *Data) {
683cab2bb3Spatrick return Data + 1;
693cab2bb3Spatrick }
703cab2bb3Spatrick
713cab2bb3Spatrick /* This method is only used in value profiler mock testing. */
723cab2bb3Spatrick COMPILER_RT_VISIBILITY void *
__llvm_get_function_addr(const __llvm_profile_data * Data)733cab2bb3Spatrick __llvm_get_function_addr(const __llvm_profile_data *Data) {
743cab2bb3Spatrick return Data->FunctionPointer;
753cab2bb3Spatrick }
763cab2bb3Spatrick
773cab2bb3Spatrick /* Allocate an array that holds the pointers to the linked lists of
783cab2bb3Spatrick * value profile counter nodes. The number of element of the array
793cab2bb3Spatrick * is the total number of value profile sites instrumented. Returns
803cab2bb3Spatrick * 0 if allocation fails.
813cab2bb3Spatrick */
823cab2bb3Spatrick
allocateValueProfileCounters(__llvm_profile_data * Data)833cab2bb3Spatrick static int allocateValueProfileCounters(__llvm_profile_data *Data) {
843cab2bb3Spatrick uint64_t NumVSites = 0;
853cab2bb3Spatrick uint32_t VKI;
863cab2bb3Spatrick
873cab2bb3Spatrick /* This function will never be called when value site array is allocated
883cab2bb3Spatrick statically at compile time. */
893cab2bb3Spatrick hasStaticCounters = 0;
903cab2bb3Spatrick /* When dynamic allocation is enabled, allow tracking the max number of
913cab2bb3Spatrick * values allowd. */
923cab2bb3Spatrick if (!hasNonDefaultValsPerSite)
933cab2bb3Spatrick VPMaxNumValsPerSite = INSTR_PROF_MAX_NUM_VAL_PER_SITE;
943cab2bb3Spatrick
953cab2bb3Spatrick for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI)
963cab2bb3Spatrick NumVSites += Data->NumValueSites[VKI];
973cab2bb3Spatrick
98d89ec533Spatrick // If NumVSites = 0, calloc is allowed to return a non-null pointer.
99d89ec533Spatrick assert(NumVSites > 0 && "NumVSites can't be zero");
1003cab2bb3Spatrick ValueProfNode **Mem =
1013cab2bb3Spatrick (ValueProfNode **)calloc(NumVSites, sizeof(ValueProfNode *));
1023cab2bb3Spatrick if (!Mem)
1033cab2bb3Spatrick return 0;
1043cab2bb3Spatrick if (!COMPILER_RT_BOOL_CMPXCHG(&Data->Values, 0, Mem)) {
1053cab2bb3Spatrick free(Mem);
1063cab2bb3Spatrick return 0;
1073cab2bb3Spatrick }
1083cab2bb3Spatrick return 1;
1093cab2bb3Spatrick }
1103cab2bb3Spatrick
allocateOneNode(void)1113cab2bb3Spatrick static ValueProfNode *allocateOneNode(void) {
1123cab2bb3Spatrick ValueProfNode *Node;
1133cab2bb3Spatrick
1143cab2bb3Spatrick if (!hasStaticCounters)
1153cab2bb3Spatrick return (ValueProfNode *)calloc(1, sizeof(ValueProfNode));
1163cab2bb3Spatrick
1173cab2bb3Spatrick /* Early check to avoid value wrapping around. */
1183cab2bb3Spatrick if (CurrentVNode + 1 > EndVNode) {
1193cab2bb3Spatrick if (OutOfNodesWarnings++ < INSTR_PROF_MAX_VP_WARNS) {
1203cab2bb3Spatrick PROF_WARN("Unable to track new values: %s. "
1213cab2bb3Spatrick " Consider using option -mllvm -vp-counters-per-site=<n> to "
1223cab2bb3Spatrick "allocate more"
1233cab2bb3Spatrick " value profile counters at compile time. \n",
1243cab2bb3Spatrick "Running out of static counters");
1253cab2bb3Spatrick }
1263cab2bb3Spatrick return 0;
1273cab2bb3Spatrick }
1283cab2bb3Spatrick Node = COMPILER_RT_PTR_FETCH_ADD(ValueProfNode, CurrentVNode, 1);
1293cab2bb3Spatrick /* Due to section padding, EndVNode point to a byte which is one pass
1303cab2bb3Spatrick * an incomplete VNode, so we need to skip the last incomplete node. */
1313cab2bb3Spatrick if (Node + 1 > EndVNode)
1323cab2bb3Spatrick return 0;
1333cab2bb3Spatrick
1343cab2bb3Spatrick return Node;
1353cab2bb3Spatrick }
1363cab2bb3Spatrick
1373cab2bb3Spatrick static COMPILER_RT_ALWAYS_INLINE void
instrumentTargetValueImpl(uint64_t TargetValue,void * Data,uint32_t CounterIndex,uint64_t CountValue)1383cab2bb3Spatrick instrumentTargetValueImpl(uint64_t TargetValue, void *Data,
1393cab2bb3Spatrick uint32_t CounterIndex, uint64_t CountValue) {
1403cab2bb3Spatrick __llvm_profile_data *PData = (__llvm_profile_data *)Data;
1413cab2bb3Spatrick if (!PData)
1423cab2bb3Spatrick return;
1433cab2bb3Spatrick if (!CountValue)
1443cab2bb3Spatrick return;
1453cab2bb3Spatrick if (!PData->Values) {
1463cab2bb3Spatrick if (!allocateValueProfileCounters(PData))
1473cab2bb3Spatrick return;
1483cab2bb3Spatrick }
1493cab2bb3Spatrick
1503cab2bb3Spatrick ValueProfNode **ValueCounters = (ValueProfNode **)PData->Values;
1513cab2bb3Spatrick ValueProfNode *PrevVNode = NULL;
1523cab2bb3Spatrick ValueProfNode *MinCountVNode = NULL;
1533cab2bb3Spatrick ValueProfNode *CurVNode = ValueCounters[CounterIndex];
1543cab2bb3Spatrick uint64_t MinCount = UINT64_MAX;
1553cab2bb3Spatrick
1563cab2bb3Spatrick uint8_t VDataCount = 0;
1573cab2bb3Spatrick while (CurVNode) {
1583cab2bb3Spatrick if (TargetValue == CurVNode->Value) {
1593cab2bb3Spatrick CurVNode->Count += CountValue;
1603cab2bb3Spatrick return;
1613cab2bb3Spatrick }
1623cab2bb3Spatrick if (CurVNode->Count < MinCount) {
1633cab2bb3Spatrick MinCount = CurVNode->Count;
1643cab2bb3Spatrick MinCountVNode = CurVNode;
1653cab2bb3Spatrick }
1663cab2bb3Spatrick PrevVNode = CurVNode;
1673cab2bb3Spatrick CurVNode = CurVNode->Next;
1683cab2bb3Spatrick ++VDataCount;
1693cab2bb3Spatrick }
1703cab2bb3Spatrick
1713cab2bb3Spatrick if (VDataCount >= VPMaxNumValsPerSite) {
1723cab2bb3Spatrick /* Bump down the min count node's count. If it reaches 0,
1733cab2bb3Spatrick * evict it. This eviction/replacement policy makes hot
1743cab2bb3Spatrick * targets more sticky while cold targets less so. In other
1753cab2bb3Spatrick * words, it makes it less likely for the hot targets to be
1763cab2bb3Spatrick * prematurally evicted during warmup/establishment period,
1773cab2bb3Spatrick * when their counts are still low. In a special case when
1783cab2bb3Spatrick * the number of values tracked is reduced to only one, this
1793cab2bb3Spatrick * policy will guarantee that the dominating target with >50%
1803cab2bb3Spatrick * total count will survive in the end. Note that this scheme
1813cab2bb3Spatrick * allows the runtime to track the min count node in an adaptive
1823cab2bb3Spatrick * manner. It can correct previous mistakes and eventually
1833cab2bb3Spatrick * lock on a cold target that is alread in stable state.
1843cab2bb3Spatrick *
1853cab2bb3Spatrick * In very rare cases, this replacement scheme may still lead
1863cab2bb3Spatrick * to target loss. For instance, out of \c N value slots, \c N-1
1873cab2bb3Spatrick * slots are occupied by luke warm targets during the warmup
1883cab2bb3Spatrick * period and the remaining one slot is competed by two or more
1893cab2bb3Spatrick * very hot targets. If those hot targets occur in an interleaved
1903cab2bb3Spatrick * way, none of them will survive (gain enough weight to throw out
1913cab2bb3Spatrick * other established entries) due to the ping-pong effect.
1923cab2bb3Spatrick * To handle this situation, user can choose to increase the max
1933cab2bb3Spatrick * number of tracked values per value site. Alternatively, a more
1943cab2bb3Spatrick * expensive eviction mechanism can be implemented. It requires
1953cab2bb3Spatrick * the runtime to track the total number of evictions per-site.
1963cab2bb3Spatrick * When the total number of evictions reaches certain threshold,
1973cab2bb3Spatrick * the runtime can wipe out more than one lowest count entries
1983cab2bb3Spatrick * to give space for hot targets.
1993cab2bb3Spatrick */
2003cab2bb3Spatrick if (MinCountVNode->Count <= CountValue) {
2013cab2bb3Spatrick CurVNode = MinCountVNode;
2023cab2bb3Spatrick CurVNode->Value = TargetValue;
2033cab2bb3Spatrick CurVNode->Count = CountValue;
2043cab2bb3Spatrick } else
2053cab2bb3Spatrick MinCountVNode->Count -= CountValue;
2063cab2bb3Spatrick
2073cab2bb3Spatrick return;
2083cab2bb3Spatrick }
2093cab2bb3Spatrick
2103cab2bb3Spatrick CurVNode = allocateOneNode();
2113cab2bb3Spatrick if (!CurVNode)
2123cab2bb3Spatrick return;
2133cab2bb3Spatrick CurVNode->Value = TargetValue;
2143cab2bb3Spatrick CurVNode->Count += CountValue;
2153cab2bb3Spatrick
2163cab2bb3Spatrick uint32_t Success = 0;
2173cab2bb3Spatrick if (!ValueCounters[CounterIndex])
2183cab2bb3Spatrick Success =
2193cab2bb3Spatrick COMPILER_RT_BOOL_CMPXCHG(&ValueCounters[CounterIndex], 0, CurVNode);
2203cab2bb3Spatrick else if (PrevVNode && !PrevVNode->Next)
2213cab2bb3Spatrick Success = COMPILER_RT_BOOL_CMPXCHG(&(PrevVNode->Next), 0, CurVNode);
2223cab2bb3Spatrick
2233cab2bb3Spatrick if (!Success && !hasStaticCounters) {
2243cab2bb3Spatrick free(CurVNode);
2253cab2bb3Spatrick return;
2263cab2bb3Spatrick }
2273cab2bb3Spatrick }
2283cab2bb3Spatrick
2293cab2bb3Spatrick COMPILER_RT_VISIBILITY void
__llvm_profile_instrument_target(uint64_t TargetValue,void * Data,uint32_t CounterIndex)2303cab2bb3Spatrick __llvm_profile_instrument_target(uint64_t TargetValue, void *Data,
2313cab2bb3Spatrick uint32_t CounterIndex) {
2323cab2bb3Spatrick instrumentTargetValueImpl(TargetValue, Data, CounterIndex, 1);
2333cab2bb3Spatrick }
2343cab2bb3Spatrick COMPILER_RT_VISIBILITY void
__llvm_profile_instrument_target_value(uint64_t TargetValue,void * Data,uint32_t CounterIndex,uint64_t CountValue)2353cab2bb3Spatrick __llvm_profile_instrument_target_value(uint64_t TargetValue, void *Data,
2363cab2bb3Spatrick uint32_t CounterIndex,
2373cab2bb3Spatrick uint64_t CountValue) {
2383cab2bb3Spatrick instrumentTargetValueImpl(TargetValue, Data, CounterIndex, CountValue);
2393cab2bb3Spatrick }
2403cab2bb3Spatrick
2413cab2bb3Spatrick /*
242d89ec533Spatrick * The target values are partitioned into multiple ranges. The range spec is
243d89ec533Spatrick * defined in InstrProfData.inc.
2443cab2bb3Spatrick */
245d89ec533Spatrick COMPILER_RT_VISIBILITY void
__llvm_profile_instrument_memop(uint64_t TargetValue,void * Data,uint32_t CounterIndex)246d89ec533Spatrick __llvm_profile_instrument_memop(uint64_t TargetValue, void *Data,
247d89ec533Spatrick uint32_t CounterIndex) {
248d89ec533Spatrick // Map the target value to the representative value of its range.
249d89ec533Spatrick uint64_t RepValue = InstrProfGetRangeRepValue(TargetValue);
250d89ec533Spatrick __llvm_profile_instrument_target(RepValue, Data, CounterIndex);
2513cab2bb3Spatrick }
2523cab2bb3Spatrick
2533cab2bb3Spatrick /*
2543cab2bb3Spatrick * A wrapper struct that represents value profile runtime data.
2553cab2bb3Spatrick * Like InstrProfRecord class which is used by profiling host tools,
256*810390e3Srobert * ValueProfRuntimeRecord also implements the abstract interfaces defined in
2573cab2bb3Spatrick * ValueProfRecordClosure so that the runtime data can be serialized using
2583cab2bb3Spatrick * shared C implementation.
2593cab2bb3Spatrick */
2603cab2bb3Spatrick typedef struct ValueProfRuntimeRecord {
2613cab2bb3Spatrick const __llvm_profile_data *Data;
2623cab2bb3Spatrick ValueProfNode **NodesKind[IPVK_Last + 1];
2633cab2bb3Spatrick uint8_t **SiteCountArray;
2643cab2bb3Spatrick } ValueProfRuntimeRecord;
2653cab2bb3Spatrick
2663cab2bb3Spatrick /* ValueProfRecordClosure Interface implementation. */
2673cab2bb3Spatrick
getNumValueSitesRT(const void * R,uint32_t VK)2683cab2bb3Spatrick static uint32_t getNumValueSitesRT(const void *R, uint32_t VK) {
2693cab2bb3Spatrick return ((const ValueProfRuntimeRecord *)R)->Data->NumValueSites[VK];
2703cab2bb3Spatrick }
2713cab2bb3Spatrick
getNumValueDataRT(const void * R,uint32_t VK)2723cab2bb3Spatrick static uint32_t getNumValueDataRT(const void *R, uint32_t VK) {
2733cab2bb3Spatrick uint32_t S = 0, I;
2743cab2bb3Spatrick const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
2753cab2bb3Spatrick if (Record->SiteCountArray[VK] == INSTR_PROF_NULLPTR)
2763cab2bb3Spatrick return 0;
2773cab2bb3Spatrick for (I = 0; I < Record->Data->NumValueSites[VK]; I++)
2783cab2bb3Spatrick S += Record->SiteCountArray[VK][I];
2793cab2bb3Spatrick return S;
2803cab2bb3Spatrick }
2813cab2bb3Spatrick
getNumValueDataForSiteRT(const void * R,uint32_t VK,uint32_t S)2823cab2bb3Spatrick static uint32_t getNumValueDataForSiteRT(const void *R, uint32_t VK,
2833cab2bb3Spatrick uint32_t S) {
2843cab2bb3Spatrick const ValueProfRuntimeRecord *Record = (const ValueProfRuntimeRecord *)R;
2853cab2bb3Spatrick return Record->SiteCountArray[VK][S];
2863cab2bb3Spatrick }
2873cab2bb3Spatrick
2883cab2bb3Spatrick static ValueProfRuntimeRecord RTRecord;
2893cab2bb3Spatrick static ValueProfRecordClosure RTRecordClosure = {
2903cab2bb3Spatrick &RTRecord, INSTR_PROF_NULLPTR, /* GetNumValueKinds */
2913cab2bb3Spatrick getNumValueSitesRT, getNumValueDataRT, getNumValueDataForSiteRT,
2923cab2bb3Spatrick INSTR_PROF_NULLPTR, /* RemapValueData */
2933cab2bb3Spatrick INSTR_PROF_NULLPTR, /* GetValueForSite, */
2943cab2bb3Spatrick INSTR_PROF_NULLPTR /* AllocValueProfData */
2953cab2bb3Spatrick };
2963cab2bb3Spatrick
2973cab2bb3Spatrick static uint32_t
initializeValueProfRuntimeRecord(const __llvm_profile_data * Data,uint8_t * SiteCountArray[])2983cab2bb3Spatrick initializeValueProfRuntimeRecord(const __llvm_profile_data *Data,
2993cab2bb3Spatrick uint8_t *SiteCountArray[]) {
3003cab2bb3Spatrick unsigned I, J, S = 0, NumValueKinds = 0;
3013cab2bb3Spatrick ValueProfNode **Nodes = (ValueProfNode **)Data->Values;
3023cab2bb3Spatrick RTRecord.Data = Data;
3033cab2bb3Spatrick RTRecord.SiteCountArray = SiteCountArray;
3043cab2bb3Spatrick for (I = 0; I <= IPVK_Last; I++) {
3053cab2bb3Spatrick uint16_t N = Data->NumValueSites[I];
3063cab2bb3Spatrick if (!N)
3073cab2bb3Spatrick continue;
3083cab2bb3Spatrick
3093cab2bb3Spatrick NumValueKinds++;
3103cab2bb3Spatrick
3113cab2bb3Spatrick RTRecord.NodesKind[I] = Nodes ? &Nodes[S] : INSTR_PROF_NULLPTR;
3123cab2bb3Spatrick for (J = 0; J < N; J++) {
3133cab2bb3Spatrick /* Compute value count for each site. */
3143cab2bb3Spatrick uint32_t C = 0;
3153cab2bb3Spatrick ValueProfNode *Site =
3163cab2bb3Spatrick Nodes ? RTRecord.NodesKind[I][J] : INSTR_PROF_NULLPTR;
3173cab2bb3Spatrick while (Site) {
3183cab2bb3Spatrick C++;
3193cab2bb3Spatrick Site = Site->Next;
3203cab2bb3Spatrick }
3213cab2bb3Spatrick if (C > UCHAR_MAX)
3223cab2bb3Spatrick C = UCHAR_MAX;
3233cab2bb3Spatrick RTRecord.SiteCountArray[I][J] = C;
3243cab2bb3Spatrick }
3253cab2bb3Spatrick S += N;
3263cab2bb3Spatrick }
3273cab2bb3Spatrick return NumValueKinds;
3283cab2bb3Spatrick }
3293cab2bb3Spatrick
getNextNValueData(uint32_t VK,uint32_t Site,InstrProfValueData * Dst,ValueProfNode * StartNode,uint32_t N)3303cab2bb3Spatrick static ValueProfNode *getNextNValueData(uint32_t VK, uint32_t Site,
3313cab2bb3Spatrick InstrProfValueData *Dst,
3323cab2bb3Spatrick ValueProfNode *StartNode, uint32_t N) {
3333cab2bb3Spatrick unsigned I;
3343cab2bb3Spatrick ValueProfNode *VNode = StartNode ? StartNode : RTRecord.NodesKind[VK][Site];
3353cab2bb3Spatrick for (I = 0; I < N; I++) {
3363cab2bb3Spatrick Dst[I].Value = VNode->Value;
3373cab2bb3Spatrick Dst[I].Count = VNode->Count;
3383cab2bb3Spatrick VNode = VNode->Next;
3393cab2bb3Spatrick }
3403cab2bb3Spatrick return VNode;
3413cab2bb3Spatrick }
3423cab2bb3Spatrick
getValueProfDataSizeWrapper(void)3433cab2bb3Spatrick static uint32_t getValueProfDataSizeWrapper(void) {
3443cab2bb3Spatrick return getValueProfDataSize(&RTRecordClosure);
3453cab2bb3Spatrick }
3463cab2bb3Spatrick
getNumValueDataForSiteWrapper(uint32_t VK,uint32_t S)3473cab2bb3Spatrick static uint32_t getNumValueDataForSiteWrapper(uint32_t VK, uint32_t S) {
3483cab2bb3Spatrick return getNumValueDataForSiteRT(&RTRecord, VK, S);
3493cab2bb3Spatrick }
3503cab2bb3Spatrick
3513cab2bb3Spatrick static VPDataReaderType TheVPDataReader = {
3523cab2bb3Spatrick initializeValueProfRuntimeRecord, getValueProfRecordHeaderSize,
3533cab2bb3Spatrick getFirstValueProfRecord, getNumValueDataForSiteWrapper,
3543cab2bb3Spatrick getValueProfDataSizeWrapper, getNextNValueData};
3553cab2bb3Spatrick
lprofGetVPDataReader(void)356*810390e3Srobert COMPILER_RT_VISIBILITY VPDataReaderType *lprofGetVPDataReader(void) {
3573cab2bb3Spatrick return &TheVPDataReader;
3583cab2bb3Spatrick }
359