1 /*===- InstrProfilingValue.c - Support library for PGO instrumentation ----===*\ 2 |* 3 |* The LLVM Compiler Infrastructure 4 |* 5 |* This file is distributed under the University of Illinois Open Source 6 |* License. See LICENSE.TXT for details. 7 |* 8 \*===----------------------------------------------------------------------===*/ 9 10 #include "InstrProfiling.h" 11 #include "InstrProfilingInternal.h" 12 #include <limits.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #define INSTR_PROF_VALUE_PROF_DATA 17 #define INSTR_PROF_COMMON_API_IMPL 18 #include "InstrProfData.inc" 19 20 #define PROF_OOM(Msg) PROF_ERR(Msg ":%s\n", "Out of memory"); 21 #define PROF_OOM_RETURN(Msg) \ 22 { \ 23 PROF_OOM(Msg) \ 24 free(ValueDataArray); \ 25 return NULL; \ 26 } 27 28 #if COMPILER_RT_HAS_ATOMICS != 1 29 COMPILER_RT_VISIBILITY 30 uint32_t BoolCmpXchg(void **Ptr, void *OldV, void *NewV) { 31 void *R = *Ptr; 32 if (R == OldV) { 33 *Ptr = NewV; 34 return 1; 35 } 36 return 0; 37 } 38 #endif 39 40 /* This method is only used in value profiler mock testing. */ 41 COMPILER_RT_VISIBILITY void 42 __llvm_profile_set_num_value_sites(__llvm_profile_data *Data, 43 uint32_t ValueKind, uint16_t NumValueSites) { 44 *((uint16_t *)&Data->NumValueSites[ValueKind]) = NumValueSites; 45 } 46 47 /* This method is only used in value profiler mock testing. */ 48 COMPILER_RT_VISIBILITY const __llvm_profile_data * 49 __llvm_profile_iterate_data(const __llvm_profile_data *Data) { 50 return Data + 1; 51 } 52 53 /* This method is only used in value profiler mock testing. */ 54 COMPILER_RT_VISIBILITY void * 55 __llvm_get_function_addr(const __llvm_profile_data *Data) { 56 return Data->FunctionPointer; 57 } 58 59 /* Allocate an array that holds the pointers to the linked lists of 60 * value profile counter nodes. The number of element of the array 61 * is the total number of value profile sites instrumented. Returns 62 * 0 if allocation fails. 63 */ 64 65 static int allocateValueProfileCounters(__llvm_profile_data *Data) { 66 uint64_t NumVSites = 0; 67 uint32_t VKI; 68 for (VKI = IPVK_First; VKI <= IPVK_Last; ++VKI) 69 NumVSites += Data->NumValueSites[VKI]; 70 71 ValueProfNode **Mem = 72 (ValueProfNode **)calloc(NumVSites, sizeof(ValueProfNode *)); 73 if (!Mem) 74 return 0; 75 if (!COMPILER_RT_BOOL_CMPXCHG(&Data->Values, 0, Mem)) { 76 free(Mem); 77 return 0; 78 } 79 return 1; 80 } 81 82 COMPILER_RT_VISIBILITY void 83 __llvm_profile_instrument_target(uint64_t TargetValue, void *Data, 84 uint32_t CounterIndex) { 85 86 __llvm_profile_data *PData = (__llvm_profile_data *)Data; 87 if (!PData) 88 return; 89 90 if (!PData->Values) { 91 if (!allocateValueProfileCounters(PData)) 92 return; 93 } 94 95 ValueProfNode **ValueCounters = (ValueProfNode **)PData->Values; 96 ValueProfNode *PrevVNode = NULL; 97 ValueProfNode *CurrentVNode = ValueCounters[CounterIndex]; 98 99 uint8_t VDataCount = 0; 100 while (CurrentVNode) { 101 if (TargetValue == CurrentVNode->VData.Value) { 102 CurrentVNode->VData.Count++; 103 return; 104 } 105 PrevVNode = CurrentVNode; 106 CurrentVNode = CurrentVNode->Next; 107 ++VDataCount; 108 } 109 110 if (VDataCount >= INSTR_PROF_MAX_NUM_VAL_PER_SITE) 111 return; 112 113 CurrentVNode = (ValueProfNode *)calloc(1, sizeof(ValueProfNode)); 114 if (!CurrentVNode) 115 return; 116 117 CurrentVNode->VData.Value = TargetValue; 118 CurrentVNode->VData.Count++; 119 120 uint32_t Success = 0; 121 if (!ValueCounters[CounterIndex]) 122 Success = 123 COMPILER_RT_BOOL_CMPXCHG(&ValueCounters[CounterIndex], 0, CurrentVNode); 124 else if (PrevVNode && !PrevVNode->Next) 125 Success = COMPILER_RT_BOOL_CMPXCHG(&(PrevVNode->Next), 0, CurrentVNode); 126 127 if (!Success) { 128 free(CurrentVNode); 129 return; 130 } 131 } 132 133 COMPILER_RT_VISIBILITY ValueProfData ** 134 __llvm_profile_gather_value_data(uint64_t *ValueDataSize) { 135 size_t S = 0; 136 __llvm_profile_data *I; 137 ValueProfData **ValueDataArray; 138 139 const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); 140 const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); 141 142 if (!ValueDataSize) 143 return NULL; 144 145 ValueDataArray = 146 (ValueProfData **)calloc(DataEnd - DataBegin, sizeof(void *)); 147 if (!ValueDataArray) 148 PROF_OOM_RETURN("Failed to write value profile data "); 149 150 /* 151 * Compute the total Size of the buffer to hold ValueProfData 152 * structures for functions with value profile data. 153 */ 154 for (I = (__llvm_profile_data *)DataBegin; I != DataEnd; ++I) { 155 ValueProfRuntimeRecord R; 156 if (initializeValueProfRuntimeRecord(&R, I->NumValueSites, I->Values)) 157 PROF_OOM_RETURN("Failed to write value profile data "); 158 159 /* Compute the size of ValueProfData from this runtime record. */ 160 if (getNumValueKindsRT(&R) != 0) { 161 ValueProfData *VD = NULL; 162 uint32_t VS = getValueProfDataSizeRT(&R); 163 VD = (ValueProfData *)calloc(VS, sizeof(uint8_t)); 164 if (!VD) 165 PROF_OOM_RETURN("Failed to write value profile data "); 166 serializeValueProfDataFromRT(&R, VD); 167 ValueDataArray[I - DataBegin] = VD; 168 S += VS; 169 } 170 finalizeValueProfRuntimeRecord(&R); 171 } 172 173 if (!S) { 174 free(ValueDataArray); 175 ValueDataArray = NULL; 176 } 177 178 *ValueDataSize = S; 179 return ValueDataArray; 180 } 181