Skip to content

Add support for -fcoverage-mapping support #24160

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
1,023 changes: 1,023 additions & 0 deletions system/lib/compiler-rt/include/profile/InstrProfData.inc

Large diffs are not rendered by default.

55 changes: 55 additions & 0 deletions system/lib/compiler-rt/include/profile/MIBEntryDef.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*===-- MemEntryDef.inc - MemProf profiling runtime macros -*- C++ -*-======== *\
|*
|* 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 macros for memprof profiling data structures.
* Eg. usage to define the memprof meminfoblock struct:
*
* struct MemInfoBlock {
* #define MIBEntryDef(NameTag, Name, Type) Type Name;
* #include MIBEntryDef.inc
* #undef MIBEntryDef
* };
*
* This file has two identical copies. The primary copy lives in LLVM and
* the other one sits in compiler-rt/include/profile directory. To make changes
* in this file, first modify the primary copy and copy it over to compiler-rt.
* Testing of any change in this file can start only after the two copies are
* synced up.
*
\*===----------------------------------------------------------------------===*/
#ifndef MIBEntryDef
#define MIBEntryDef(NameTag, Name, Type)
#endif

MIBEntryDef(AllocCount = 1, AllocCount, uint32_t)
MIBEntryDef(TotalAccessCount = 2, TotalAccessCount, uint64_t)
MIBEntryDef(MinAccessCount = 3, MinAccessCount, uint64_t)
MIBEntryDef(MaxAccessCount = 4, MaxAccessCount, uint64_t)
MIBEntryDef(TotalSize = 5, TotalSize, uint64_t)
MIBEntryDef(MinSize = 6, MinSize, uint32_t)
MIBEntryDef(MaxSize = 7, MaxSize, uint32_t)
MIBEntryDef(AllocTimestamp = 8, AllocTimestamp, uint32_t)
MIBEntryDef(DeallocTimestamp = 9, DeallocTimestamp, uint32_t)
MIBEntryDef(TotalLifetime = 10, TotalLifetime, uint64_t)
MIBEntryDef(MinLifetime = 11, MinLifetime, uint32_t)
MIBEntryDef(MaxLifetime = 12, MaxLifetime, uint32_t)
MIBEntryDef(AllocCpuId = 13, AllocCpuId, uint32_t)
MIBEntryDef(DeallocCpuId = 14, DeallocCpuId, uint32_t)
MIBEntryDef(NumMigratedCpu = 15, NumMigratedCpu, uint32_t)
MIBEntryDef(NumLifetimeOverlaps = 16, NumLifetimeOverlaps, uint32_t)
MIBEntryDef(NumSameAllocCpu = 17, NumSameAllocCpu, uint32_t)
MIBEntryDef(NumSameDeallocCpu = 18, NumSameDeallocCpu, uint32_t)
MIBEntryDef(DataTypeId = 19, DataTypeId, uint64_t)
MIBEntryDef(TotalAccessDensity = 20, TotalAccessDensity, uint64_t)
MIBEntryDef(MinAccessDensity = 21, MinAccessDensity, uint32_t)
MIBEntryDef(MaxAccessDensity = 22, MaxAccessDensity, uint32_t)
MIBEntryDef(TotalLifetimeAccessDensity = 23, TotalLifetimeAccessDensity, uint64_t)
MIBEntryDef(MinLifetimeAccessDensity = 24, MinLifetimeAccessDensity, uint32_t)
MIBEntryDef(MaxLifetimeAccessDensity = 25, MaxLifetimeAccessDensity, uint32_t)
MIBEntryDef(AccessHistogramSize = 26, AccessHistogramSize, uint32_t)
MIBEntryDef(AccessHistogram = 27, AccessHistogram, uintptr_t)
235 changes: 235 additions & 0 deletions system/lib/compiler-rt/include/profile/MemProfData.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
#ifndef MEMPROF_DATA_INC
#define MEMPROF_DATA_INC
/*===-- MemProfData.inc - MemProf profiling runtime structures -*- C++ -*-=== *\
|*
|* 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 is the main file that defines all the data structure, signature,
* constant literals that are shared across profiling runtime library,
* and host tools (reader/writer).
*
* This file has two identical copies. The primary copy lives in LLVM and
* the other one sits in compiler-rt/include/profile directory. To make changes
* in this file, first modify the primary copy and copy it over to compiler-rt.
* Testing of any change in this file can start only after the two copies are
* synced up.
*
\*===----------------------------------------------------------------------===*/
#include <string.h>

#ifdef _MSC_VER
#define PACKED(...) __pragma(pack(push,1)) __VA_ARGS__ __pragma(pack(pop))
#else
#define PACKED(...) __VA_ARGS__ __attribute__((__packed__))
#endif

// A 64-bit magic number to uniquely identify the raw binary memprof profile file.
#define MEMPROF_RAW_MAGIC_64 \
((uint64_t)255 << 56 | (uint64_t)'m' << 48 | (uint64_t)'p' << 40 | (uint64_t)'r' << 32 | \
(uint64_t)'o' << 24 | (uint64_t)'f' << 16 | (uint64_t)'r' << 8 | (uint64_t)129)

// The version number of the raw binary format.
#define MEMPROF_RAW_VERSION 4ULL

// Currently supported versions.
#define MEMPROF_RAW_SUPPORTED_VERSIONS \
{ 3ULL, 4ULL }

#define MEMPROF_V3_MIB_SIZE 132ULL;

#define MEMPROF_BUILDID_MAX_SIZE 32ULL

namespace llvm {
namespace memprof {
// A struct describing the header used for the raw binary memprof profile format.
PACKED(struct Header {
uint64_t Magic;
uint64_t Version;
uint64_t TotalSize;
uint64_t SegmentOffset;
uint64_t MIBOffset;
uint64_t StackOffset;
});

// A struct describing the information necessary to describe a /proc/maps
// segment entry for a particular binary/library identified by its build id.
PACKED(struct SegmentEntry {
uint64_t Start;
uint64_t End;
uint64_t Offset;
uint64_t BuildIdSize;
uint8_t BuildId[MEMPROF_BUILDID_MAX_SIZE] = {0};

// This constructor is only used in tests so don't set the BuildId.
SegmentEntry(uint64_t S, uint64_t E, uint64_t O)
: Start(S), End(E), Offset(O), BuildIdSize(0) {}

SegmentEntry(const SegmentEntry& S) {
Start = S.Start;
End = S.End;
Offset = S.Offset;
BuildIdSize = S.BuildIdSize;
memcpy(BuildId, S.BuildId, S.BuildIdSize);
}

SegmentEntry& operator=(const SegmentEntry& S) {
Start = S.Start;
End = S.End;
Offset = S.Offset;
BuildIdSize = S.BuildIdSize;
memcpy(BuildId, S.BuildId, S.BuildIdSize);
return *this;
}

bool operator==(const SegmentEntry& S) const {
return Start == S.Start && End == S.End && Offset == S.Offset &&
BuildIdSize == S.BuildIdSize &&
memcmp(BuildId, S.BuildId, S.BuildIdSize) == 0;
}
});

// Packed struct definition for MSVC. We can't use the PACKED macro defined in
// MemProfData.inc since it would mean we are embedding a directive (the
// #include for MIBEntryDef) into the macros which is undefined behaviour.
#ifdef _MSC_VER
__pragma(pack(push,1))
#endif

// A struct representing the heap allocation characteristics of a particular
// runtime context. This struct is shared between the compiler-rt runtime and
// the raw profile reader. The indexed format uses a separate, self-describing
// backwards compatible format.
struct MemInfoBlock{

#define MIBEntryDef(NameTag, Name, Type) Type Name;
#include "MIBEntryDef.inc"
#undef MIBEntryDef

bool operator==(const MemInfoBlock& Other) const {
bool IsEqual = true;
#define MIBEntryDef(NameTag, Name, Type) \
IsEqual = (IsEqual && Name == Other.Name);
#include "MIBEntryDef.inc"
#undef MIBEntryDef
return IsEqual;
}

MemInfoBlock() {
#define MIBEntryDef(NameTag, Name, Type) Name = Type();
#include "MIBEntryDef.inc"
#undef MIBEntryDef
}

MemInfoBlock(uint32_t Size, uint64_t AccessCount, uint32_t AllocTs,
uint32_t DeallocTs, uint32_t AllocCpu, uint32_t DeallocCpu,
uintptr_t Histogram, uint32_t HistogramSize)
: MemInfoBlock() {
AllocCount = 1U;
TotalAccessCount = AccessCount;
MinAccessCount = AccessCount;
MaxAccessCount = AccessCount;
TotalSize = Size;
MinSize = Size;
MaxSize = Size;
AllocTimestamp = AllocTs;
DeallocTimestamp = DeallocTs;
TotalLifetime = DeallocTimestamp - AllocTimestamp;
MinLifetime = TotalLifetime;
MaxLifetime = TotalLifetime;
// Access density is accesses per byte. Multiply by 100 to include the
// fractional part.
TotalAccessDensity = AccessCount * 100 / Size;
MinAccessDensity = TotalAccessDensity;
MaxAccessDensity = TotalAccessDensity;
// Lifetime access density is the access density per second of lifetime.
// Multiply by 1000 to convert denominator lifetime to seconds (using a
// minimum lifetime of 1ms to avoid divide by 0. Do the multiplication first
// to reduce truncations to 0.
TotalLifetimeAccessDensity =
TotalAccessDensity * 1000 / (TotalLifetime ? TotalLifetime : 1);
MinLifetimeAccessDensity = TotalLifetimeAccessDensity;
MaxLifetimeAccessDensity = TotalLifetimeAccessDensity;
AllocCpuId = AllocCpu;
DeallocCpuId = DeallocCpu;
NumMigratedCpu = AllocCpuId != DeallocCpuId;
AccessHistogramSize = HistogramSize;
AccessHistogram = Histogram;
}

void Merge(const MemInfoBlock &newMIB) {
AllocCount += newMIB.AllocCount;

TotalAccessCount += newMIB.TotalAccessCount;
MinAccessCount = newMIB.MinAccessCount < MinAccessCount ? newMIB.MinAccessCount : MinAccessCount;
MaxAccessCount = newMIB.MaxAccessCount > MaxAccessCount ? newMIB.MaxAccessCount : MaxAccessCount;

TotalSize += newMIB.TotalSize;
MinSize = newMIB.MinSize < MinSize ? newMIB.MinSize : MinSize;
MaxSize = newMIB.MaxSize > MaxSize ? newMIB.MaxSize : MaxSize;

TotalLifetime += newMIB.TotalLifetime;
MinLifetime = newMIB.MinLifetime < MinLifetime ? newMIB.MinLifetime : MinLifetime;
MaxLifetime = newMIB.MaxLifetime > MaxLifetime ? newMIB.MaxLifetime : MaxLifetime;

TotalAccessDensity += newMIB.TotalAccessDensity;
MinAccessDensity = newMIB.MinAccessDensity < MinAccessDensity
? newMIB.MinAccessDensity
: MinAccessDensity;
MaxAccessDensity = newMIB.MaxAccessDensity > MaxAccessDensity
? newMIB.MaxAccessDensity
: MaxAccessDensity;

TotalLifetimeAccessDensity += newMIB.TotalLifetimeAccessDensity;
MinLifetimeAccessDensity =
newMIB.MinLifetimeAccessDensity < MinLifetimeAccessDensity
? newMIB.MinLifetimeAccessDensity
: MinLifetimeAccessDensity;
MaxLifetimeAccessDensity =
newMIB.MaxLifetimeAccessDensity > MaxLifetimeAccessDensity
? newMIB.MaxLifetimeAccessDensity
: MaxLifetimeAccessDensity;

// We know newMIB was deallocated later, so just need to check if it was
// allocated before last one deallocated.
NumLifetimeOverlaps += newMIB.AllocTimestamp < DeallocTimestamp;
AllocTimestamp = newMIB.AllocTimestamp;
DeallocTimestamp = newMIB.DeallocTimestamp;

NumSameAllocCpu += AllocCpuId == newMIB.AllocCpuId;
NumSameDeallocCpu += DeallocCpuId == newMIB.DeallocCpuId;
AllocCpuId = newMIB.AllocCpuId;
DeallocCpuId = newMIB.DeallocCpuId;

// For merging histograms, we always keep the longer histogram, and add
// values of shorter histogram to larger one.
uintptr_t ShorterHistogram;
uint32_t ShorterHistogramSize;
if (newMIB.AccessHistogramSize > AccessHistogramSize) {
ShorterHistogram = AccessHistogram;
ShorterHistogramSize = AccessHistogramSize;
// Swap histogram of current to larger histogram
AccessHistogram = newMIB.AccessHistogram;
AccessHistogramSize = newMIB.AccessHistogramSize;
} else {
ShorterHistogram = newMIB.AccessHistogram;
ShorterHistogramSize = newMIB.AccessHistogramSize;
}
for (size_t i = 0; i < ShorterHistogramSize; ++i) {
((uint64_t *)AccessHistogram)[i] += ((uint64_t *)ShorterHistogram)[i];
}
}

#ifdef _MSC_VER
} __pragma(pack(pop));
#else
} __attribute__((__packed__));
#endif

} // namespace memprof
} // namespace llvm

#endif
92 changes: 92 additions & 0 deletions system/lib/compiler-rt/include/profile/instr_prof_interface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*===---- instr_prof_interface.h - Instrumentation PGO User Program API ----===
*
* 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 header provides a public interface for fine-grained control of counter
* reset and profile dumping. These interface functions can be directly called
* in user programs.
*
\*===---------------------------------------------------------------------===*/

#ifndef COMPILER_RT_INSTR_PROFILING
#define COMPILER_RT_INSTR_PROFILING

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __LLVM_INSTR_PROFILE_GENERATE
// Profile file reset and dump interfaces.
// When `-fprofile[-instr]-generate`/`-fcs-profile-generate` is in effect,
// clang defines __LLVM_INSTR_PROFILE_GENERATE to pick up the API calls.

/*!
* \brief Set the filename for writing instrumentation data.
*
* Sets the filename to be used for subsequent calls to
* \a __llvm_profile_write_file().
*
* \c Name is not copied, so it must remain valid. Passing NULL resets the
* filename logic to the default behaviour.
*
* Note: There may be multiple copies of the profile runtime (one for each
* instrumented image/DSO). This API only modifies the filename within the
* copy of the runtime available to the calling image.
*
* Warning: This is a no-op if continuous mode (\ref
* __llvm_profile_is_continuous_mode_enabled) is on. The reason for this is
* that in continuous mode, profile counters are mmap()'d to the profile at
* program initialization time. Support for transferring the mmap'd profile
* counts to a new file has not been implemented.
*/
void __llvm_profile_set_filename(const char *Name);

/*!
* \brief Interface to set all PGO counters to zero for the current process.
*
*/
void __llvm_profile_reset_counters(void);

/*!
* \brief this is a wrapper interface to \c __llvm_profile_write_file.
* After this interface is invoked, an already dumped flag will be set
* so that profile won't be dumped again during program exit.
* Invocation of interface __llvm_profile_reset_counters will clear
* the flag. This interface is designed to be used to collect profile
* data from user selected hot regions. The use model is
* __llvm_profile_reset_counters();
* ... hot region 1
* __llvm_profile_dump();
* .. some other code
* __llvm_profile_reset_counters();
* ... hot region 2
* __llvm_profile_dump();
*
* It is expected that on-line profile merging is on with \c %m specifier
* used in profile filename . If merging is not turned on, user is expected
* to invoke __llvm_profile_set_filename to specify different profile names
* for different regions before dumping to avoid profile write clobbering.
*/
int __llvm_profile_dump(void);

// Interface to dump the current process' order file to disk.
int __llvm_orderfile_dump(void);

#else

#define __llvm_profile_set_filename(Name)
#define __llvm_profile_reset_counters()
#define __llvm_profile_dump() (0)
#define __llvm_orderfile_dump() (0)

#endif

#ifdef __cplusplus
} // extern "C"
#endif

#endif
Loading