1 /*===- InstrProfilingMerge.c - Profile in-process Merging  ---------------===*\
2 |*
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
6 |*
7 |*===----------------------------------------------------------------------===*
8 |* This file defines the API needed for in-process merging of profile data
9 |* stored in memory buffer.
10 \*===---------------------------------------------------------------------===*/
11 
12 #include "InstrProfiling.h"
13 #include "InstrProfilingInternal.h"
14 #include "InstrProfilingUtil.h"
15 
16 #define INSTR_PROF_VALUE_PROF_DATA
17 #include "profile/InstrProfData.inc"
18 
19 COMPILER_RT_VISIBILITY
20 void (*VPMergeHook)(ValueProfData *, __llvm_profile_data *);
21 
22 COMPILER_RT_VISIBILITY
23 uint64_t lprofGetLoadModuleSignature() {
24   /* A very fast way to compute a module signature.  */
25   uint64_t CounterSize = (uint64_t)(__llvm_profile_end_counters() -
26                                     __llvm_profile_begin_counters());
27   uint64_t DataSize = __llvm_profile_get_data_size(__llvm_profile_begin_data(),
28                                                    __llvm_profile_end_data());
29   uint64_t NamesSize =
30       (uint64_t)(__llvm_profile_end_names() - __llvm_profile_begin_names());
31   uint64_t NumVnodes =
32       (uint64_t)(__llvm_profile_end_vnodes() - __llvm_profile_begin_vnodes());
33   const __llvm_profile_data *FirstD = __llvm_profile_begin_data();
34 
35   return (NamesSize << 40) + (CounterSize << 30) + (DataSize << 20) +
36          (NumVnodes << 10) + (DataSize > 0 ? FirstD->NameRef : 0);
37 }
38 
39 /* Returns 1 if profile is not structurally compatible.  */
40 COMPILER_RT_VISIBILITY
41 int __llvm_profile_check_compatibility(const char *ProfileData,
42                                        uint64_t ProfileSize) {
43   /* Check profile header only for now  */
44   __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
45   __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
46   SrcDataStart =
47       (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header));
48   SrcDataEnd = SrcDataStart + Header->DataSize;
49 
50   if (ProfileSize < sizeof(__llvm_profile_header))
51     return 1;
52 
53   /* Check the header first.  */
54   if (Header->Magic != __llvm_profile_get_magic() ||
55       Header->Version != __llvm_profile_get_version() ||
56       Header->DataSize !=
57           __llvm_profile_get_data_size(__llvm_profile_begin_data(),
58                                        __llvm_profile_end_data()) ||
59       Header->CountersSize != (uint64_t)(__llvm_profile_end_counters() -
60                                          __llvm_profile_begin_counters()) ||
61       Header->NamesSize != (uint64_t)(__llvm_profile_end_names() -
62                                       __llvm_profile_begin_names()) ||
63       Header->ValueKindLast != IPVK_Last)
64     return 1;
65 
66   if (ProfileSize < sizeof(__llvm_profile_header) +
67                         Header->DataSize * sizeof(__llvm_profile_data) +
68                         Header->NamesSize + Header->CountersSize)
69     return 1;
70 
71   for (SrcData = SrcDataStart,
72        DstData = (__llvm_profile_data *)__llvm_profile_begin_data();
73        SrcData < SrcDataEnd; ++SrcData, ++DstData) {
74     if (SrcData->NameRef != DstData->NameRef ||
75         SrcData->FuncHash != DstData->FuncHash ||
76         SrcData->NumCounters != DstData->NumCounters)
77       return 1;
78   }
79 
80   /* Matched! */
81   return 0;
82 }
83 
84 COMPILER_RT_VISIBILITY
85 void __llvm_profile_merge_from_buffer(const char *ProfileData,
86                                       uint64_t ProfileSize) {
87   __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
88   __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
89   uint64_t *SrcCountersStart;
90   const char *SrcNameStart;
91   ValueProfData *SrcValueProfDataStart, *SrcValueProfData;
92 
93   SrcDataStart =
94       (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header));
95   SrcDataEnd = SrcDataStart + Header->DataSize;
96   SrcCountersStart = (uint64_t *)SrcDataEnd;
97   SrcNameStart = (const char *)(SrcCountersStart + Header->CountersSize);
98   SrcValueProfDataStart =
99       (ValueProfData *)(SrcNameStart + Header->NamesSize +
100                         __llvm_profile_get_num_padding_bytes(
101                             Header->NamesSize));
102 
103   for (SrcData = SrcDataStart,
104       DstData = (__llvm_profile_data *)__llvm_profile_begin_data(),
105       SrcValueProfData = SrcValueProfDataStart;
106        SrcData < SrcDataEnd; ++SrcData, ++DstData) {
107     uint64_t *SrcCounters;
108     uint64_t *DstCounters = (uint64_t *)DstData->CounterPtr;
109     unsigned I, NC, NVK = 0;
110 
111     NC = SrcData->NumCounters;
112     SrcCounters = SrcCountersStart +
113                   ((size_t)SrcData->CounterPtr - Header->CountersDelta) /
114                       sizeof(uint64_t);
115     for (I = 0; I < NC; I++)
116       DstCounters[I] += SrcCounters[I];
117 
118     /* Now merge value profile data.  */
119     if (!VPMergeHook)
120       continue;
121 
122     for (I = 0; I <= IPVK_Last; I++)
123       NVK += (SrcData->NumValueSites[I] != 0);
124 
125     if (!NVK)
126       continue;
127 
128     VPMergeHook(SrcValueProfData, DstData);
129     SrcValueProfData = (ValueProfData *)((char *)SrcValueProfData +
130                                          SrcValueProfData->TotalSize);
131   }
132 }
133