Skip to content
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

-Add -g option to save sample indices following Go's PGO requirements #171

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 30 additions & 19 deletions src/perf_data_converter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -500,27 +500,37 @@ ProfileBuilder* PerfDataConverter::GetOrCreateBuilder(
int unknown_event_idx = 0;
for (int event_idx = 0; event_idx < perf_data_.file_attrs_size();
++event_idx) {
// Come up with an event name for this event. perf.data will usually
// contain an event_types section of the same cardinality as its
// file_attrs; in this case we can just use the name there. Otherwise
// we just give it an anonymous name.
std::string event_name = "";
if (perf_data_.file_attrs_size() == perf_data_.event_types_size()) {
const auto& event_type = perf_data_.event_types(event_idx);
if (event_type.has_name()) {
event_name = event_type.name() + "_";
if (options_ & kFollowGoPgoRequirements) {
auto sample_type = profile->add_sample_type();
sample_type->set_type(UTF8StringId("samples", builder));
sample_type->set_unit(builder->StringId("count"));
sample_type = profile->add_sample_type();
last_index = UTF8StringId("event", builder);
sample_type->set_type(last_index);
sample_type->set_unit(builder->StringId("count"));
} else {
// Come up with an event name for this event. perf.data will usually
// contain an event_types section of the same cardinality as its
// file_attrs; in this case we can just use the name there. Otherwise
// we just give it an anonymous name.
std::string event_name = "";
if (perf_data_.file_attrs_size() == perf_data_.event_types_size()) {
const auto& event_type = perf_data_.event_types(event_idx);
if (event_type.has_name()) {
event_name = event_type.name() + "_";
}
}
if (event_name.empty()) {
event_name = "event_" + std::to_string(unknown_event_idx++) + "_";
}
auto sample_type = profile->add_sample_type();
sample_type->set_type(UTF8StringId(event_name + "sample", builder));
sample_type->set_unit(builder->StringId("count"));
sample_type = profile->add_sample_type();
last_index = UTF8StringId(event_name + "event", builder);
sample_type->set_type(last_index);
sample_type->set_unit(builder->StringId("count"));
}
if (event_name.empty()) {
event_name = "event_" + std::to_string(unknown_event_idx++) + "_";
}
auto sample_type = profile->add_sample_type();
sample_type->set_type(UTF8StringId(event_name + "sample", builder));
sample_type->set_unit(builder->StringId("count"));
sample_type = profile->add_sample_type();
last_index = UTF8StringId(event_name + "event", builder);
sample_type->set_type(last_index);
sample_type->set_unit(builder->StringId("count"));
}
DCHECK_NE(last_index, 0);
profile->set_default_sample_type(last_index);
Expand Down Expand Up @@ -945,6 +955,7 @@ ProcessProfiles RawPerfDataToProfiles(
opts.deduce_huge_page_mappings = true;
opts.combine_mappings = true;
opts.allow_unaligned_jit_mappings = options & kAllowUnalignedJitMappings;
opts.follow_go_pgo_requirements = options & kFollowGoPgoRequirements;
quipper::PerfParser parser(&reader, opts);
if (!parser.ParseRawEvents()) {
LOG(ERROR) << "Could not parse perf events.";
Expand Down
4 changes: 4 additions & 0 deletions src/perf_data_converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ enum ConversionOptions {
// Whether to add sampled data addresses as leaf frames for converted
// profiles.
kAddDataAddressFrames = 8,
// Whether to save sample indices following Go's PGO requirements,
// with at least one of the indices having type/unit of samples/count
// or cpu/nanoseconds. https://go.dev/doc/pgo#alternative-sources
kFollowGoPgoRequirements = 16,
};

struct ProcessProfile {
Expand Down
6 changes: 5 additions & 1 deletion src/perf_to_profile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ int main(int argc, char** argv) {
std::string input, output;
bool overwriteOutput = false;
bool allowUnalignedJitMappings = false;
bool followGoPgoRequirements = false;
if (!ParseArguments(argc, const_cast<const char**>(argv), &input, &output,
&overwriteOutput, &allowUnalignedJitMappings)) {
&overwriteOutput, &allowUnalignedJitMappings, &followGoPgoRequirements)) {
PrintUsage();
return EXIT_FAILURE;
}
Expand All @@ -24,6 +25,9 @@ int main(int argc, char** argv) {
if (allowUnalignedJitMappings) {
options |= perftools::ConversionOptions::kAllowUnalignedJitMappings;
}
if (followGoPgoRequirements) {
options |= perftools::ConversionOptions::kFollowGoPgoRequirements;
}
std::string data = ReadFileToString(input);
const auto profiles = StringToProfiles(data, perftools::kNoLabels, options);

Expand Down
13 changes: 11 additions & 2 deletions src/perf_to_profile_lib.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,23 @@ void PrintUsage() {
<< "profile.";
LOG(INFO) << "If the -j option is given, allow unaligned MMAP events "
<< "required by perf data from VMs with JITs.";
LOG(INFO) << "If the -g option is given, saves the profile with sample "
<< "indices that follow Go's PGO requirements: "
<< "one of the indices should have the type/unit "
<< "“samples”/“count” or “cpu”/“nanoseconds”.";
}

bool ParseArguments(int argc, const char* argv[], std::string* input,
std::string* output, bool* overwrite_output,
bool* allow_unaligned_jit_mappings) {
bool* allow_unaligned_jit_mappings,
bool* follow_go_pgo_requirements) {
*input = "";
*output = "";
*overwrite_output = false;
*allow_unaligned_jit_mappings = false;
*follow_go_pgo_requirements = false;
int opt;
while ((opt = getopt(argc, const_cast<char* const*>(argv), ":jfi:o:")) !=
while ((opt = getopt(argc, const_cast<char* const*>(argv), ":gjfi:o:")) !=
-1) {
switch (opt) {
case 'i':
Expand All @@ -82,6 +88,9 @@ bool ParseArguments(int argc, const char* argv[], std::string* input,
case 'j':
*allow_unaligned_jit_mappings = true;
break;
case 'g':
*follow_go_pgo_requirements = true;
break;
case ':':
LOG(ERROR) << "Must provide arguments for flags -i and -o";
return false;
Expand Down
5 changes: 3 additions & 2 deletions src/perf_to_profile_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ void CreateFile(const std::string& path, std::ofstream* file,
bool overwrite_output);

// Parses arguments, stores the results in |input|, |output|
// |overwrite_output| and |allow_unaligned_jit_mappings|, and returns true if
// |overwrite_output|, |allow_unaligned_jit_mappings| and |follow_go_pgo_requirements|, and returns true if
// arguments parsed successfully and false otherwise.
bool ParseArguments(int argc, const char* argv[], std::string* input,
std::string* output, bool* overwrite_output,
bool* allow_unaligned_jit_mappings);
bool* allow_unaligned_jit_mappings,
bool* follow_go_pgo_requirements);

// Prints the usage of the tool.
void PrintUsage();
Expand Down
12 changes: 11 additions & 1 deletion src/perf_to_profile_lib_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ TEST(PerfToProfileTest, ParseArguments) {
std::string expected_output;
bool expected_overwrite_output;
bool allow_unaligned_jit_mappings;
bool follow_go_pgo_requirements;
bool want_error;
};

Expand All @@ -34,6 +35,7 @@ TEST(PerfToProfileTest, ParseArguments) {
.expected_output = "output_profile",
.expected_overwrite_output = true,
.allow_unaligned_jit_mappings = false,
.follow_go_pgo_requirements = false,
.want_error = false});
tests.push_back(
Test{.desc = "With input and output flags",
Expand All @@ -42,6 +44,7 @@ TEST(PerfToProfileTest, ParseArguments) {
.expected_output = "output_profile",
.expected_overwrite_output = false,
.allow_unaligned_jit_mappings = false,
.follow_go_pgo_requirements = false,
.want_error = false});
tests.push_back(Test{
.desc = "With input and output flags and jit-support",
Expand All @@ -50,13 +53,15 @@ TEST(PerfToProfileTest, ParseArguments) {
.expected_output = "output_profile",
.expected_overwrite_output = false,
.allow_unaligned_jit_mappings = true,
.follow_go_pgo_requirements = false,
.want_error = false});
tests.push_back(Test{.desc = "With only overwrite flag",
.argv = {"<exec>", "-f"},
.expected_input = "",
.expected_output = "",
.expected_overwrite_output = false,
.allow_unaligned_jit_mappings = false,
.follow_go_pgo_requirements = false,
.want_error = true});
tests.push_back(Test{
.desc = "With input, output, and invalid flags",
Expand All @@ -65,30 +70,35 @@ TEST(PerfToProfileTest, ParseArguments) {
.expected_output = "",
.expected_overwrite_output = false,
.allow_unaligned_jit_mappings = false,
.follow_go_pgo_requirements = false,
.want_error = true});
tests.push_back(Test{.desc = "With an invalid flag",
.argv = {"<exec>", "-F"},
.expected_input = "",
.expected_output = "",
.expected_overwrite_output = false,
.allow_unaligned_jit_mappings = false,
.follow_go_pgo_requirements = false,
.want_error = true});
for (auto test : tests) {
std::string input;
std::string output;
bool overwrite_output;
bool allow_unaligned_jit_mappings;
bool follow_go_pgo_requirements;
LOG(INFO) << "Testing: " << test.desc;
EXPECT_THAT(
ParseArguments(test.argv.size(), test.argv.data(), &input, &output,
&overwrite_output, &allow_unaligned_jit_mappings),
&overwrite_output, &allow_unaligned_jit_mappings, &follow_go_pgo_requirements),
Eq(!test.want_error));
if (!test.want_error) {
EXPECT_THAT(input, Eq(test.expected_input));
EXPECT_THAT(output, Eq(test.expected_output));
EXPECT_THAT(overwrite_output, Eq(test.expected_overwrite_output));
EXPECT_THAT(allow_unaligned_jit_mappings,
Eq(test.allow_unaligned_jit_mappings));
EXPECT_THAT(follow_go_pgo_requirements,
Eq(test.follow_go_pgo_requirements));
}
optind = 1;
}
Expand Down
4 changes: 4 additions & 0 deletions src/quipper/perf_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ struct PerfParserOptions {
// Handle unaligned MMAP events emited by VMs that dynamically generate
// code objects.
bool allow_unaligned_jit_mappings = false;
// The sample indices will be saved following Go's PGO requirements,
// with at least one of the indexes having type/unit samples/count
// or cpu/nanoseconds. https://go.dev/doc/pgo#alternative-sources
bool follow_go_pgo_requirements = false;
};

class PerfParser {
Expand Down