[PATCH] This patch is the full version of the 5 individual patches that portthe Perf converter from https://github.com/google/autofdo.The earlier patches are described in detail at:http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon...
Justin Bogner
mail at justinbogner.com
Wed Aug 13 16:07:09 PDT 2014
Diego Novillo <dnovillo at google.com> writes:
> I tried creating 5 individual phabricator issues for this, but they are
> very hard to maintain as they are all in the same tree. Phabricator does
> not make this easy in any way.
>
> Main changes:
>
> - Remove unused parts of LinuxPerf/utils.cc to avoid -lcrypto dependency.
> - Add -Wno-pedantic for LinuxPerf
> - Removed all the unused code.
> - Removed all traces of base/, glog/ and gflags/
> - Add samplepgo namespace. Rename ProfileCreator to SampleProfileConverter.
> - Add LLVM copyright headers.
> - Add support for autoconf.
>
> http://reviews.llvm.org/D4850
I haven't looked at anything under ProfileData/PerfConverter in detail,
but it looks pretty reasonable at a high level given that you plan on
replacing the parts that obviously duplicate llvm functionality RSN.
Some tests would be nice.
I can't help but think that it'd be nice if the API that other parts of
LLVM will use follows the LLVM style - ie, the classes in the
SampleProfileConverter/Reader headers. I'll make some specific nitpicks
about that below.
The changes to llvm-profdata are obvious and look great. I have a minor
style comment in there, but otherwise that part LGTM.
> Index: include/llvm/ProfileData/SampleProfileConverter.h
> ===================================================================
> --- /dev/null
> +++ include/llvm/ProfileData/SampleProfileConverter.h
> @@ -0,0 +1,57 @@
> +//=-- SampleProfileConverter.h - Sample profile converter API -----*- C++ -*-=//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file contains support for converting profiles from external profilers
> +// into the format supported by lib/Transforms/Scalar/SampleProfile.cpp.
> +//
> +//===----------------------------------------------------------------------===//
> +#ifndef SAMPLEPGO_PROFILE_CONVERTER_H_
> +#define SAMPLEPGO_PROFILE_CONVERTER_H_
> +
> +#include "llvm/ProfileData/SampleProfileReader.h"
> +
> +namespace samplepgo {
> +
> +class SampleProfileConverter {
> + public:
> + explicit SampleProfileConverter(const string &binary) : sample_reader_(NULL),
> + binary_(binary) {}
This indentation's a bit odd, and I'd prefer nullptr here.
> +
> + ~SampleProfileConverter() {
> + delete sample_reader_;
> + }
sample_reader_ could be a unique_ptr to make ownership explicit and save
writing this destructor, though since it's entirely private it doesn't
really matter.
> +
> + // Creates SamplePGO profile, returns true if success, false otherwise.
Please add an extra slash (///) so that doxygen picks these up.
> + bool CreateProfile(const string &input_profile_name,
> + const string &profiler,
> + const string &output_profile_name);
Lower case names for these functions would make using this API more
LLVM-y.
> +
> + // Reads samples from the input profile.
> + bool ReadSample(const string &input_profile_name,
> + const string &profiler);
> +
> + // Creates output profile after reading from the input profile.
> + bool CreateProfileFromSample(const string &output_profile_name);
> +
> + // Returns total number of samples collected.
> + uint64_t TotalSamples();
> +
> + // Returns the SampleReader pointer.
> + const samplepgo::SampleReader &sample_reader() {
> + return *sample_reader_;
> + }
A name like getSampleReader would be more consistent with other LLVM APIs.
> +
> + private:
> + SampleReader *sample_reader_;
> + string binary_;
> +};
> +
> +} // namespace samplepgo
> +
> +#endif // SAMPLEPGO_PROFILE_CONVERTER_H_
> Index: include/llvm/ProfileData/SampleProfileReader.h
> ===================================================================
> --- /dev/null
> +++ include/llvm/ProfileData/SampleProfileReader.h
> @@ -0,0 +1,106 @@
> +//=-- SampleProfileReader.h - Generic sample profiling reader API -*- C++ -*-=//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file contains support for reading profiling data from external
> +// sampling profilers.
> +//
> +//===----------------------------------------------------------------------===//
> +#ifndef SAMPLEPGO_SAMPLE_READER_H_
> +#define SAMPLEPGO_SAMPLE_READER_H_
> +
> +#include <map>
> +#include <set>
> +#include <string>
> +#include <vector>
> +#include <utility>
> +
> +#include "llvm/Support/DataTypes.h"
> +
> +using namespace std;
> +
> +namespace samplepgo {
> +
> +typedef map<uint64_t, uint64_t> AddressCountMap;
> +typedef pair<uint64_t, uint64_t> Range;
> +typedef map<Range, uint64_t> RangeCountMap;
> +typedef pair<uint64_t, uint64_t> Branch;
> +typedef map<Branch, uint64_t> BranchCountMap;
> +
> +// Reads in the profile data, and represent it in address_count_map_.
> +class SampleReader {
> +public:
> + explicit SampleReader() : max_count_(0) {}
> + virtual ~SampleReader() {}
> +
> + bool ReadAndSetMaxCount();
> +
> + const AddressCountMap &address_count_map() const {
> + return address_count_map_;
> + }
> +
> + const RangeCountMap &range_count_map() const { return range_count_map_; }
> +
> + const BranchCountMap &branch_count_map() const { return branch_count_map_; }
> +
> + set<uint64_t> GetSampledAddresses() const;
> +
> + // Returns the sample count for a given instruction.
> + uint64_t GetSampleCountOrZero(uint64_t addr) const;
See above comments on naming and doxygen comments :)
> +
> + // Returns the total sampled count.
> + uint64_t GetTotalSampleCount() const;
> +
> + // Returns the max count.
> + uint64_t GetMaxCount() const { return max_count_; }
> +
> + // Clear all maps to release memory.
> + void Clear() {
> + address_count_map_.clear();
> + range_count_map_.clear();
> + branch_count_map_.clear();
> + }
> +
> +protected:
> + // Virtual read function to read from different types of profiles.
> + virtual bool Read() = 0;
> +
> + uint64_t max_count_;
> + AddressCountMap address_count_map_;
> + RangeCountMap range_count_map_;
> + BranchCountMap branch_count_map_;
> +};
> +
> +// Base class that reads in the profile from a sample data file.
> +class FileSampleReader : public SampleReader {
> +public:
> + explicit FileSampleReader(const string &profile_file)
> + : profile_file_(profile_file) {}
> +
> + virtual bool Append(const string &profile_file) = 0;
> +
> +protected:
> + virtual bool Read();
> +
> + string profile_file_;
> +};
> +
> +// Reads in the sample data from a 'perf -b' output file.
> +class PerfDataSampleReader : public FileSampleReader {
> +public:
> + explicit PerfDataSampleReader(const string &profile_file, const string &re)
> + : FileSampleReader(profile_file), focus_binary_re_(re) {}
> + virtual bool Append(const string &profile_file);
> +
> +private:
> + const string focus_binary_re_;
> +};
> +
> +} // namespace samplepgo
> +
> +#endif // SAMPLEPGO_SAMPLE_READER_H_
<snip>
> Index: tools/llvm-profdata/llvm-profdata.cpp
> ===================================================================
> --- tools/llvm-profdata/llvm-profdata.cpp
> +++ tools/llvm-profdata/llvm-profdata.cpp
> @@ -14,6 +14,7 @@
> #include "llvm/ADT/StringRef.h"
> #include "llvm/ProfileData/InstrProfReader.h"
> #include "llvm/ProfileData/InstrProfWriter.h"
> +#include "llvm/ProfileData/SampleProfileConverter.h"
> #include "llvm/Support/CommandLine.h"
> #include "llvm/Support/FileSystem.h"
> #include "llvm/Support/Format.h"
> @@ -150,6 +151,59 @@
> return 0;
> }
>
> +int convert_main(int argc, const char *argv[]) {
> + cl::opt<std::string> InputProfile(cl::Positional, cl::Required,
> + cl::desc("<profdata-file>"));
> +
> + cl::opt<std::string> ProfileType(
> + "profile-type", cl::desc("Input profile type"), cl::init("perf"));
> +
> + cl::opt<std::string> OutputProfile("out",
> + cl::desc("Output profile file name"));
> + cl::alias OutputProfileA("o", cl::desc("Alias for --output"),
> + cl::aliasopt(OutputProfile));
> +
> + cl::opt<std::string> InputBinary(
> + "binary", cl::desc("Input binary executable (in ELF format) to read "
> + "(this executable must be compiled with -gmlt)"));
> +
> + const char *usage = "\nConverts a sample profile collected with Linux Perf "
> + "(https://perf.wiki.kernel.org/)\n"
> + "into an LLVM sample profile. The output file can be "
> + "used with Clang's -fprofile-sample-use flag.\n"
> + "\nSample usage:\n"
> + "\n$ llvm-profdata --out=perf.llvm --binary=a.out "
> + "--type=perf perf.data\n";
> +
> + cl::ParseCommandLineOptions(argc, argv, usage);
> +
> + if (InputProfile.empty()) {
> + errs() << usage;
> + errs() << "Need a name for the input profile file.\n";
> + return 1;
> + }
> +
> + if (OutputProfile.empty()) {
> + errs() << usage;
> + errs() << "Need a name for the output LLVM profile file.\n";
> + errs() << "Use --out to specify an output file.\n";
> + return 1;
> + }
> +
> + if (InputBinary.empty()) {
> + errs() << usage;
> + errs() << "Need a name for the ELF executable.\n";
> + errs() << "Use --binary to specify an input executable file.\n";
> + return 1;
> + }
> +
> + samplepgo::SampleProfileConverter converter(InputBinary);
> + if (converter.CreateProfile(InputProfile, ProfileType, OutputProfile))
> + return 0;
> + else
> + return -1;
This should be called "Converter", and I find this easier to read like so:
samplepgo::SampleProfileConverter Converter(InputBinary);
if (!Converter.CreateProfile(InputProfile, ProfileType, OutputProfile))
return -1;
return 0;
> +}
> +
> int main(int argc, const char *argv[]) {
> // Print a stack trace if we signal out.
> sys::PrintStackTraceOnErrorSignal();
> @@ -164,6 +218,8 @@
> func = merge_main;
> else if (strcmp(argv[1], "show") == 0)
> func = show_main;
> + else if (strcmp(argv[1], "convert") == 0)
> + func = convert_main;
>
> if (func) {
> std::string Invocation(ProgName.str() + " " + argv[1]);
> @@ -178,7 +234,7 @@
> errs() << "OVERVIEW: LLVM profile data tools\n\n"
> << "USAGE: " << ProgName << " <command> [args...]\n"
> << "USAGE: " << ProgName << " <command> -help\n\n"
> - << "Available commands: merge, show\n";
> + << "Available commands: merge, show, convert\n";
> return 0;
> }
> }
> @@ -188,6 +244,6 @@
> else
> errs() << ProgName << ": Unknown command!\n";
>
> - errs() << "USAGE: " << ProgName << " <merge|show> [args...]\n";
> + errs() << "USAGE: " << ProgName << " <merge|show|convert> [args...]\n";
> return 1;
> }
More information about the llvm-commits
mailing list