10b57cec5SDimitry Andric /*===- InstrProfilingMerge.c - Profile in-process Merging ---------------===*\ 20b57cec5SDimitry Andric |* 30b57cec5SDimitry Andric |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric |* See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric |* 70b57cec5SDimitry Andric |*===----------------------------------------------------------------------===* 80b57cec5SDimitry Andric |* This file defines the API needed for in-process merging of profile data 90b57cec5SDimitry Andric |* stored in memory buffer. 100b57cec5SDimitry Andric \*===---------------------------------------------------------------------===*/ 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include "InstrProfiling.h" 130b57cec5SDimitry Andric #include "InstrProfilingInternal.h" 140b57cec5SDimitry Andric #include "InstrProfilingUtil.h" 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #define INSTR_PROF_VALUE_PROF_DATA 17480093f4SDimitry Andric #include "profile/InstrProfData.inc" 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 200b57cec5SDimitry Andric void (*VPMergeHook)(ValueProfData *, __llvm_profile_data *); 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 2381ad6265SDimitry Andric uint64_t lprofGetLoadModuleSignature(void) { 240b57cec5SDimitry Andric /* A very fast way to compute a module signature. */ 256e75b2fbSDimitry Andric uint64_t Version = __llvm_profile_get_version(); 2604eeddc0SDimitry Andric uint64_t NumCounters = __llvm_profile_get_num_counters( 2704eeddc0SDimitry Andric __llvm_profile_begin_counters(), __llvm_profile_end_counters()); 2804eeddc0SDimitry Andric uint64_t NumData = __llvm_profile_get_num_data(__llvm_profile_begin_data(), 290b57cec5SDimitry Andric __llvm_profile_end_data()); 300b57cec5SDimitry Andric uint64_t NamesSize = 310b57cec5SDimitry Andric (uint64_t)(__llvm_profile_end_names() - __llvm_profile_begin_names()); 320b57cec5SDimitry Andric uint64_t NumVnodes = 330b57cec5SDimitry Andric (uint64_t)(__llvm_profile_end_vnodes() - __llvm_profile_begin_vnodes()); 340b57cec5SDimitry Andric const __llvm_profile_data *FirstD = __llvm_profile_begin_data(); 350b57cec5SDimitry Andric 3604eeddc0SDimitry Andric return (NamesSize << 40) + (NumCounters << 30) + (NumData << 20) + 3704eeddc0SDimitry Andric (NumVnodes << 10) + (NumData > 0 ? FirstD->NameRef : 0) + Version + 384824e7fdSDimitry Andric __llvm_profile_get_magic(); 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric 4106c3fb27SDimitry Andric #ifdef __GNUC__ 4206c3fb27SDimitry Andric #pragma GCC diagnostic push 4306c3fb27SDimitry Andric #pragma GCC diagnostic ignored "-Wcast-qual" 447a6dacacSDimitry Andric #elif defined(__clang__) 457a6dacacSDimitry Andric #pragma clang diagnostic push 467a6dacacSDimitry Andric #pragma clang diagnostic ignored "-Wcast-qual" 4706c3fb27SDimitry Andric #endif 4806c3fb27SDimitry Andric 490b57cec5SDimitry Andric /* Returns 1 if profile is not structurally compatible. */ 500b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 510b57cec5SDimitry Andric int __llvm_profile_check_compatibility(const char *ProfileData, 520b57cec5SDimitry Andric uint64_t ProfileSize) { 530b57cec5SDimitry Andric __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData; 540b57cec5SDimitry Andric __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData; 550b57cec5SDimitry Andric SrcDataStart = 566e75b2fbSDimitry Andric (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header) + 576e75b2fbSDimitry Andric Header->BinaryIdsSize); 585f757f3fSDimitry Andric SrcDataEnd = SrcDataStart + Header->NumData; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric if (ProfileSize < sizeof(__llvm_profile_header)) 610b57cec5SDimitry Andric return 1; 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric /* Check the header first. */ 640b57cec5SDimitry Andric if (Header->Magic != __llvm_profile_get_magic() || 650b57cec5SDimitry Andric Header->Version != __llvm_profile_get_version() || 665f757f3fSDimitry Andric Header->NumData != 6704eeddc0SDimitry Andric __llvm_profile_get_num_data(__llvm_profile_begin_data(), 680b57cec5SDimitry Andric __llvm_profile_end_data()) || 695f757f3fSDimitry Andric Header->NumCounters != 7004eeddc0SDimitry Andric __llvm_profile_get_num_counters(__llvm_profile_begin_counters(), 7104eeddc0SDimitry Andric __llvm_profile_end_counters()) || 725f757f3fSDimitry Andric Header->NumBitmapBytes != 735f757f3fSDimitry Andric __llvm_profile_get_num_bitmap_bytes(__llvm_profile_begin_bitmap(), 745f757f3fSDimitry Andric __llvm_profile_end_bitmap()) || 755f757f3fSDimitry Andric Header->NamesSize != 765f757f3fSDimitry Andric __llvm_profile_get_name_size(__llvm_profile_begin_names(), 775f757f3fSDimitry Andric __llvm_profile_end_names()) || 780b57cec5SDimitry Andric Header->ValueKindLast != IPVK_Last) 790b57cec5SDimitry Andric return 1; 800b57cec5SDimitry Andric 8104eeddc0SDimitry Andric if (ProfileSize < 8204eeddc0SDimitry Andric sizeof(__llvm_profile_header) + Header->BinaryIdsSize + 835f757f3fSDimitry Andric Header->NumData * sizeof(__llvm_profile_data) + Header->NamesSize + 845f757f3fSDimitry Andric Header->NumCounters * __llvm_profile_counter_entry_size() + 855f757f3fSDimitry Andric Header->NumBitmapBytes) 860b57cec5SDimitry Andric return 1; 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric for (SrcData = SrcDataStart, 890b57cec5SDimitry Andric DstData = (__llvm_profile_data *)__llvm_profile_begin_data(); 900b57cec5SDimitry Andric SrcData < SrcDataEnd; ++SrcData, ++DstData) { 910b57cec5SDimitry Andric if (SrcData->NameRef != DstData->NameRef || 920b57cec5SDimitry Andric SrcData->FuncHash != DstData->FuncHash || 935f757f3fSDimitry Andric SrcData->NumCounters != DstData->NumCounters || 945f757f3fSDimitry Andric SrcData->NumBitmapBytes != DstData->NumBitmapBytes) 950b57cec5SDimitry Andric return 1; 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric /* Matched! */ 990b57cec5SDimitry Andric return 0; 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 102349cc55cSDimitry Andric static uintptr_t signextIfWin64(void *V) { 103349cc55cSDimitry Andric #ifdef _WIN64 104349cc55cSDimitry Andric return (uintptr_t)(int32_t)(uintptr_t)V; 105349cc55cSDimitry Andric #else 106349cc55cSDimitry Andric return (uintptr_t)V; 107349cc55cSDimitry Andric #endif 108349cc55cSDimitry Andric } 109349cc55cSDimitry Andric 110*0fca6ea1SDimitry Andric // Skip names section, vtable profile data section and vtable names section 111*0fca6ea1SDimitry Andric // for runtime profile merge. To merge runtime addresses from multiple 112*0fca6ea1SDimitry Andric // profiles collected from the same instrumented binary, the binary should be 113*0fca6ea1SDimitry Andric // loaded at fixed base address (e.g., build with -no-pie, or run with ASLR 114*0fca6ea1SDimitry Andric // disabled). In this set-up these three sections remain unchanged. 115*0fca6ea1SDimitry Andric static uint64_t 116*0fca6ea1SDimitry Andric getDistanceFromCounterToValueProf(const __llvm_profile_header *const Header) { 117*0fca6ea1SDimitry Andric const uint64_t VTableSectionSize = 118*0fca6ea1SDimitry Andric Header->NumVTables * sizeof(VTableProfData); 119*0fca6ea1SDimitry Andric const uint64_t PaddingBytesAfterVTableSection = 120*0fca6ea1SDimitry Andric __llvm_profile_get_num_padding_bytes(VTableSectionSize); 121*0fca6ea1SDimitry Andric const uint64_t VNamesSize = Header->VNamesSize; 122*0fca6ea1SDimitry Andric const uint64_t PaddingBytesAfterVNamesSize = 123*0fca6ea1SDimitry Andric __llvm_profile_get_num_padding_bytes(VNamesSize); 124*0fca6ea1SDimitry Andric return Header->NamesSize + 125*0fca6ea1SDimitry Andric __llvm_profile_get_num_padding_bytes(Header->NamesSize) + 126*0fca6ea1SDimitry Andric VTableSectionSize + PaddingBytesAfterVTableSection + VNamesSize + 127*0fca6ea1SDimitry Andric PaddingBytesAfterVNamesSize; 128*0fca6ea1SDimitry Andric } 129*0fca6ea1SDimitry Andric 1300b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 131fe6060f1SDimitry Andric int __llvm_profile_merge_from_buffer(const char *ProfileData, 1320b57cec5SDimitry Andric uint64_t ProfileSize) { 1335f757f3fSDimitry Andric if (__llvm_profile_get_version() & VARIANT_MASK_TEMPORAL_PROF) { 1345f757f3fSDimitry Andric PROF_ERR("%s\n", 1355f757f3fSDimitry Andric "Temporal profiles do not support profile merging at runtime. " 1360eae32dcSDimitry Andric "Instead, merge raw profiles using the llvm-profdata tool."); 1370eae32dcSDimitry Andric return 1; 1380eae32dcSDimitry Andric } 1390eae32dcSDimitry Andric 1400b57cec5SDimitry Andric __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData; 1410b57cec5SDimitry Andric __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData; 1425f757f3fSDimitry Andric char *SrcCountersStart, *DstCounter; 1435f757f3fSDimitry Andric const char *SrcCountersEnd, *SrcCounter; 1445f757f3fSDimitry Andric const char *SrcBitmapStart; 1450b57cec5SDimitry Andric const char *SrcNameStart; 146fe6060f1SDimitry Andric const char *SrcValueProfDataStart, *SrcValueProfData; 147349cc55cSDimitry Andric uintptr_t CountersDelta = Header->CountersDelta; 1485f757f3fSDimitry Andric uintptr_t BitmapDelta = Header->BitmapDelta; 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric SrcDataStart = 1516e75b2fbSDimitry Andric (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header) + 1526e75b2fbSDimitry Andric Header->BinaryIdsSize); 1535f757f3fSDimitry Andric SrcDataEnd = SrcDataStart + Header->NumData; 15404eeddc0SDimitry Andric SrcCountersStart = (char *)SrcDataEnd; 1555f757f3fSDimitry Andric SrcCountersEnd = SrcCountersStart + 1565f757f3fSDimitry Andric Header->NumCounters * __llvm_profile_counter_entry_size(); 1575f757f3fSDimitry Andric SrcBitmapStart = SrcCountersEnd; 1585f757f3fSDimitry Andric SrcNameStart = SrcBitmapStart + Header->NumBitmapBytes; 1590b57cec5SDimitry Andric SrcValueProfDataStart = 160*0fca6ea1SDimitry Andric SrcNameStart + getDistanceFromCounterToValueProf(Header); 1615f757f3fSDimitry Andric if (SrcNameStart < SrcCountersStart || SrcNameStart < SrcBitmapStart) 162fe6060f1SDimitry Andric return 1; 1630b57cec5SDimitry Andric 1645f757f3fSDimitry Andric // Merge counters by iterating the entire counter section when data section is 1655f757f3fSDimitry Andric // empty due to correlation. 1665f757f3fSDimitry Andric if (Header->NumData == 0) { 1675f757f3fSDimitry Andric for (SrcCounter = SrcCountersStart, 1685f757f3fSDimitry Andric DstCounter = __llvm_profile_begin_counters(); 1695f757f3fSDimitry Andric SrcCounter < SrcCountersEnd;) { 1705f757f3fSDimitry Andric if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE) { 1715f757f3fSDimitry Andric *DstCounter &= *SrcCounter; 1725f757f3fSDimitry Andric } else { 1735f757f3fSDimitry Andric *(uint64_t *)DstCounter += *(uint64_t *)SrcCounter; 1745f757f3fSDimitry Andric } 1755f757f3fSDimitry Andric SrcCounter += __llvm_profile_counter_entry_size(); 1765f757f3fSDimitry Andric DstCounter += __llvm_profile_counter_entry_size(); 1775f757f3fSDimitry Andric } 1785f757f3fSDimitry Andric return 0; 1795f757f3fSDimitry Andric } 1805f757f3fSDimitry Andric 1810b57cec5SDimitry Andric for (SrcData = SrcDataStart, 1820b57cec5SDimitry Andric DstData = (__llvm_profile_data *)__llvm_profile_begin_data(), 1830b57cec5SDimitry Andric SrcValueProfData = SrcValueProfDataStart; 1840b57cec5SDimitry Andric SrcData < SrcDataEnd; ++SrcData, ++DstData) { 185349cc55cSDimitry Andric // For the in-memory destination, CounterPtr is the distance from the start 186349cc55cSDimitry Andric // address of the data to the start address of the counter. On WIN64, 187349cc55cSDimitry Andric // CounterPtr is a truncated 32-bit value due to COFF limitation. Sign 188349cc55cSDimitry Andric // extend CounterPtr to get the original value. 18904eeddc0SDimitry Andric char *DstCounters = 19004eeddc0SDimitry Andric (char *)((uintptr_t)DstData + signextIfWin64(DstData->CounterPtr)); 1915f757f3fSDimitry Andric char *DstBitmap = 1925f757f3fSDimitry Andric (char *)((uintptr_t)DstData + signextIfWin64(DstData->BitmapPtr)); 193fe6060f1SDimitry Andric unsigned NVK = 0; 1940b57cec5SDimitry Andric 195349cc55cSDimitry Andric // SrcData is a serialized representation of the memory image. We need to 196349cc55cSDimitry Andric // compute the in-buffer counter offset from the in-memory address distance. 197349cc55cSDimitry Andric // The initial CountersDelta is the in-memory address difference 198349cc55cSDimitry Andric // start(__llvm_prf_cnts)-start(__llvm_prf_data), so SrcData->CounterPtr - 199349cc55cSDimitry Andric // CountersDelta computes the offset into the in-buffer counter section. 200349cc55cSDimitry Andric // 201349cc55cSDimitry Andric // On WIN64, CountersDelta is truncated as well, so no need for signext. 20204eeddc0SDimitry Andric char *SrcCounters = 20304eeddc0SDimitry Andric SrcCountersStart + ((uintptr_t)SrcData->CounterPtr - CountersDelta); 204349cc55cSDimitry Andric // CountersDelta needs to be decreased as we advance to the next data 205349cc55cSDimitry Andric // record. 206349cc55cSDimitry Andric CountersDelta -= sizeof(*SrcData); 207fe6060f1SDimitry Andric unsigned NC = SrcData->NumCounters; 208fe6060f1SDimitry Andric if (NC == 0) 209fe6060f1SDimitry Andric return 1; 21004eeddc0SDimitry Andric if (SrcCounters < SrcCountersStart || SrcCounters >= SrcNameStart || 21104eeddc0SDimitry Andric (SrcCounters + __llvm_profile_counter_entry_size() * NC) > SrcNameStart) 212fe6060f1SDimitry Andric return 1; 2131fd87a68SDimitry Andric for (unsigned I = 0; I < NC; I++) { 2141fd87a68SDimitry Andric if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE) { 2151fd87a68SDimitry Andric // A value of zero signifies the function is covered. 2161fd87a68SDimitry Andric DstCounters[I] &= SrcCounters[I]; 2171fd87a68SDimitry Andric } else { 21804eeddc0SDimitry Andric ((uint64_t *)DstCounters)[I] += ((uint64_t *)SrcCounters)[I]; 2191fd87a68SDimitry Andric } 2201fd87a68SDimitry Andric } 2210b57cec5SDimitry Andric 2225f757f3fSDimitry Andric const char *SrcBitmap = 2235f757f3fSDimitry Andric SrcBitmapStart + ((uintptr_t)SrcData->BitmapPtr - BitmapDelta); 2245f757f3fSDimitry Andric // BitmapDelta also needs to be decreased as we advance to the next data 2255f757f3fSDimitry Andric // record. 2265f757f3fSDimitry Andric BitmapDelta -= sizeof(*SrcData); 2275f757f3fSDimitry Andric unsigned NB = SrcData->NumBitmapBytes; 2285f757f3fSDimitry Andric // NumBitmapBytes may legitimately be 0. Just keep going. 2295f757f3fSDimitry Andric if (NB != 0) { 2305f757f3fSDimitry Andric if (SrcBitmap < SrcBitmapStart || (SrcBitmap + NB) > SrcNameStart) 2315f757f3fSDimitry Andric return 1; 2325f757f3fSDimitry Andric // Merge Src and Dst Bitmap bytes by simply ORing them together. 2335f757f3fSDimitry Andric for (unsigned I = 0; I < NB; I++) 2345f757f3fSDimitry Andric DstBitmap[I] |= SrcBitmap[I]; 2355f757f3fSDimitry Andric } 2365f757f3fSDimitry Andric 2370b57cec5SDimitry Andric /* Now merge value profile data. */ 2380b57cec5SDimitry Andric if (!VPMergeHook) 2390b57cec5SDimitry Andric continue; 2400b57cec5SDimitry Andric 241fe6060f1SDimitry Andric for (unsigned I = 0; I <= IPVK_Last; I++) 2420b57cec5SDimitry Andric NVK += (SrcData->NumValueSites[I] != 0); 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric if (!NVK) 2450b57cec5SDimitry Andric continue; 2460b57cec5SDimitry Andric 247fe6060f1SDimitry Andric if (SrcValueProfData >= ProfileData + ProfileSize) 248fe6060f1SDimitry Andric return 1; 249fe6060f1SDimitry Andric VPMergeHook((ValueProfData *)SrcValueProfData, DstData); 250fe6060f1SDimitry Andric SrcValueProfData = 251fe6060f1SDimitry Andric SrcValueProfData + ((ValueProfData *)SrcValueProfData)->TotalSize; 2520b57cec5SDimitry Andric } 253fe6060f1SDimitry Andric 254fe6060f1SDimitry Andric return 0; 2550b57cec5SDimitry Andric } 25606c3fb27SDimitry Andric 25706c3fb27SDimitry Andric #ifdef __GNUC__ 25806c3fb27SDimitry Andric #pragma GCC diagnostic pop 2597a6dacacSDimitry Andric #elif defined(__clang__) 2607a6dacacSDimitry Andric #pragma clang diagnostic pop 26106c3fb27SDimitry Andric #endif 262