[llvm] 7cca33b - [memprof] Extend llvm-profdata to display MemProf profile summaries.
Snehasish Kumar via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 30 10:46:19 PST 2021
Author: Snehasish Kumar
Date: 2021-11-30T10:45:26-08:00
New Revision: 7cca33b40f77c2d8bcd4241bcd0e4c45a0209683
URL: https://github.com/llvm/llvm-project/commit/7cca33b40f77c2d8bcd4241bcd0e4c45a0209683
DIFF: https://github.com/llvm/llvm-project/commit/7cca33b40f77c2d8bcd4241bcd0e4c45a0209683.diff
LOG: [memprof] Extend llvm-profdata to display MemProf profile summaries.
This commit adds initial support to llvm-profdata to read and print
summaries of raw memprof profiles.
Summary of changes:
* Refactor shared defs to MemProfData.inc
* Extend show_main to display memprof profile summaries.
* Add a simple raw memprof profile reader.
* Add a couple of tests to tools/llvm-profdata.
Differential Revision: https://reviews.llvm.org/D114286
Added:
compiler-rt/include/profile/MemProfData.inc
llvm/include/llvm/ProfileData/MemProfData.inc
llvm/include/llvm/ProfileData/RawMemProfReader.h
llvm/lib/ProfileData/RawMemProfReader.cpp
llvm/test/tools/llvm-profdata/Inputs/basic.memprofraw
llvm/test/tools/llvm-profdata/Inputs/multi.memprofraw
llvm/test/tools/llvm-profdata/memprof-basic.test
llvm/test/tools/llvm-profdata/memprof-multi.test
Modified:
compiler-rt/include/CMakeLists.txt
compiler-rt/lib/memprof/CMakeLists.txt
compiler-rt/lib/memprof/memprof_rawprofile.cpp
compiler-rt/lib/memprof/memprof_rawprofile.h
llvm/lib/ProfileData/CMakeLists.txt
llvm/test/tools/llvm-profdata/text-format-errors.test
llvm/tools/llvm-profdata/llvm-profdata.cpp
Removed:
################################################################################
diff --git a/compiler-rt/include/CMakeLists.txt b/compiler-rt/include/CMakeLists.txt
index 7b415f0b88a3..20408714f5af 100644
--- a/compiler-rt/include/CMakeLists.txt
+++ b/compiler-rt/include/CMakeLists.txt
@@ -23,6 +23,7 @@ endif(COMPILER_RT_BUILD_SANITIZERS)
if (COMPILER_RT_BUILD_MEMPROF)
set(MEMPROF_HEADERS
sanitizer/memprof_interface.h
+ profile/MemProfData.inc
)
endif(COMPILER_RT_BUILD_MEMPROF)
diff --git a/compiler-rt/include/profile/MemProfData.inc b/compiler-rt/include/profile/MemProfData.inc
new file mode 100644
index 000000000000..d64227e4ba31
--- /dev/null
+++ b/compiler-rt/include/profile/MemProfData.inc
@@ -0,0 +1,61 @@
+#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.
+ *
+\*===----------------------------------------------------------------------===*/
+
+
+#ifdef _MSC_VER
+#define PACKED(__decl__) __pragma(pack(push,1)) __decl__ __pragma(pack(pop))
+#else
+#define PACKED(__decl__) __decl__ __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 1ULL
+
+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;
+ uint8_t BuildId[32];
+});
+} // namespace memprof
+} // namespace llvm
+
+#endif
diff --git a/compiler-rt/lib/memprof/CMakeLists.txt b/compiler-rt/lib/memprof/CMakeLists.txt
index f797610d61ff..20d699206bc6 100644
--- a/compiler-rt/lib/memprof/CMakeLists.txt
+++ b/compiler-rt/lib/memprof/CMakeLists.txt
@@ -46,6 +46,7 @@ SET(MEMPROF_HEADERS
)
include_directories(..)
+include_directories(../../include)
set(MEMPROF_CFLAGS ${SANITIZER_COMMON_CFLAGS})
set(MEMPROF_COMMON_DEFINITIONS "")
diff --git a/compiler-rt/lib/memprof/memprof_rawprofile.cpp b/compiler-rt/lib/memprof/memprof_rawprofile.cpp
index 96f315f95b24..48e579cdab26 100644
--- a/compiler-rt/lib/memprof/memprof_rawprofile.cpp
+++ b/compiler-rt/lib/memprof/memprof_rawprofile.cpp
@@ -1,5 +1,10 @@
-#include "memprof_rawprofile.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
#include "memprof_meminfoblock.h"
+#include "memprof_rawprofile.h"
+#include "profile/MemProfData.inc"
#include "sanitizer_common/sanitizer_allocator_internal.h"
#include "sanitizer_common/sanitizer_linux.h"
#include "sanitizer_common/sanitizer_procmaps.h"
@@ -8,29 +13,12 @@
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_vector.h"
-#include <stdlib.h>
-#include <string.h>
-
namespace __memprof {
using ::__sanitizer::Vector;
+using SegmentEntry = ::llvm::memprof::SegmentEntry;
+using Header = ::llvm::memprof::Header;
namespace {
-typedef struct __attribute__((__packed__)) {
- u64 start;
- u64 end;
- u64 offset;
- u8 buildId[32];
-} SegmentEntry;
-
-typedef struct __attribute__((__packed__)) {
- u64 magic;
- u64 version;
- u64 total_size;
- u64 segment_offset;
- u64 mib_offset;
- u64 stack_offset;
-} Header;
-
template <class T> char *WriteBytes(T Pod, char *&Buffer) {
*(T *)Buffer = Pod;
return Buffer + sizeof(T);
@@ -76,12 +64,12 @@ void SerializeSegmentsToBuffer(MemoryMappingLayoutBase &Layout,
for (Layout.Reset(); Layout.Next(&segment);) {
if (segment.IsReadable() && segment.IsExecutable()) {
- SegmentEntry entry{};
- entry.start = segment.start;
- entry.end = segment.end;
- entry.offset = segment.offset;
- memcpy(entry.buildId, segment.uuid, sizeof(segment.uuid));
- memcpy(Ptr, &entry, sizeof(SegmentEntry));
+ SegmentEntry Entry{};
+ Entry.Start = segment.start;
+ Entry.End = segment.end;
+ Entry.Offset = segment.offset;
+ memcpy(Entry.BuildId, segment.uuid, sizeof(segment.uuid));
+ memcpy(Ptr, &Entry, sizeof(SegmentEntry));
Ptr += sizeof(SegmentEntry);
NumSegmentsRecorded++;
}
diff --git a/compiler-rt/lib/memprof/memprof_rawprofile.h b/compiler-rt/lib/memprof/memprof_rawprofile.h
index 052bac3267f1..575104e7e34e 100644
--- a/compiler-rt/lib/memprof/memprof_rawprofile.h
+++ b/compiler-rt/lib/memprof/memprof_rawprofile.h
@@ -5,17 +5,10 @@
#include "sanitizer_common/sanitizer_procmaps.h"
namespace __memprof {
-
-// TODO: pull these in from MemProfData.inc
-#define MEMPROF_RAW_MAGIC_64 \
- (u64)255 << 56 | (u64)'m' << 48 | (u64)'p' << 40 | (u64)'r' << 32 | \
- (u64)'o' << 24 | (u64)'f' << 16 | (u64)'r' << 8 | (u64)129
-
-#define MEMPROF_RAW_VERSION 1ULL
-
+// Serialize the in-memory representation of the memprof profile to the raw
+// binary format. The format itself is documented memprof_rawprofile.cpp.
u64 SerializeToRawProfile(MIBMapTy &BlockCache, MemoryMappingLayoutBase &Layout,
char *&Buffer);
-
} // namespace __memprof
#endif // MEMPROF_RAWPROFILE_H_
diff --git a/llvm/include/llvm/ProfileData/MemProfData.inc b/llvm/include/llvm/ProfileData/MemProfData.inc
new file mode 100644
index 000000000000..d64227e4ba31
--- /dev/null
+++ b/llvm/include/llvm/ProfileData/MemProfData.inc
@@ -0,0 +1,61 @@
+#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.
+ *
+\*===----------------------------------------------------------------------===*/
+
+
+#ifdef _MSC_VER
+#define PACKED(__decl__) __pragma(pack(push,1)) __decl__ __pragma(pack(pop))
+#else
+#define PACKED(__decl__) __decl__ __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 1ULL
+
+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;
+ uint8_t BuildId[32];
+});
+} // namespace memprof
+} // namespace llvm
+
+#endif
diff --git a/llvm/include/llvm/ProfileData/RawMemProfReader.h b/llvm/include/llvm/ProfileData/RawMemProfReader.h
new file mode 100644
index 000000000000..45544927a86f
--- /dev/null
+++ b/llvm/include/llvm/ProfileData/RawMemProfReader.h
@@ -0,0 +1,43 @@
+#ifndef LLVM_PROFILEDATA_RAWMEMPROFREADER_H_
+#define LLVM_PROFILEDATA_RAWMEMPROFREADER_H_
+//===- MemProfReader.h - Instrumented memory profiling reader ---*- 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 contains support for reading MemProf profiling data.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+namespace llvm {
+namespace memprof {
+
+class RawMemProfReader {
+public:
+ RawMemProfReader(std::unique_ptr<MemoryBuffer> DataBuffer)
+ : DataBuffer(std::move(DataBuffer)) {}
+ // Prints aggregate counts for each raw profile parsed from the DataBuffer.
+ void printSummaries(raw_ostream &OS) const;
+
+ // Return true if the \p DataBuffer starts with magic bytes indicating it is
+ // a raw binary memprof profile.
+ static bool hasFormat(const MemoryBuffer &DataBuffer);
+
+ // Create a RawMemProfReader after sanity checking the contents of the file at
+ // \p Path.
+ static Expected<std::unique_ptr<RawMemProfReader>> create(const Twine &Path);
+
+private:
+ std::unique_ptr<MemoryBuffer> DataBuffer;
+};
+
+} // namespace memprof
+} // namespace llvm
+
+#endif // LLVM_PROFILEDATA_RAWMEMPROFREADER_H_
diff --git a/llvm/lib/ProfileData/CMakeLists.txt b/llvm/lib/ProfileData/CMakeLists.txt
index 2a377e4d74d3..eec2392aef42 100644
--- a/llvm/lib/ProfileData/CMakeLists.txt
+++ b/llvm/lib/ProfileData/CMakeLists.txt
@@ -7,6 +7,7 @@ add_llvm_component_library(LLVMProfileData
SampleProf.cpp
SampleProfReader.cpp
SampleProfWriter.cpp
+ RawMemProfReader.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/ProfileData
diff --git a/llvm/lib/ProfileData/RawMemProfReader.cpp b/llvm/lib/ProfileData/RawMemProfReader.cpp
new file mode 100644
index 000000000000..07c218aa9746
--- /dev/null
+++ b/llvm/lib/ProfileData/RawMemProfReader.cpp
@@ -0,0 +1,111 @@
+//===- RawMemProfReader.cpp - Instrumented memory profiling reader --------===//
+//
+// 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 contains support for reading MemProf profiling data.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstdint>
+
+#include "llvm/ProfileData/InstrProf.h"
+#include "llvm/ProfileData/MemProfData.inc"
+#include "llvm/ProfileData/RawMemProfReader.h"
+
+namespace llvm {
+namespace memprof {
+namespace {
+
+struct Summary {
+ uint64_t Version;
+ uint64_t TotalSizeBytes;
+ uint64_t NumSegments;
+ uint64_t NumMIBInfo;
+ uint64_t NumStackOffsets;
+};
+
+Summary computeSummary(const char *Start) {
+ auto *H = reinterpret_cast<const Header *>(Start);
+
+ return Summary{
+ H->Version,
+ H->TotalSize,
+ *reinterpret_cast<const uint64_t *>(Start + H->SegmentOffset),
+ *reinterpret_cast<const uint64_t *>(Start + H->MIBOffset),
+ *reinterpret_cast<const uint64_t *>(Start + H->StackOffset),
+ };
+}
+
+} // namespace
+
+Expected<std::unique_ptr<RawMemProfReader>>
+RawMemProfReader::create(const Twine &Path) {
+ auto BufferOr = MemoryBuffer::getFileOrSTDIN(Path, /*IsText=*/true);
+ if (std::error_code EC = BufferOr.getError())
+ return errorCodeToError(EC);
+
+ std::unique_ptr<MemoryBuffer> Buffer(BufferOr.get().release());
+
+ if (Buffer->getBufferSize() == 0)
+ return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
+
+ if (!RawMemProfReader::hasFormat(*Buffer))
+ return make_error<InstrProfError>(instrprof_error::bad_magic);
+
+ if (Buffer->getBufferSize() < sizeof(Header)) {
+ return make_error<InstrProfError>(instrprof_error::truncated);
+ }
+
+ // The size of the buffer can be > header total size since we allow repeated
+ // serialization of memprof profiles to the same file.
+ uint64_t TotalSize = 0;
+ const char *Next = Buffer->getBufferStart();
+ while (Next < Buffer->getBufferEnd()) {
+ auto *H = reinterpret_cast<const Header *>(Next);
+ if (H->Version != MEMPROF_RAW_VERSION) {
+ return make_error<InstrProfError>(instrprof_error::unsupported_version);
+ }
+
+ TotalSize += H->TotalSize;
+ Next += H->TotalSize;
+ }
+
+ if (Buffer->getBufferSize() != TotalSize) {
+ return make_error<InstrProfError>(instrprof_error::malformed);
+ }
+
+ return std::make_unique<RawMemProfReader>(std::move(Buffer));
+}
+
+bool RawMemProfReader::hasFormat(const MemoryBuffer &Buffer) {
+ if (Buffer.getBufferSize() < sizeof(uint64_t))
+ return false;
+ uint64_t Magic = *reinterpret_cast<const uint64_t *>(Buffer.getBufferStart());
+ return Magic == MEMPROF_RAW_MAGIC_64;
+}
+
+void RawMemProfReader::printSummaries(raw_ostream &OS) const {
+ int Count = 0;
+ const char *Next = DataBuffer->getBufferStart();
+ while (Next < DataBuffer->getBufferEnd()) {
+ auto Summary = computeSummary(Next);
+ OS << "MemProf Profile " << ++Count << "\n";
+ OS << " Version: " << Summary.Version << "\n";
+ OS << " TotalSizeBytes: " << Summary.TotalSizeBytes << "\n";
+ OS << " NumSegments: " << Summary.NumSegments << "\n";
+ OS << " NumMIBInfo: " << Summary.NumMIBInfo << "\n";
+ OS << " NumStackOffsets: " << Summary.NumStackOffsets << "\n";
+ // TODO: Print the build ids once we can record them using the
+ // sanitizer_procmaps library for linux.
+
+ auto *H = reinterpret_cast<const Header *>(Next);
+ Next += H->TotalSize;
+ }
+}
+
+} // namespace memprof
+} // namespace llvm
diff --git a/llvm/test/tools/llvm-profdata/Inputs/basic.memprofraw b/llvm/test/tools/llvm-profdata/Inputs/basic.memprofraw
new file mode 100644
index 000000000000..b0be02ade8da
Binary files /dev/null and b/llvm/test/tools/llvm-profdata/Inputs/basic.memprofraw
diff er
diff --git a/llvm/test/tools/llvm-profdata/Inputs/multi.memprofraw b/llvm/test/tools/llvm-profdata/Inputs/multi.memprofraw
new file mode 100644
index 000000000000..e740903344ca
Binary files /dev/null and b/llvm/test/tools/llvm-profdata/Inputs/multi.memprofraw
diff er
diff --git a/llvm/test/tools/llvm-profdata/memprof-basic.test b/llvm/test/tools/llvm-profdata/memprof-basic.test
new file mode 100644
index 000000000000..b9f624d0038e
--- /dev/null
+++ b/llvm/test/tools/llvm-profdata/memprof-basic.test
@@ -0,0 +1,40 @@
+The input raw profile test has been generated from the following source code:
+
+```
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+ char *x = (char *)malloc(10);
+ memset(x, 0, 10);
+ free(x);
+ x = (char *)malloc(10);
+ memset(x, 0, 10);
+ free(x);
+ return 0;
+}
+```
+
+The following commands were used to compile the source to a memprof instrumented
+executable and collect a raw binary format profile. Since the profile contains
+virtual addresses for the callstack, we do not expect the raw binary profile to
+be deterministic. The summary should be deterministic apart from changes to
+the shared libraries linked in which could change the number of segments
+recorded.
+
+```
+clang -fmemory-profile -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls -gline-tables-only -m64 -Wl,-build-id source.c -o rawprofile.out
+
+env MEMPROF_OPTIONS=log_path=stdout ./rawprofile.out > basic.memprofraw
+```
+
+RUN: llvm-profdata show --memory %p/Inputs/basic.memprofraw -o - | FileCheck %s
+
+We expect 3 MIB entries, 1 each for the malloc calls in the program and one
+additional entry from a realloc in glibc/libio/vasprintf.c.
+
+CHECK: MemProf Profile 1
+CHECK: Version: 1
+CHECK: TotalSizeBytes: 1012
+CHECK: NumSegments: 9
+CHECK: NumMIBInfo: 3
+CHECK: NumStackOffsets: 3
diff --git a/llvm/test/tools/llvm-profdata/memprof-multi.test b/llvm/test/tools/llvm-profdata/memprof-multi.test
new file mode 100644
index 000000000000..d27612b18779
--- /dev/null
+++ b/llvm/test/tools/llvm-profdata/memprof-multi.test
@@ -0,0 +1,48 @@
+The input raw profile test has been generated from the following source code:
+
+```
+#include <sanitizer/memprof_interface.h>
+#include <stdlib.h>
+#include <string.h>
+int main(int argc, char **argv) {
+ char *x = (char *)malloc(10);
+ memset(x, 0, 10);
+ free(x);
+ __memprof_profile_dump();
+ x = (char *)malloc(10);
+ memset(x, 0, 10);
+ free(x);
+ return 0;
+}
+```
+
+The following commands were used to compile the source to a memprof instrumented
+executable and collect a raw binary format profile. Since the profile contains
+virtual addresses for the callstack, we do not expect the raw binary profile to
+be deterministic. The summary should be deterministic apart from changes to
+the shared libraries linked in which could change the number of segments
+recorded.
+
+```
+clang -fmemory-profile -mno-omit-leaf-frame-pointer -fno-omit-frame-pointer -fno-optimize-sibling-calls -gline-tables-only -m64 -Wl,-build-id source.c -o rawprofile.out
+
+env MEMPROF_OPTIONS=log_path=stdout ./rawprofile.out > multi.memprofraw
+```
+
+RUN: llvm-profdata show --memory %p/Inputs/multi.memprofraw -o - | FileCheck %s
+
+We expect 2 MIB entries, 1 each for the malloc calls in the program. Unlike the
+memprof-basic.test we do not see any allocation from glibc.
+
+CHECK: MemProf Profile 1
+CHECK: Version: 1
+CHECK: TotalSizeBytes: 864
+CHECK: NumSegments: 9
+CHECK: NumMIBInfo: 2
+CHECK: NumStackOffsets: 2
+CHECK: MemProf Profile 2
+CHECK: Version: 1
+CHECK: TotalSizeBytes: 864
+CHECK: NumSegments: 9
+CHECK: NumMIBInfo: 2
+CHECK: NumStackOffsets: 2
diff --git a/llvm/test/tools/llvm-profdata/text-format-errors.test b/llvm/test/tools/llvm-profdata/text-format-errors.test
index 9d3f3ff6e989..4a75edd70ff4 100644
--- a/llvm/test/tools/llvm-profdata/text-format-errors.test
+++ b/llvm/test/tools/llvm-profdata/text-format-errors.test
@@ -25,7 +25,7 @@ NO-COUNTS: error: {{.*}}no-counts.proftext: malformed instrumentation profile da
4- Detect binary input
RUN: not llvm-profdata show %p/Inputs/text-format-errors.text.bin 2>&1 | FileCheck %s --check-prefix=BINARY
BINARY: error: {{.+}}: unrecognized instrumentation profile encoding format
-BINARY: Perhaps you forgot to use the --sample option?
+BINARY: Perhaps you forgot to use the --sample or --memory option?
5- Detect malformed value profile data
RUN: not llvm-profdata show %p/Inputs/vp-malform.proftext 2>&1 | FileCheck %s --check-prefix=VP
diff --git a/llvm/tools/llvm-profdata/llvm-profdata.cpp b/llvm/tools/llvm-profdata/llvm-profdata.cpp
index fd67cac3cdd2..7208011c9866 100644
--- a/llvm/tools/llvm-profdata/llvm-profdata.cpp
+++ b/llvm/tools/llvm-profdata/llvm-profdata.cpp
@@ -17,6 +17,7 @@
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/ProfileData/InstrProfWriter.h"
#include "llvm/ProfileData/ProfileCommon.h"
+#include "llvm/ProfileData/RawMemProfReader.h"
#include "llvm/ProfileData/SampleProfReader.h"
#include "llvm/ProfileData/SampleProfWriter.h"
#include "llvm/Support/CommandLine.h"
@@ -80,8 +81,8 @@ static void exitWithError(Error E, StringRef Whence = "") {
instrprof_error instrError = IPE.get();
StringRef Hint = "";
if (instrError == instrprof_error::unrecognized_format) {
- // Hint for common error of forgetting --sample for sample profiles.
- Hint = "Perhaps you forgot to use the --sample option?";
+ // Hint in case user missed specifying the profile type.
+ Hint = "Perhaps you forgot to use the --sample or --memory option?";
}
exitWithError(IPE.message(), std::string(Whence), std::string(Hint));
});
@@ -95,7 +96,7 @@ static void exitWithErrorCode(std::error_code EC, StringRef Whence = "") {
}
namespace {
-enum ProfileKinds { instr, sample };
+enum ProfileKinds { instr, sample, memory };
enum FailureMode { failIfAnyAreInvalid, failIfAllAreInvalid };
}
@@ -2447,6 +2448,17 @@ static int showSampleProfile(const std::string &Filename, bool ShowCounts,
return 0;
}
+static int showMemProfProfile(const std::string &Filename, raw_fd_ostream &OS) {
+ auto ReaderOr = llvm::memprof::RawMemProfReader::create(Filename);
+ if (Error E = ReaderOr.takeError())
+ exitWithError(std::move(E), Filename);
+
+ std::unique_ptr<llvm::memprof::RawMemProfReader> Reader(
+ ReaderOr.get().release());
+ Reader->printSummaries(OS);
+ return 0;
+}
+
static int show_main(int argc, const char *argv[]) {
cl::opt<std::string> Filename(cl::Positional, cl::Required,
cl::desc("<profdata-file>"));
@@ -2487,7 +2499,8 @@ static int show_main(int argc, const char *argv[]) {
cl::opt<ProfileKinds> ProfileKind(
cl::desc("Profile kind:"), cl::init(instr),
cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
- clEnumVal(sample, "Sample profile")));
+ clEnumVal(sample, "Sample profile"),
+ clEnumVal(memory, "MemProf memory access profile")));
cl::opt<uint32_t> TopNFunctions(
"topn", cl::init(0),
cl::desc("Show the list of functions with the largest internal counts"));
@@ -2532,11 +2545,12 @@ static int show_main(int argc, const char *argv[]) {
ShowMemOPSizes, ShowDetailedSummary, DetailedSummaryCutoffs,
ShowAllFunctions, ShowCS, ValueCutoff, OnlyListBelow, ShowFunction,
TextFormat, ShowBinaryIds, OS);
- else
+ if (ProfileKind == sample)
return showSampleProfile(Filename, ShowCounts, TopNFunctions,
ShowAllFunctions, ShowDetailedSummary,
ShowFunction, ShowProfileSymbolList,
ShowSectionInfoOnly, ShowHotFuncList, OS);
+ return showMemProfProfile(Filename, OS);
}
int main(int argc, const char *argv[]) {
More information about the llvm-commits
mailing list