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
lprofGetLoadModuleSignature(void)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
__llvm_profile_check_compatibility(const char * ProfileData,uint64_t ProfileSize)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
signextIfWin64(void * V)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
getDistanceFromCounterToValueProf(const __llvm_profile_header * const Header)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
__llvm_profile_merge_from_buffer(const char * ProfileData,uint64_t ProfileSize)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