blob: 474b0469911c8c5e584fa0171baf0b0c3b190ccc [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <algorithm>
#include <map>
#include <string>
#include "base/logging.h"
#include "perf_reader.h"
#include "perf_test_files.h"
#include "quipper_string.h"
#include "quipper_test.h"
#include "scoped_temp_path.h"
#include "test_utils.h"
#include "utils.h"
namespace quipper {
namespace {
// Any run of perf should have MMAPs with the following substrings.
const char* kExpectedFilenameSubstrings[] = {
"perf",
"kernel",
"libc",
};
void CheckNoDuplicates(const std::vector<string>& list) {
std::set<string> list_as_set(list.begin(), list.end());
if (list.size() != list_as_set.size())
ADD_FAILURE() << "Given list has at least one duplicate";
}
void CheckForElementWithSubstring(string substring_to_find,
const std::vector<string>& list) {
std::vector<string>::const_iterator iter;
for (iter = list.begin(); iter != list.end(); ++iter)
if (iter->find(substring_to_find) != string::npos)
return;
ADD_FAILURE() << substring_to_find
<< " is not present in any of the elements of the given list";
}
void CreateFilenameToBuildIDMap(
const std::vector<string>& filenames, unsigned int seed,
std::map<string, string>* filenames_to_build_ids) {
srand(seed);
// Only use every other filename, so that half the filenames are unused.
for (size_t i = 0; i < filenames.size(); i += 2) {
u8 build_id[kBuildIDArraySize];
for (size_t j = 0; j < kBuildIDArraySize; ++j)
build_id[j] = rand_r(&seed);
(*filenames_to_build_ids)[filenames[i]] =
HexToString(build_id, kBuildIDArraySize);
}
}
void CheckFilenameAndBuildIDMethods(const string& input_perf_data,
const string& output_perf_data_prefix,
unsigned int seed,
PerfReader* reader) {
// Check filenames.
std::vector<string> filenames;
reader->GetFilenames(&filenames);
ASSERT_FALSE(filenames.empty());
CheckNoDuplicates(filenames);
for (size_t i = 0; i < arraysize(kExpectedFilenameSubstrings); ++i)
CheckForElementWithSubstring(kExpectedFilenameSubstrings[i], filenames);
std::set<string> filename_set;
reader->GetFilenamesAsSet(&filename_set);
// Make sure all MMAP filenames are in the set.
const std::vector<event_t*>& events = reader->events();
for (size_t i = 0; i < events.size(); ++i) {
const event_t& event = *events[i];
if (event.header.type == PERF_RECORD_MMAP) {
EXPECT_TRUE(filename_set.find(event.mmap.filename) != filename_set.end())
<< event.mmap.filename << " is not present in the filename set";
}
}
std::map<string, string> expected_map;
reader->GetFilenamesToBuildIDs(&expected_map);
// Inject some made up build ids.
std::map<string, string> filenames_to_build_ids;
CreateFilenameToBuildIDMap(filenames, seed, &filenames_to_build_ids);
ASSERT_TRUE(reader->InjectBuildIDs(filenames_to_build_ids));
// Reader should now correctly populate the filenames to build ids map.
std::map<string, string>::const_iterator it;
for (it = filenames_to_build_ids.begin();
it != filenames_to_build_ids.end();
++it) {
expected_map[it->first] = it->second;
}
std::map<string, string> reader_map;
reader->GetFilenamesToBuildIDs(&reader_map);
EXPECT_EQ(expected_map, reader_map);
string output_perf_data1 = output_perf_data_prefix + ".parse.inject.out";
ASSERT_TRUE(reader->WriteFile(output_perf_data1));
// Perf should find the same build ids.
std::map<string, string> perf_build_id_map;
ASSERT_TRUE(GetPerfBuildIDMap(output_perf_data1, &perf_build_id_map));
EXPECT_EQ(expected_map, perf_build_id_map);
std::map<string, string> build_id_localizer;
// Only localize the first half of the files which have build ids.
for (size_t j = 0; j < filenames.size() / 2; ++j) {
string old_filename = filenames[j];
if (expected_map.find(old_filename) == expected_map.end())
continue;
string build_id = expected_map[old_filename];
string new_filename = old_filename + ".local";
filenames[j] = new_filename;
build_id_localizer[build_id] = new_filename;
expected_map[new_filename] = build_id;
expected_map.erase(old_filename);
}
reader->Localize(build_id_localizer);
// Filenames should be the same.
std::vector<string> new_filenames;
reader->GetFilenames(&new_filenames);
std::sort(filenames.begin(), filenames.end());
EXPECT_EQ(filenames, new_filenames);
// Build ids should be updated.
reader_map.clear();
reader->GetFilenamesToBuildIDs(&reader_map);
EXPECT_EQ(expected_map, reader_map);
string output_perf_data2 = output_perf_data_prefix + ".parse.localize.out";
ASSERT_TRUE(reader->WriteFile(output_perf_data2));
perf_build_id_map.clear();
ASSERT_TRUE(GetPerfBuildIDMap(output_perf_data2, &perf_build_id_map));
EXPECT_EQ(expected_map, perf_build_id_map);
std::map<string, string> filename_localizer;
// Only localize every third filename.
for (size_t j = 0; j < filenames.size(); j += 3) {
string old_filename = filenames[j];
string new_filename = old_filename + ".local2";
filenames[j] = new_filename;
filename_localizer[old_filename] = new_filename;
if (expected_map.find(old_filename) != expected_map.end()) {
string build_id = expected_map[old_filename];
expected_map[new_filename] = build_id;
expected_map.erase(old_filename);
}
}
reader->LocalizeUsingFilenames(filename_localizer);
// Filenames should be the same.
new_filenames.clear();
reader->GetFilenames(&new_filenames);
std::sort(filenames.begin(), filenames.end());
EXPECT_EQ(filenames, new_filenames);
// Build ids should be updated.
reader_map.clear();
reader->GetFilenamesToBuildIDs(&reader_map);
EXPECT_EQ(expected_map, reader_map);
string output_perf_data3 = output_perf_data_prefix + ".parse.localize2.out";
ASSERT_TRUE(reader->WriteFile(output_perf_data3));
perf_build_id_map.clear();
ASSERT_TRUE(GetPerfBuildIDMap(output_perf_data3, &perf_build_id_map));
EXPECT_EQ(expected_map, perf_build_id_map);
}
} // namespace
TEST(PerfReaderTest, Test1Cycle) {
ScopedTempDir output_dir;
ASSERT_FALSE(output_dir.path().empty());
string output_path = output_dir.path();
for (unsigned int i = 0;
i < arraysize(perf_test_files::kPerfDataFiles);
++i) {
const char* test_file = perf_test_files::kPerfDataFiles[i];
string input_perf_data = GetTestInputFilePath(test_file);
LOG(INFO) << "Testing " << input_perf_data;
string output_perf_data = output_path + test_file + ".pr.out";
PerfReader pr;
ASSERT_TRUE(pr.ReadFile(input_perf_data));
ASSERT_TRUE(pr.WriteFile(output_perf_data));
EXPECT_TRUE(CheckPerfDataAgainstBaseline(input_perf_data));
EXPECT_TRUE(CheckPerfDataAgainstBaseline(output_perf_data));
EXPECT_TRUE(ComparePerfBuildIDLists(input_perf_data, output_perf_data));
CheckFilenameAndBuildIDMethods(input_perf_data, output_path + test_file,
i, &pr);
}
std::map<string, std::vector<string> > metadata;
for (unsigned int i = 0;
i < arraysize(perf_test_files::kPerfPipedDataFiles);
++i) {
const char* test_file = perf_test_files::kPerfPipedDataFiles[i];
string input_perf_data = GetTestInputFilePath(test_file);
LOG(INFO) << "Testing " << input_perf_data;
string output_perf_data = output_path + test_file + ".pr.out";
PerfReader pr;
ASSERT_TRUE(pr.ReadFile(input_perf_data));
ASSERT_TRUE(pr.WriteFile(output_perf_data));
EXPECT_TRUE(CheckPerfDataAgainstBaseline(input_perf_data));
EXPECT_TRUE(CheckPerfDataAgainstBaseline(output_perf_data));
CheckFilenameAndBuildIDMethods(input_perf_data, output_path + test_file,
i, &pr);
}
}
TEST(PerfReaderTest, CorruptedFiles) {
for (unsigned int i = 0;
i < arraysize(perf_test_files::kCorruptedPerfPipedDataFiles);
++i) {
const char* test_file = perf_test_files::kCorruptedPerfPipedDataFiles[i];
string input_perf_data = GetTestInputFilePath(test_file);
LOG(INFO) << "Testing " << input_perf_data;
ASSERT_TRUE(FileExists(input_perf_data)) << "Test file does not exist!";
PerfReader pr;
ASSERT_FALSE(pr.ReadFile(input_perf_data));
}
}
TEST(PerfReaderTest, PerfizeBuildID) {
string test = "f";
PerfReader::PerfizeBuildIDString(&test);
EXPECT_EQ("f000000000000000000000000000000000000000", test);
PerfReader::PerfizeBuildIDString(&test);
EXPECT_EQ("f000000000000000000000000000000000000000", test);
test = "01234567890123456789012345678901234567890";
PerfReader::PerfizeBuildIDString(&test);
EXPECT_EQ("0123456789012345678901234567890123456789", test);
PerfReader::PerfizeBuildIDString(&test);
EXPECT_EQ("0123456789012345678901234567890123456789", test);
}
TEST(PerfReaderTest, UnperfizeBuildID) {
string test = "f000000000000000000000000000000000000000";
PerfReader::UnperfizeBuildIDString(&test);
EXPECT_EQ("f0000000", test);
PerfReader::UnperfizeBuildIDString(&test);
EXPECT_EQ("f0000000", test);
test = "0123456789012345678901234567890123456789";
PerfReader::UnperfizeBuildIDString(&test);
EXPECT_EQ("0123456789012345678901234567890123456789", test);
test = "0000000000000000000000000000000000000000";
PerfReader::UnperfizeBuildIDString(&test);
EXPECT_EQ("00000000", test);
PerfReader::UnperfizeBuildIDString(&test);
EXPECT_EQ("00000000", test);
test = "0000000000000000000000000000001000000000";
PerfReader::UnperfizeBuildIDString(&test);
EXPECT_EQ("00000000000000000000000000000010", test);
PerfReader::UnperfizeBuildIDString(&test);
EXPECT_EQ("00000000000000000000000000000010", test);
}
} // namespace quipper
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}