Skip to content

Commit

Permalink
Upgrade LLVM profiling runtime to version 9
Browse files Browse the repository at this point in the history
Fixes #19
  • Loading branch information
Amanieu committed Jun 22, 2024
1 parent 695dbbb commit d13d207
Show file tree
Hide file tree
Showing 18 changed files with 613 additions and 218 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ minicov = "0.3"
```

3. Before your program exits, call `minicov::capture_coverage` with a sink (such
as `Vec<u8>`) and then dump its contents to a file with the `.profraw` extension:
as `Vec<u8>`) and then dump its contents to a file with the `.profraw` extension:

```ignore
fn main() {
Expand All @@ -75,7 +75,7 @@ Sinks must implement the `CoverageWriter` trait. If the default `alloc` feature
is enabled then an implementation is provided for `Vec<u8>`.

4. Use a tool such as [grcov] or llvm-cov to generate a human-readable coverage
report:
report:

```sh
grcov output.profraw -b ./target/debug/my_program -s . -t html -o cov_report
Expand Down
8 changes: 4 additions & 4 deletions minicov/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ fn main() {
cfg.flag("-fno-coverage-mapping");
cfg.define("COMPILER_RT_HAS_ATOMICS", "1");

let mut sources = vec![
let sources = vec![
"c/InstrProfiling.c",
"c/InstrProfilingBuffer.c",
"c/InstrProfilingInternal.c",
"c/InstrProfilingMerge.c",
"c/InstrProfilingPlatformLinux.c",
"c/InstrProfilingPlatformOther.c",
"c/InstrProfilingPlatformWindows.c",
"c/InstrProfilingWriter.c",
"c/InstrProfilingValue.c",
"c/InstrProfilingVersionVar.c",
Expand All @@ -24,9 +27,6 @@ fn main() {
let target = env::var("TARGET").unwrap_or_default();
if target.ends_with("-uefi") {
cfg.define("MINICOV_UEFI", "1");
sources.push("c/InstrProfilingPlatformWindows.c");
} else {
sources.push("c/InstrProfilingPlatformLinux.c");
}

for source in &sources {
Expand Down
23 changes: 19 additions & 4 deletions minicov/c/InstrProfiling.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
#define INSTR_PROF_VALUE_PROF_DATA
#include "profile/InstrProfData.inc"

static uint32_t __llvm_profile_global_timestamp = 1;

COMPILER_RT_VISIBILITY
void INSTR_PROF_PROFILE_SET_TIMESTAMP(uint64_t *Probe) {
if (*Probe == 0 || *Probe == (uint64_t)-1)
*Probe = __llvm_profile_global_timestamp++;
}

COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_magic(void) {
return sizeof(void *) == sizeof(uint64_t) ? (INSTR_PROF_RAW_MAGIC_64)
: (INSTR_PROF_RAW_MAGIC_32);
Expand All @@ -37,13 +45,20 @@ COMPILER_RT_VISIBILITY uint64_t __llvm_profile_get_version(void) {
}

COMPILER_RT_VISIBILITY void __llvm_profile_reset_counters(void) {
if (__llvm_profile_get_version() & VARIANT_MASK_TEMPORAL_PROF)
__llvm_profile_global_timestamp = 1;

char *I = __llvm_profile_begin_counters();
char *E = __llvm_profile_end_counters();

char ResetValue =
(__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE) ? 0xFF : 0;
memset(I, ResetValue, E - I);

I = __llvm_profile_begin_bitmap();
E = __llvm_profile_end_bitmap();
memset(I, 0x0, E - I);

const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
const __llvm_profile_data *DI;
Expand All @@ -59,11 +74,11 @@ COMPILER_RT_VISIBILITY void __llvm_profile_reset_counters(void) {
CurrentVSiteCount += DI->NumValueSites[VKI];

for (i = 0; i < CurrentVSiteCount; ++i) {
ValueProfNode *CurrentVNode = ValueCounters[i];
ValueProfNode *CurrVNode = ValueCounters[i];

while (CurrentVNode) {
CurrentVNode->Count = 0;
CurrentVNode = CurrentVNode->Next;
while (CurrVNode) {
CurrVNode->Count = 0;
CurrVNode = CurrVNode->Next;
}
}
}
Expand Down
95 changes: 36 additions & 59 deletions minicov/c/InstrProfiling.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@

#include "InstrProfilingPort.h"

// Make sure __LLVM_INSTR_PROFILE_GENERATE is always defined before
// including instr_prof_interface.h so the interface functions are
// declared correctly for the runtime.
// __LLVM_INSTR_PROFILE_GENERATE is always `#undef`ed after the header,
// because compiler-rt does not support profiling the profiling runtime itself.
#ifndef __LLVM_INSTR_PROFILE_GENERATE
#define __LLVM_INSTR_PROFILE_GENERATE
#endif
#include "profile/instr_prof_interface.h"
#undef __LLVM_INSTR_PROFILE_GENERATE

#define INSTR_PROF_VISIBILITY COMPILER_RT_VISIBILITY
#include "profile/InstrProfData.inc"

Expand Down Expand Up @@ -53,6 +64,12 @@ int __llvm_profile_is_continuous_mode_enabled(void);
*/
void __llvm_profile_enable_continuous_mode(void);

/*!
* \brief Disable continuous mode.
*
*/
void __llvm_profile_disable_continuous_mode(void);

/*!
* \brief Set the page size.
*
Expand Down Expand Up @@ -87,33 +104,29 @@ const char *__llvm_profile_begin_names(void);
const char *__llvm_profile_end_names(void);
char *__llvm_profile_begin_counters(void);
char *__llvm_profile_end_counters(void);
char *__llvm_profile_begin_bitmap(void);
char *__llvm_profile_end_bitmap(void);
ValueProfNode *__llvm_profile_begin_vnodes();
ValueProfNode *__llvm_profile_end_vnodes();
uint32_t *__llvm_profile_begin_orderfile();

/*!
* \brief Clear profile counters to zero.
*
*/
void __llvm_profile_reset_counters(void);

/*!
* \brief Merge profile data from buffer.
*
* Read profile data form buffer \p Profile and merge with in-process profile
* counters. The client is expected to have checked or already knows the profile
* data in the buffer matches the in-process counter structure before calling
* it. Returns 0 (success) if the profile data is valid. Upon reading
* invalid/corrupted profile data, returns 1 (failure).
* Read profile data from buffer \p Profile and merge with in-process profile
* counters and bitmaps. The client is expected to have checked or already
* know the profile data in the buffer matches the in-process counter
* structure before calling it. Returns 0 (success) if the profile data is
* valid. Upon reading invalid/corrupted profile data, returns 1 (failure).
*/
int __llvm_profile_merge_from_buffer(const char *Profile, uint64_t Size);

/*! \brief Check if profile in buffer matches the current binary.
*
* Returns 0 (success) if the profile data in buffer \p Profile with size
* \p Size was generated by the same binary and therefore matches
* structurally the in-process counters. If the profile data in buffer is
* not compatible, the interface returns 1 (failure).
* structurally the in-process counters and bitmaps. If the profile data in
* buffer is not compatible, the interface returns 1 (failure).
*/
int __llvm_profile_check_compatibility(const char *Profile,
uint64_t Size);
Expand Down Expand Up @@ -147,50 +160,6 @@ void __llvm_profile_instrument_target_value(uint64_t TargetValue, void *Data,
int __llvm_profile_write_file(void);

int __llvm_orderfile_write_file(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);

int __llvm_orderfile_dump(void);

/*!
* \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 Set the FILE object for writing instrumentation data. Return 0 if set
Expand Down Expand Up @@ -275,6 +244,13 @@ uint64_t __llvm_profile_get_num_counters(const char *Begin, const char *End);
/*! \brief Get the size of the profile counters section in bytes. */
uint64_t __llvm_profile_get_counters_size(const char *Begin, const char *End);

/*! \brief Get the number of bytes in the profile bitmap section. */
uint64_t __llvm_profile_get_num_bitmap_bytes(const char *Begin,
const char *End);

/*! \brief Get the size of the profile name section in bytes. */
uint64_t __llvm_profile_get_name_size(const char *Begin, const char *End);

/* ! \brief Given the sizes of the data and counter information, return the
* number of padding bytes before and after the counters, and after the names,
* in the raw profile.
Expand All @@ -285,8 +261,9 @@ uint64_t __llvm_profile_get_counters_size(const char *Begin, const char *End);
* needed to achieve that.
*/
void __llvm_profile_get_padding_sizes_for_counters(
uint64_t DataSize, uint64_t CountersSize, uint64_t NamesSize,
uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
uint64_t DataSize, uint64_t CountersSize, uint64_t NumBitmapBytes,
uint64_t NamesSize, uint64_t *PaddingBytesBeforeCounters,
uint64_t *PaddingBytesAfterCounters, uint64_t *PaddingBytesAfterBitmap,
uint64_t *PaddingBytesAfterNames);

/*!
Expand Down
54 changes: 42 additions & 12 deletions minicov/c/InstrProfilingBuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ COMPILER_RT_VISIBILITY void __llvm_profile_enable_continuous_mode(void) {
ContinuouslySyncProfile = 1;
}

COMPILER_RT_VISIBILITY void __llvm_profile_disable_continuous_mode(void) {
ContinuouslySyncProfile = 0;
}

COMPILER_RT_VISIBILITY void __llvm_profile_set_page_size(unsigned PS) {
PageSize = PS;
}
Expand All @@ -43,11 +47,14 @@ uint64_t __llvm_profile_get_size_for_buffer(void) {
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
const char *CountersBegin = __llvm_profile_begin_counters();
const char *CountersEnd = __llvm_profile_end_counters();
const char *BitmapBegin = __llvm_profile_begin_bitmap();
const char *BitmapEnd = __llvm_profile_end_bitmap();
const char *NamesBegin = __llvm_profile_begin_names();
const char *NamesEnd = __llvm_profile_end_names();

return __llvm_profile_get_size_for_buffer_internal(
DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd);
DataBegin, DataEnd, CountersBegin, CountersEnd, BitmapBegin, BitmapEnd,
NamesBegin, NamesEnd);
}

COMPILER_RT_VISIBILITY
Expand Down Expand Up @@ -83,6 +90,17 @@ uint64_t __llvm_profile_get_counters_size(const char *Begin, const char *End) {
__llvm_profile_counter_entry_size();
}

COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_num_bitmap_bytes(const char *Begin,
const char *End) {
return (End - Begin);
}

COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_name_size(const char *Begin, const char *End) {
return End - Begin;
}

/// Calculate the number of padding bytes needed to add to \p Offset in order
/// for (\p Offset + Padding) to be page-aligned.
static uint64_t calculateBytesNeededToPageAlign(uint64_t Offset) {
Expand All @@ -102,12 +120,16 @@ static int needsCounterPadding(void) {

COMPILER_RT_VISIBILITY
void __llvm_profile_get_padding_sizes_for_counters(
uint64_t DataSize, uint64_t CountersSize, uint64_t NamesSize,
uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
uint64_t DataSize, uint64_t CountersSize, uint64_t NumBitmapBytes,
uint64_t NamesSize, uint64_t *PaddingBytesBeforeCounters,
uint64_t *PaddingBytesAfterCounters, uint64_t *PaddingBytesAfterBitmapBytes,
uint64_t *PaddingBytesAfterNames) {
if (!needsCounterPadding()) {
*PaddingBytesBeforeCounters = 0;
*PaddingBytesAfterCounters = 0;
*PaddingBytesAfterCounters =
__llvm_profile_get_num_padding_bytes(CountersSize);
*PaddingBytesAfterBitmapBytes =
__llvm_profile_get_num_padding_bytes(NumBitmapBytes);
*PaddingBytesAfterNames = __llvm_profile_get_num_padding_bytes(NamesSize);
return;
}
Expand All @@ -117,31 +139,37 @@ void __llvm_profile_get_padding_sizes_for_counters(
*PaddingBytesBeforeCounters =
calculateBytesNeededToPageAlign(sizeof(__llvm_profile_header) + DataSize);
*PaddingBytesAfterCounters = calculateBytesNeededToPageAlign(CountersSize);
*PaddingBytesAfterBitmapBytes =
calculateBytesNeededToPageAlign(NumBitmapBytes);
*PaddingBytesAfterNames = calculateBytesNeededToPageAlign(NamesSize);
}

COMPILER_RT_VISIBILITY
uint64_t __llvm_profile_get_size_for_buffer_internal(
const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
const char *CountersBegin, const char *CountersEnd, const char *NamesBegin,
const char *NamesEnd) {
const char *CountersBegin, const char *CountersEnd, const char *BitmapBegin,
const char *BitmapEnd, const char *NamesBegin, const char *NamesEnd) {
/* Match logic in __llvm_profile_write_buffer(). */
const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
uint64_t CountersSize =
__llvm_profile_get_counters_size(CountersBegin, CountersEnd);
const uint64_t NumBitmapBytes =
__llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);

/* Determine how much padding is needed before/after the counters and after
* the names. */
uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
PaddingBytesAfterNames;
PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes;
__llvm_profile_get_padding_sizes_for_counters(
DataSize, CountersSize, NamesSize, &PaddingBytesBeforeCounters,
&PaddingBytesAfterCounters, &PaddingBytesAfterNames);
DataSize, CountersSize, NumBitmapBytes, NamesSize,
&PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,
&PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames);

return sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) +
DataSize + PaddingBytesBeforeCounters + CountersSize +
PaddingBytesAfterCounters + NamesSize + PaddingBytesAfterNames;
PaddingBytesAfterCounters + NumBitmapBytes +
PaddingBytesAfterBitmapBytes + NamesSize + PaddingBytesAfterNames;
}

COMPILER_RT_VISIBILITY
Expand All @@ -159,9 +187,11 @@ COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) {
COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal(
char *Buffer, const __llvm_profile_data *DataBegin,
const __llvm_profile_data *DataEnd, const char *CountersBegin,
const char *CountersEnd, const char *NamesBegin, const char *NamesEnd) {
const char *CountersEnd, const char *BitmapBegin, const char *BitmapEnd,
const char *NamesBegin, const char *NamesEnd) {
ProfDataWriter BufferWriter;
initBufferWriter(&BufferWriter, Buffer);
return lprofWriteDataImpl(&BufferWriter, DataBegin, DataEnd, CountersBegin,
CountersEnd, 0, NamesBegin, NamesEnd, 0);
CountersEnd, BitmapBegin, BitmapEnd, 0, NamesBegin,
NamesEnd, 0);
}
Loading

0 comments on commit d13d207

Please sign in to comment.