1 /*===- InstrProfilingMerge.c - Profile in-process Merging ---------------===*\
3 |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 |* See https://llvm.org/LICENSE.txt for license information.
5 |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 |*===----------------------------------------------------------------------===*
8 |* This file defines the API needed for in-process merging of profile data
9 |* stored in memory buffer.
10 \*===---------------------------------------------------------------------===*/
12 #include "InstrProfiling.h"
13 #include "InstrProfilingInternal.h"
14 #include "InstrProfilingUtil.h"
16 #define INSTR_PROF_VALUE_PROF_DATA
17 #include "profile/InstrProfData.inc"
19 COMPILER_RT_VISIBILITY
20 void (*VPMergeHook
)(ValueProfData
*, __llvm_profile_data
*);
22 COMPILER_RT_VISIBILITY
23 uint64_t lprofGetLoadModuleSignature(void) {
24 /* A very fast way to compute a module signature. */
25 uint64_t Version
= __llvm_profile_get_version();
26 uint64_t NumCounters
= __llvm_profile_get_num_counters(
27 __llvm_profile_begin_counters(), __llvm_profile_end_counters());
28 uint64_t NumData
= __llvm_profile_get_num_data(__llvm_profile_begin_data(),
29 __llvm_profile_end_data());
31 (uint64_t)(__llvm_profile_end_names() - __llvm_profile_begin_names());
33 (uint64_t)(__llvm_profile_end_vnodes() - __llvm_profile_begin_vnodes());
34 const __llvm_profile_data
*FirstD
= __llvm_profile_begin_data();
36 return (NamesSize
<< 40) + (NumCounters
<< 30) + (NumData
<< 20) +
37 (NumVnodes
<< 10) + (NumData
> 0 ? FirstD
->NameRef
: 0) + Version
+
38 __llvm_profile_get_magic();
41 /* Returns 1 if profile is not structurally compatible. */
42 COMPILER_RT_VISIBILITY
43 int __llvm_profile_check_compatibility(const char *ProfileData
,
44 uint64_t ProfileSize
) {
45 /* Check profile header only for now */
46 __llvm_profile_header
*Header
= (__llvm_profile_header
*)ProfileData
;
47 __llvm_profile_data
*SrcDataStart
, *SrcDataEnd
, *SrcData
, *DstData
;
49 (__llvm_profile_data
*)(ProfileData
+ sizeof(__llvm_profile_header
) +
50 Header
->BinaryIdsSize
);
51 SrcDataEnd
= SrcDataStart
+ Header
->DataSize
;
53 if (ProfileSize
< sizeof(__llvm_profile_header
))
56 /* Check the header first. */
57 if (Header
->Magic
!= __llvm_profile_get_magic() ||
58 Header
->Version
!= __llvm_profile_get_version() ||
60 __llvm_profile_get_num_data(__llvm_profile_begin_data(),
61 __llvm_profile_end_data()) ||
62 Header
->CountersSize
!=
63 __llvm_profile_get_num_counters(__llvm_profile_begin_counters(),
64 __llvm_profile_end_counters()) ||
65 Header
->NamesSize
!= (uint64_t)(__llvm_profile_end_names() -
66 __llvm_profile_begin_names()) ||
67 Header
->ValueKindLast
!= IPVK_Last
)
71 sizeof(__llvm_profile_header
) + Header
->BinaryIdsSize
+
72 Header
->DataSize
* sizeof(__llvm_profile_data
) + Header
->NamesSize
+
73 Header
->CountersSize
* __llvm_profile_counter_entry_size())
76 for (SrcData
= SrcDataStart
,
77 DstData
= (__llvm_profile_data
*)__llvm_profile_begin_data();
78 SrcData
< SrcDataEnd
; ++SrcData
, ++DstData
) {
79 if (SrcData
->NameRef
!= DstData
->NameRef
||
80 SrcData
->FuncHash
!= DstData
->FuncHash
||
81 SrcData
->NumCounters
!= DstData
->NumCounters
)
89 static uintptr_t signextIfWin64(void *V
) {
91 return (uintptr_t)(int32_t)(uintptr_t)V
;
97 COMPILER_RT_VISIBILITY
98 int __llvm_profile_merge_from_buffer(const char *ProfileData
,
99 uint64_t ProfileSize
) {
100 if (__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE
) {
103 "Debug info correlation does not support profile merging at runtime. "
104 "Instead, merge raw profiles using the llvm-profdata tool.");
108 __llvm_profile_data
*SrcDataStart
, *SrcDataEnd
, *SrcData
, *DstData
;
109 __llvm_profile_header
*Header
= (__llvm_profile_header
*)ProfileData
;
110 char *SrcCountersStart
;
111 const char *SrcNameStart
;
112 const char *SrcValueProfDataStart
, *SrcValueProfData
;
113 uintptr_t CountersDelta
= Header
->CountersDelta
;
116 (__llvm_profile_data
*)(ProfileData
+ sizeof(__llvm_profile_header
) +
117 Header
->BinaryIdsSize
);
118 SrcDataEnd
= SrcDataStart
+ Header
->DataSize
;
119 SrcCountersStart
= (char *)SrcDataEnd
;
120 SrcNameStart
= SrcCountersStart
+
121 Header
->CountersSize
* __llvm_profile_counter_entry_size();
122 SrcValueProfDataStart
=
123 SrcNameStart
+ Header
->NamesSize
+
124 __llvm_profile_get_num_padding_bytes(Header
->NamesSize
);
125 if (SrcNameStart
< SrcCountersStart
)
128 for (SrcData
= SrcDataStart
,
129 DstData
= (__llvm_profile_data
*)__llvm_profile_begin_data(),
130 SrcValueProfData
= SrcValueProfDataStart
;
131 SrcData
< SrcDataEnd
; ++SrcData
, ++DstData
) {
132 // For the in-memory destination, CounterPtr is the distance from the start
133 // address of the data to the start address of the counter. On WIN64,
134 // CounterPtr is a truncated 32-bit value due to COFF limitation. Sign
135 // extend CounterPtr to get the original value.
137 (char *)((uintptr_t)DstData
+ signextIfWin64(DstData
->CounterPtr
));
140 // SrcData is a serialized representation of the memory image. We need to
141 // compute the in-buffer counter offset from the in-memory address distance.
142 // The initial CountersDelta is the in-memory address difference
143 // start(__llvm_prf_cnts)-start(__llvm_prf_data), so SrcData->CounterPtr -
144 // CountersDelta computes the offset into the in-buffer counter section.
146 // On WIN64, CountersDelta is truncated as well, so no need for signext.
148 SrcCountersStart
+ ((uintptr_t)SrcData
->CounterPtr
- CountersDelta
);
149 // CountersDelta needs to be decreased as we advance to the next data
151 CountersDelta
-= sizeof(*SrcData
);
152 unsigned NC
= SrcData
->NumCounters
;
155 if (SrcCounters
< SrcCountersStart
|| SrcCounters
>= SrcNameStart
||
156 (SrcCounters
+ __llvm_profile_counter_entry_size() * NC
) > SrcNameStart
)
158 for (unsigned I
= 0; I
< NC
; I
++) {
159 if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE
) {
160 // A value of zero signifies the function is covered.
161 DstCounters
[I
] &= SrcCounters
[I
];
163 ((uint64_t *)DstCounters
)[I
] += ((uint64_t *)SrcCounters
)[I
];
167 /* Now merge value profile data. */
171 for (unsigned I
= 0; I
<= IPVK_Last
; I
++)
172 NVK
+= (SrcData
->NumValueSites
[I
] != 0);
177 if (SrcValueProfData
>= ProfileData
+ ProfileSize
)
179 VPMergeHook((ValueProfData
*)SrcValueProfData
, DstData
);
181 SrcValueProfData
+ ((ValueProfData
*)SrcValueProfData
)->TotalSize
;