This header fragment is useful on its own for any consumer that wants to use custom instruction profile runtime with the LLVM instrumentation. The concrete use case is in Fuchsia's kernel where we want to use instruction profile instrumentation, but we cannot use the compiler-rt runtime because it's not designed for use in the kernel environment. This change allows installing this header as part of compiler-rt. Differential Revision: https://reviews.llvm.org/D64532
133 lines
5.1 KiB
C
133 lines
5.1 KiB
C
/*===- InstrProfilingMerge.c - Profile in-process Merging ---------------===*\
|
|
|*
|
|
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|* See https://llvm.org/LICENSE.txt for license information.
|
|
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|*
|
|
|*===----------------------------------------------------------------------===*
|
|
|* This file defines the API needed for in-process merging of profile data
|
|
|* stored in memory buffer.
|
|
\*===---------------------------------------------------------------------===*/
|
|
|
|
#include "InstrProfiling.h"
|
|
#include "InstrProfilingInternal.h"
|
|
#include "InstrProfilingUtil.h"
|
|
|
|
#define INSTR_PROF_VALUE_PROF_DATA
|
|
#include "profile/InstrProfData.inc"
|
|
|
|
COMPILER_RT_VISIBILITY
|
|
void (*VPMergeHook)(ValueProfData *, __llvm_profile_data *);
|
|
|
|
COMPILER_RT_VISIBILITY
|
|
uint64_t lprofGetLoadModuleSignature() {
|
|
/* A very fast way to compute a module signature. */
|
|
uint64_t CounterSize = (uint64_t)(__llvm_profile_end_counters() -
|
|
__llvm_profile_begin_counters());
|
|
uint64_t DataSize = __llvm_profile_get_data_size(__llvm_profile_begin_data(),
|
|
__llvm_profile_end_data());
|
|
uint64_t NamesSize =
|
|
(uint64_t)(__llvm_profile_end_names() - __llvm_profile_begin_names());
|
|
uint64_t NumVnodes =
|
|
(uint64_t)(__llvm_profile_end_vnodes() - __llvm_profile_begin_vnodes());
|
|
const __llvm_profile_data *FirstD = __llvm_profile_begin_data();
|
|
|
|
return (NamesSize << 40) + (CounterSize << 30) + (DataSize << 20) +
|
|
(NumVnodes << 10) + (DataSize > 0 ? FirstD->NameRef : 0);
|
|
}
|
|
|
|
/* Returns 1 if profile is not structurally compatible. */
|
|
COMPILER_RT_VISIBILITY
|
|
int __llvm_profile_check_compatibility(const char *ProfileData,
|
|
uint64_t ProfileSize) {
|
|
/* Check profile header only for now */
|
|
__llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
|
|
__llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
|
|
SrcDataStart =
|
|
(__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header));
|
|
SrcDataEnd = SrcDataStart + Header->DataSize;
|
|
|
|
if (ProfileSize < sizeof(__llvm_profile_header))
|
|
return 1;
|
|
|
|
/* Check the header first. */
|
|
if (Header->Magic != __llvm_profile_get_magic() ||
|
|
Header->Version != __llvm_profile_get_version() ||
|
|
Header->DataSize !=
|
|
__llvm_profile_get_data_size(__llvm_profile_begin_data(),
|
|
__llvm_profile_end_data()) ||
|
|
Header->CountersSize != (uint64_t)(__llvm_profile_end_counters() -
|
|
__llvm_profile_begin_counters()) ||
|
|
Header->NamesSize != (uint64_t)(__llvm_profile_end_names() -
|
|
__llvm_profile_begin_names()) ||
|
|
Header->ValueKindLast != IPVK_Last)
|
|
return 1;
|
|
|
|
if (ProfileSize < sizeof(__llvm_profile_header) +
|
|
Header->DataSize * sizeof(__llvm_profile_data) +
|
|
Header->NamesSize + Header->CountersSize)
|
|
return 1;
|
|
|
|
for (SrcData = SrcDataStart,
|
|
DstData = (__llvm_profile_data *)__llvm_profile_begin_data();
|
|
SrcData < SrcDataEnd; ++SrcData, ++DstData) {
|
|
if (SrcData->NameRef != DstData->NameRef ||
|
|
SrcData->FuncHash != DstData->FuncHash ||
|
|
SrcData->NumCounters != DstData->NumCounters)
|
|
return 1;
|
|
}
|
|
|
|
/* Matched! */
|
|
return 0;
|
|
}
|
|
|
|
COMPILER_RT_VISIBILITY
|
|
void __llvm_profile_merge_from_buffer(const char *ProfileData,
|
|
uint64_t ProfileSize) {
|
|
__llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
|
|
__llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
|
|
uint64_t *SrcCountersStart;
|
|
const char *SrcNameStart;
|
|
ValueProfData *SrcValueProfDataStart, *SrcValueProfData;
|
|
|
|
SrcDataStart =
|
|
(__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header));
|
|
SrcDataEnd = SrcDataStart + Header->DataSize;
|
|
SrcCountersStart = (uint64_t *)SrcDataEnd;
|
|
SrcNameStart = (const char *)(SrcCountersStart + Header->CountersSize);
|
|
SrcValueProfDataStart =
|
|
(ValueProfData *)(SrcNameStart + Header->NamesSize +
|
|
__llvm_profile_get_num_padding_bytes(
|
|
Header->NamesSize));
|
|
|
|
for (SrcData = SrcDataStart,
|
|
DstData = (__llvm_profile_data *)__llvm_profile_begin_data(),
|
|
SrcValueProfData = SrcValueProfDataStart;
|
|
SrcData < SrcDataEnd; ++SrcData, ++DstData) {
|
|
uint64_t *SrcCounters;
|
|
uint64_t *DstCounters = (uint64_t *)DstData->CounterPtr;
|
|
unsigned I, NC, NVK = 0;
|
|
|
|
NC = SrcData->NumCounters;
|
|
SrcCounters = SrcCountersStart +
|
|
((size_t)SrcData->CounterPtr - Header->CountersDelta) /
|
|
sizeof(uint64_t);
|
|
for (I = 0; I < NC; I++)
|
|
DstCounters[I] += SrcCounters[I];
|
|
|
|
/* Now merge value profile data. */
|
|
if (!VPMergeHook)
|
|
continue;
|
|
|
|
for (I = 0; I <= IPVK_Last; I++)
|
|
NVK += (SrcData->NumValueSites[I] != 0);
|
|
|
|
if (!NVK)
|
|
continue;
|
|
|
|
VPMergeHook(SrcValueProfData, DstData);
|
|
SrcValueProfData = (ValueProfData *)((char *)SrcValueProfData +
|
|
SrcValueProfData->TotalSize);
|
|
}
|
|
}
|