1303235Sdim/*===- InstrProfilingMerge.c - Profile in-process Merging  ---------------===*\
2303235Sdim|*
3353358Sdim|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim|* See https://llvm.org/LICENSE.txt for license information.
5353358Sdim|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6303235Sdim|*
7303235Sdim|*===----------------------------------------------------------------------===*
8303235Sdim|* This file defines the API needed for in-process merging of profile data
9303235Sdim|* stored in memory buffer.
10303235Sdim\*===---------------------------------------------------------------------===*/
11303235Sdim
12303235Sdim#include "InstrProfiling.h"
13303235Sdim#include "InstrProfilingInternal.h"
14303235Sdim#include "InstrProfilingUtil.h"
15303235Sdim
16303235Sdim#define INSTR_PROF_VALUE_PROF_DATA
17360784Sdim#include "profile/InstrProfData.inc"
18303235Sdim
19303235SdimCOMPILER_RT_VISIBILITY
20341825Sdimvoid (*VPMergeHook)(ValueProfData *, __llvm_profile_data *);
21341825Sdim
22341825SdimCOMPILER_RT_VISIBILITY
23303235Sdimuint64_t lprofGetLoadModuleSignature() {
24303235Sdim  /* A very fast way to compute a module signature.  */
25303235Sdim  uint64_t CounterSize = (uint64_t)(__llvm_profile_end_counters() -
26303235Sdim                                    __llvm_profile_begin_counters());
27303235Sdim  uint64_t DataSize = __llvm_profile_get_data_size(__llvm_profile_begin_data(),
28303235Sdim                                                   __llvm_profile_end_data());
29303235Sdim  uint64_t NamesSize =
30303235Sdim      (uint64_t)(__llvm_profile_end_names() - __llvm_profile_begin_names());
31303235Sdim  uint64_t NumVnodes =
32303235Sdim      (uint64_t)(__llvm_profile_end_vnodes() - __llvm_profile_begin_vnodes());
33303235Sdim  const __llvm_profile_data *FirstD = __llvm_profile_begin_data();
34303235Sdim
35303235Sdim  return (NamesSize << 40) + (CounterSize << 30) + (DataSize << 20) +
36303235Sdim         (NumVnodes << 10) + (DataSize > 0 ? FirstD->NameRef : 0);
37303235Sdim}
38303235Sdim
39303235Sdim/* Returns 1 if profile is not structurally compatible.  */
40303235SdimCOMPILER_RT_VISIBILITY
41303235Sdimint __llvm_profile_check_compatibility(const char *ProfileData,
42303235Sdim                                       uint64_t ProfileSize) {
43303235Sdim  /* Check profile header only for now  */
44303235Sdim  __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
45303235Sdim  __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
46303235Sdim  SrcDataStart =
47303235Sdim      (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header));
48303235Sdim  SrcDataEnd = SrcDataStart + Header->DataSize;
49303235Sdim
50303235Sdim  if (ProfileSize < sizeof(__llvm_profile_header))
51303235Sdim    return 1;
52303235Sdim
53303235Sdim  /* Check the header first.  */
54303235Sdim  if (Header->Magic != __llvm_profile_get_magic() ||
55303235Sdim      Header->Version != __llvm_profile_get_version() ||
56303235Sdim      Header->DataSize !=
57303235Sdim          __llvm_profile_get_data_size(__llvm_profile_begin_data(),
58303235Sdim                                       __llvm_profile_end_data()) ||
59303235Sdim      Header->CountersSize != (uint64_t)(__llvm_profile_end_counters() -
60303235Sdim                                         __llvm_profile_begin_counters()) ||
61303235Sdim      Header->NamesSize != (uint64_t)(__llvm_profile_end_names() -
62303235Sdim                                      __llvm_profile_begin_names()) ||
63303235Sdim      Header->ValueKindLast != IPVK_Last)
64303235Sdim    return 1;
65303235Sdim
66303235Sdim  if (ProfileSize < sizeof(__llvm_profile_header) +
67303235Sdim                        Header->DataSize * sizeof(__llvm_profile_data) +
68303235Sdim                        Header->NamesSize + Header->CountersSize)
69303235Sdim    return 1;
70303235Sdim
71303235Sdim  for (SrcData = SrcDataStart,
72303235Sdim       DstData = (__llvm_profile_data *)__llvm_profile_begin_data();
73303235Sdim       SrcData < SrcDataEnd; ++SrcData, ++DstData) {
74303235Sdim    if (SrcData->NameRef != DstData->NameRef ||
75303235Sdim        SrcData->FuncHash != DstData->FuncHash ||
76303235Sdim        SrcData->NumCounters != DstData->NumCounters)
77303235Sdim      return 1;
78303235Sdim  }
79303235Sdim
80303235Sdim  /* Matched! */
81303235Sdim  return 0;
82303235Sdim}
83303235Sdim
84303235SdimCOMPILER_RT_VISIBILITY
85303235Sdimvoid __llvm_profile_merge_from_buffer(const char *ProfileData,
86303235Sdim                                      uint64_t ProfileSize) {
87303235Sdim  __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
88303235Sdim  __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
89303235Sdim  uint64_t *SrcCountersStart;
90303235Sdim  const char *SrcNameStart;
91303235Sdim  ValueProfData *SrcValueProfDataStart, *SrcValueProfData;
92303235Sdim
93303235Sdim  SrcDataStart =
94303235Sdim      (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header));
95303235Sdim  SrcDataEnd = SrcDataStart + Header->DataSize;
96303235Sdim  SrcCountersStart = (uint64_t *)SrcDataEnd;
97303235Sdim  SrcNameStart = (const char *)(SrcCountersStart + Header->CountersSize);
98303235Sdim  SrcValueProfDataStart =
99303235Sdim      (ValueProfData *)(SrcNameStart + Header->NamesSize +
100303235Sdim                        __llvm_profile_get_num_padding_bytes(
101303235Sdim                            Header->NamesSize));
102303235Sdim
103303235Sdim  for (SrcData = SrcDataStart,
104303235Sdim      DstData = (__llvm_profile_data *)__llvm_profile_begin_data(),
105303235Sdim      SrcValueProfData = SrcValueProfDataStart;
106303235Sdim       SrcData < SrcDataEnd; ++SrcData, ++DstData) {
107303235Sdim    uint64_t *SrcCounters;
108303235Sdim    uint64_t *DstCounters = (uint64_t *)DstData->CounterPtr;
109303235Sdim    unsigned I, NC, NVK = 0;
110303235Sdim
111303235Sdim    NC = SrcData->NumCounters;
112303235Sdim    SrcCounters = SrcCountersStart +
113303235Sdim                  ((size_t)SrcData->CounterPtr - Header->CountersDelta) /
114303235Sdim                      sizeof(uint64_t);
115303235Sdim    for (I = 0; I < NC; I++)
116303235Sdim      DstCounters[I] += SrcCounters[I];
117303235Sdim
118303235Sdim    /* Now merge value profile data.  */
119303235Sdim    if (!VPMergeHook)
120303235Sdim      continue;
121303235Sdim
122303235Sdim    for (I = 0; I <= IPVK_Last; I++)
123303235Sdim      NVK += (SrcData->NumValueSites[I] != 0);
124303235Sdim
125303235Sdim    if (!NVK)
126303235Sdim      continue;
127303235Sdim
128303235Sdim    VPMergeHook(SrcValueProfData, DstData);
129303235Sdim    SrcValueProfData = (ValueProfData *)((char *)SrcValueProfData +
130303235Sdim                                         SrcValueProfData->TotalSize);
131303235Sdim  }
132303235Sdim}
133