From 8a992e96d615eb710ae781b47e0e68ca739bb4ac Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Thu, 22 Mar 2018 19:48:48 -0700 Subject: Perfprofd: Add GZIP compression Add support for output compression with libz. (cherry picked from commit 894b3f9b0d3ed1a082d8c533ac812341c047561c) Bug: 73175642 Test: mmma system/extras/perfprofd Test: perfprofd_test Merged-In: I4e38040fa197fd67c4e844199e980520887e6258 Change-Id: I4e38040fa197fd67c4e844199e980520887e6258 --- perfprofd/binder_interface/perfprofd_binder.cc | 13 +- perfprofd/config.h | 3 + perfprofd/configreader.cc | 4 + perfprofd/perfprofd_io.cc | 241 ++++++++++++++++- perfprofd/perfprofd_io.h | 6 +- perfprofd/perfprofdcore.cc | 6 +- perfprofd/tests/Android.bp | 1 + perfprofd/tests/perfprofd_test.cc | 354 ++++++++++++++++--------- 8 files changed, 489 insertions(+), 139 deletions(-) diff --git a/perfprofd/binder_interface/perfprofd_binder.cc b/perfprofd/binder_interface/perfprofd_binder.cc index d04e185c..184d38c1 100644 --- a/perfprofd/binder_interface/perfprofd_binder.cc +++ b/perfprofd/binder_interface/perfprofd_binder.cc @@ -184,13 +184,18 @@ static Status WriteDropboxFile(android::perfprofd::PerfprofdRecord* encodedProfi } } - if (!SerializeProtobuf(encodedProfile, std::move(tmp_fd))) { + constexpr bool kCompress = true; // Ignore the config here. Dropbox will always end up + // compressing the data, might as well make the temp + // file smaller and help it out. + using DropBoxManager = android::os::DropBoxManager; + constexpr int kDropboxFlags = DropBoxManager::IS_GZIPPED; + + if (!SerializeProtobuf(encodedProfile, std::move(tmp_fd), kCompress)) { return Status::fromExceptionCode(1, "Could not serialize to temp file"); } - using DropBoxManager = android::os::DropBoxManager; sp dropbox(new DropBoxManager()); - return dropbox->addFile(String16("perfprofd"), read_only.release(), 0); + return dropbox->addFile(String16("perfprofd"), read_only.release(), kDropboxFlags); } bool PerfProfdNativeService::BinderHandler( @@ -227,7 +232,7 @@ bool PerfProfdNativeService::BinderHandler( std::string data_file_path(config->destination_directory); data_file_path += "/perf.data"; std::string path = android::base::StringPrintf("%s.encoded.%d", data_file_path.c_str(), seq_); - if (!SerializeProtobuf(encodedProfile, path.c_str())) { + if (!SerializeProtobuf(encodedProfile, path.c_str(), config->compress)) { return false; } diff --git a/perfprofd/config.h b/perfprofd/config.h index bbbcb3fc..4c1f12b1 100644 --- a/perfprofd/config.h +++ b/perfprofd/config.h @@ -93,6 +93,9 @@ struct Config { // If true, use an ELF symbolizer to on-device symbolize. bool use_elf_symbolizer = true; + // If true, use libz to compress the output proto. + bool compress = true; + // Sleep for the given number of seconds. virtual void Sleep(size_t seconds) = 0; diff --git a/perfprofd/configreader.cc b/perfprofd/configreader.cc index f8fb3d6d..f7d6fd29 100644 --- a/perfprofd/configreader.cc +++ b/perfprofd/configreader.cc @@ -127,6 +127,9 @@ void ConfigReader::addDefaultEntries() // If true, use an ELF symbolizer to on-device symbolize. addUnsignedEntry("use_elf_symbolizer", 1, 0, 1); + + // If true, use libz to compress the output proto. + addUnsignedEntry("compress", 0, 0, 1); } void ConfigReader::addUnsignedEntry(const char *key, @@ -325,4 +328,5 @@ void ConfigReader::FillConfig(Config* config) { config->process = -1; config->use_elf_symbolizer = getBoolValue("use_elf_symbolizer"); + config->compress = getBoolValue("compress"); } diff --git a/perfprofd/perfprofd_io.cc b/perfprofd/perfprofd_io.cc index 0b0bd6d7..d88cae4a 100644 --- a/perfprofd/perfprofd_io.cc +++ b/perfprofd/perfprofd_io.cc @@ -20,15 +20,21 @@ #include #include +#include + #include #include +#include +#include #include +#include #include "perfprofd_record.pb.h" namespace android { namespace perfprofd { +using android::base::StringPrintf; using android::base::unique_fd; using android::base::WriteFully; @@ -47,24 +53,249 @@ class FileCopyingOutputStream : public ::google::protobuf::io::CopyingOutputStre android::base::unique_fd fd_; }; +using google::protobuf::io::ZeroCopyOutputStream; + +// Protobuf's Gzip implementation is not available in protobuf-lite. :-( +class GzipOutputStream : public ZeroCopyOutputStream { + public: + ~GzipOutputStream(); + + static std::unique_ptr Create(ZeroCopyOutputStream* next, + std::string* error_msg); + + bool Next(void** data, int* size) override; + + void BackUp(int count) override; + + google::protobuf::int64 ByteCount() const override; + + bool WriteAliasedRaw(const void* data, int size) override; + bool AllowsAliasing() const override; + + bool Flush(); + bool Close(); + + private: + GzipOutputStream(ZeroCopyOutputStream* next, z_stream* stream); + + int Write(int flush_flags); + bool NextBuffer(); + + ZeroCopyOutputStream* next_; + void* next_data_; + int next_size_; + + z_stream* stream_; + std::unique_ptr stream_buffer_; + bool had_error_; +}; + +constexpr size_t kStreamBufferSize = 16u * 1024u; + +GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* next, z_stream* stream) + : next_(next), + next_data_(nullptr), + next_size_(0), + stream_(stream), + stream_buffer_(nullptr), + had_error_(false) { +} + +GzipOutputStream::~GzipOutputStream() { + if (stream_ != nullptr) { + deflateEnd(stream_); + delete stream_; + stream_ = nullptr; + } +} + +bool GzipOutputStream::WriteAliasedRaw(const void* data ATTRIBUTE_UNUSED, + int size ATTRIBUTE_UNUSED) { + LOG(FATAL) << "Not supported"; + __builtin_unreachable(); +} +bool GzipOutputStream::AllowsAliasing() const { + return false; +} + +google::protobuf::int64 GzipOutputStream::ByteCount() const { + return stream_->total_in + stream_->avail_in; +} + +std::unique_ptr GzipOutputStream::Create(ZeroCopyOutputStream* next, + std::string* error_msg) { + std::unique_ptr stream(new z_stream); + + stream->zalloc = Z_NULL; + stream->zfree = Z_NULL; + stream->opaque = Z_NULL; + stream->msg = nullptr; + stream->avail_in = 0; + stream->total_in = 0; + stream->next_in = nullptr; + stream->total_out = 0; + + { + constexpr int kWindowBits = 15; + constexpr int kGzipEncoding = 16; + constexpr int kMemLevel = 8; // Default. + int init_result = deflateInit2(stream.get(), + Z_DEFAULT_COMPRESSION, + Z_DEFLATED, + kWindowBits | kGzipEncoding, + kMemLevel, + Z_DEFAULT_STRATEGY); + if (init_result != Z_OK) { + *error_msg = StringPrintf("Could not initialize compression: %d (%s)", + init_result, + stream->msg != nullptr ? stream->msg : "no message"); + return nullptr; + } + } + + return std::unique_ptr(new GzipOutputStream(next, stream.release())); +} + +bool GzipOutputStream::NextBuffer() { + for (;;) { + if (!next_->Next(&next_data_, &next_size_)) { + next_data_ = nullptr; + next_size_ = 0; + return false; + } + if (next_size_ == 0) { + continue; + } + stream_->next_out = static_cast(next_data_); + stream_->avail_out = next_size_; + return true; + } +} + +int GzipOutputStream::Write(int flush_flags) { + CHECK(flush_flags == Z_NO_FLUSH || flush_flags == Z_FULL_FLUSH || flush_flags == Z_FINISH); + + int res; + do { + if ((next_data_ == nullptr || stream_->avail_out == 0) && !NextBuffer()) { + return Z_BUF_ERROR; + } + res = deflate(stream_, flush_flags); + } while (res == Z_OK && stream_->avail_out == 0); + + if (flush_flags == Z_FULL_FLUSH || flush_flags == Z_FINISH) { + next_->BackUp(stream_->avail_out); + next_data_ = nullptr; + next_size_ = 0; + } + + return res; +} + +bool GzipOutputStream::Next(void** data, int* size) { + if (had_error_) { + return false; + } + + // Write all pending data. + if (stream_->avail_in > 0) { + int write_error = Write(Z_NO_FLUSH); + if (write_error != Z_OK) { + had_error_ = true; + return false; + } + CHECK_EQ(stream_->avail_in, 0); + } + + if (stream_buffer_ == nullptr) { + stream_buffer_.reset(new uint8_t[kStreamBufferSize]); + } + + stream_->next_in = static_cast(stream_buffer_.get()); + stream_->avail_in = kStreamBufferSize; + *data = stream_buffer_.get(); + *size = kStreamBufferSize; + return true; +} + +void GzipOutputStream::BackUp(int count) { + CHECK_GE(stream_->avail_in, count); + stream_->avail_in -= count; +} + +bool GzipOutputStream::Flush() { + if (had_error_) { + return false; + } + + int res = Write(Z_FULL_FLUSH); + had_error_ |= (res != Z_OK) + && !(res == Z_BUF_ERROR && stream_->avail_in == 0 && stream_->avail_out > 0); + return !had_error_; +} + +bool GzipOutputStream::Close() { + if (had_error_) { + return false; + } + + { + int res; + do { + res = Write(Z_FINISH); + } while (res == Z_OK); + } + + int res = deflateEnd(stream_); + delete stream_; + stream_ = nullptr; + + had_error_ = true; // Pretend an error so no other operations succeed. + + return res == Z_OK; +} + } // namespace bool SerializeProtobuf(android::perfprofd::PerfprofdRecord* encodedProfile, - android::base::unique_fd&& fd) { + android::base::unique_fd&& fd, + bool compress) { FileCopyingOutputStream fcos(std::move(fd)); google::protobuf::io::CopyingOutputStreamAdaptor cosa(&fcos); - bool serialized = encodedProfile->SerializeToZeroCopyStream(&cosa); + ZeroCopyOutputStream* out; + + std::unique_ptr gzip; + if (compress) { + std::string error_msg; + gzip = GzipOutputStream::Create(&cosa, &error_msg); + if (gzip == nullptr) { + LOG(ERROR) << error_msg; + return false; + } + out = gzip.get(); + } else { + out = &cosa; + } + + bool serialized = encodedProfile->SerializeToZeroCopyStream(out); if (!serialized) { LOG(WARNING) << "SerializeToZeroCopyStream failed"; return false; } + bool zip_ok = true; + if (gzip != nullptr) { + zip_ok = gzip->Flush(); + zip_ok = gzip->Close() && zip_ok; + } cosa.Flush(); - return true; + return zip_ok; } -bool SerializeProtobuf(PerfprofdRecord* encodedProfile, const char* encoded_file_path) { +bool SerializeProtobuf(PerfprofdRecord* encodedProfile, + const char* encoded_file_path, + bool compress) { unlink(encoded_file_path); // Attempt to unlink for a clean slate. constexpr int kFlags = O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC; unique_fd fd(open(encoded_file_path, kFlags, 0664)); @@ -72,7 +303,7 @@ bool SerializeProtobuf(PerfprofdRecord* encodedProfile, const char* encoded_file PLOG(WARNING) << "Could not open " << encoded_file_path << " for serialization"; return false; } - return SerializeProtobuf(encodedProfile, std::move(fd)); + return SerializeProtobuf(encodedProfile, std::move(fd), compress); } } // namespace perfprofd diff --git a/perfprofd/perfprofd_io.h b/perfprofd/perfprofd_io.h index a102cd8d..3e754b54 100644 --- a/perfprofd/perfprofd_io.h +++ b/perfprofd/perfprofd_io.h @@ -26,9 +26,11 @@ namespace android { namespace perfprofd { bool SerializeProtobuf(android::perfprofd::PerfprofdRecord* encodedProfile, - const char* encoded_file_path); + const char* encoded_file_path, + bool compress = true); bool SerializeProtobuf(android::perfprofd::PerfprofdRecord* encodedProfile, - android::base::unique_fd&& fd); + android::base::unique_fd&& fd, + bool compress = true); } // namespace perfprofd } // namespace android diff --git a/perfprofd/perfprofdcore.cc b/perfprofd/perfprofdcore.cc index bb9dc998..4fa666d3 100644 --- a/perfprofd/perfprofdcore.cc +++ b/perfprofd/perfprofdcore.cc @@ -516,7 +516,9 @@ PROFILE_RESULT encode_to_proto(const std::string &data_file_path, return ERR_PERF_ENCODE_FAILED; } - return android::perfprofd::SerializeProtobuf(encodedProfile.get(), encoded_file_path) + return android::perfprofd::SerializeProtobuf(encodedProfile.get(), + encoded_file_path, + config.compress) ? OK_PROFILE_COLLECTION : ERR_WRITE_ENCODED_FILE_FAILED; } @@ -1009,7 +1011,7 @@ int perfprofd_main(int argc, char** argv, Config* config) data_file_path += "/"; data_file_path += PERF_OUTPUT; std::string path = android::base::StringPrintf("%s.encoded.%d", data_file_path.c_str(), seq); - if (!android::perfprofd::SerializeProtobuf(proto, path.c_str())) { + if (!android::perfprofd::SerializeProtobuf(proto, path.c_str(), handler_config->compress)) { return false; } diff --git a/perfprofd/tests/Android.bp b/perfprofd/tests/Android.bp index 870592e8..c245ff6c 100644 --- a/perfprofd/tests/Android.bp +++ b/perfprofd/tests/Android.bp @@ -36,6 +36,7 @@ cc_test { "libsimpleperf_elf_read", "libbase", "libutils", + "libz", ], shared_libs: [ "libprotobuf-cpp-lite", diff --git a/perfprofd/tests/perfprofd_test.cc b/perfprofd/tests/perfprofd_test.cc index 3568933d..73ee638f 100644 --- a/perfprofd/tests/perfprofd_test.cc +++ b/perfprofd/tests/perfprofd_test.cc @@ -37,6 +37,7 @@ #include #include #include +#include #include "config.h" #include "configreader.h" @@ -362,7 +363,7 @@ static std::string encoded_file_path(const std::string& dest_dir, } static void readEncodedProfile(const std::string& dest_dir, - const char *testpoint, + bool compressed, android::perfprofd::PerfprofdRecord& encodedProfile) { struct stat statb; @@ -378,6 +379,54 @@ static void readEncodedProfile(const std::string& dest_dir, ASSERT_EQ(1, items_read); fclose(ifp); + // uncompress + if (compressed && !encoded.empty()) { + z_stream stream; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + + { + constexpr int kWindowBits = 15; + constexpr int kGzipEncoding = 16; + int init_result = inflateInit2(&stream, kWindowBits | kGzipEncoding); + if (init_result != Z_OK) { + LOG(ERROR) << "Could not initialize libz stream " << init_result; + return; + } + } + + std::string buf; + buf.reserve(2 * encoded.size()); + stream.avail_in = encoded.size(); + stream.next_in = reinterpret_cast(const_cast(encoded.data())); + + int result; + do { + uint8_t chunk[1024]; + stream.next_out = static_cast(chunk); + stream.avail_out = arraysize(chunk); + + result = inflate(&stream, 0); + const size_t amount = arraysize(chunk) - stream.avail_out; + if (amount > 0) { + if (buf.capacity() - buf.size() < amount) { + buf.reserve(buf.capacity() + 64u * 1024u); + CHECK_LE(amount, buf.capacity() - buf.size()); + } + size_t index = buf.size(); + buf.resize(buf.size() + amount); + memcpy(reinterpret_cast(const_cast(buf.data())) + index, chunk, amount); + } + } while (result == Z_OK); + inflateEnd(&stream); + if (result != Z_STREAM_END) { + LOG(ERROR) << "Finished with not-Z_STREAM_END " << result; + return; + } + encoded = buf; + } + // decode encodedProfile.ParseFromString(encoded); } @@ -658,7 +707,125 @@ std::string FormatSampleEvent(const quipper::PerfDataProto_SampleEvent& sample) } -TEST_F(PerfProfdTest, BasicRunWithCannedPerf) +struct BasicRunWithCannedPerf : PerfProfdTest { + void VerifyBasicCannedProfile(const android::perfprofd::PerfprofdRecord& encodedProfile) { + ASSERT_TRUE(encodedProfile.has_perf_data()) << test_logger.JoinTestLog(" "); + const quipper::PerfDataProto& perf_data = encodedProfile.perf_data(); + + // Expect 21108 events. + EXPECT_EQ(21108, perf_data.events_size()) << CreateStats(perf_data); + + EXPECT_EQ(48, CountMmapEvents(perf_data)) << CreateStats(perf_data); + EXPECT_EQ(19986, CountSampleEvents(perf_data)) << CreateStats(perf_data); + EXPECT_EQ(1033, CountCommEvents(perf_data)) << CreateStats(perf_data); + EXPECT_EQ(15, CountForkEvents(perf_data)) << CreateStats(perf_data); + EXPECT_EQ(26, CountExitEvents(perf_data)) << CreateStats(perf_data); + + if (HasNonfatalFailure()) { + FAIL(); + } + + { + MmapEventIterator mmap(perf_data); + constexpr std::pair kMmapEvents[] = { + std::make_pair("[kernel.kallsyms]_text", 0), + std::make_pair("/system/lib/libc.so", 3067412480u), + std::make_pair("/system/vendor/lib/libdsutils.so", 3069911040u), + std::make_pair("/system/lib/libc.so", 3067191296u), + std::make_pair("/system/lib/libc++.so", 3069210624u), + std::make_pair("/data/dalvik-cache/arm/system@framework@boot.oat", 1900048384u), + std::make_pair("/system/lib/libjavacore.so", 2957135872u), + std::make_pair("/system/vendor/lib/libqmi_encdec.so", 3006644224u), + std::make_pair("/data/dalvik-cache/arm/system@framework@wifi-service.jar@classes.dex", + 3010351104u), + std::make_pair("/system/lib/libart.so", 3024150528u), + std::make_pair("/system/lib/libz.so", 3056410624u), + std::make_pair("/system/lib/libicui18n.so", 3057610752u), + }; + for (auto& pair : kMmapEvents) { + EXPECT_STREQ(pair.first, mmap->mmap_event().filename().c_str()); + EXPECT_EQ(pair.second, mmap->mmap_event().start()) << pair.first; + ++mmap; + } + } + + { + CommEventIterator comm(perf_data); + constexpr const char* kCommEvents[] = { + "init", "kthreadd", "ksoftirqd/0", "kworker/u:0H", "migration/0", "khelper", + "netns", "modem_notifier", "smd_channel_clo", "smsm_cb_wq", "rpm-smd", "kworker/u:1H", + }; + for (auto str : kCommEvents) { + EXPECT_STREQ(str, comm->comm_event().comm().c_str()); + ++comm; + } + } + + { + SampleEventIterator samples(perf_data); + constexpr const char* kSampleEvents[] = { + "pid=0 tid=0 ip=3222720196", + "pid=0 tid=0 ip=3222910876", + "pid=0 tid=0 ip=3222910876", + "pid=0 tid=0 ip=3222910876", + "pid=0 tid=0 ip=3222910876", + "pid=0 tid=0 ip=3222910876", + "pid=0 tid=0 ip=3222910876", + "pid=3 tid=3 ip=3231975108", + "pid=5926 tid=5926 ip=3231964952", + "pid=5926 tid=5926 ip=3225342428", + "pid=5926 tid=5926 ip=3223841448", + "pid=5926 tid=5926 ip=3069807920", + }; + for (auto str : kSampleEvents) { + EXPECT_STREQ(str, FormatSampleEvent(samples->sample_event()).c_str()); + ++samples; + } + + // Skip some samples. + for (size_t i = 0; i != 5000; ++i) { + ++samples; + } + constexpr const char* kSampleEvents2[] = { + "pid=5938 tid=5938 ip=3069630992", + "pid=5938 tid=5938 ip=3069626616", + "pid=5938 tid=5938 ip=3069626636", + "pid=5938 tid=5938 ip=3069637212", + "pid=5938 tid=5938 ip=3069637208", + "pid=5938 tid=5938 ip=3069637252", + "pid=5938 tid=5938 ip=3069346040", + "pid=5938 tid=5938 ip=3069637128", + "pid=5938 tid=5938 ip=3069626616", + }; + for (auto str : kSampleEvents2) { + EXPECT_STREQ(str, FormatSampleEvent(samples->sample_event()).c_str()); + ++samples; + } + + // Skip some samples. + for (size_t i = 0; i != 5000; ++i) { + ++samples; + } + constexpr const char* kSampleEvents3[] = { + "pid=5938 tid=5938 ip=3069912036", + "pid=5938 tid=5938 ip=3069637260", + "pid=5938 tid=5938 ip=3069631024", + "pid=5938 tid=5938 ip=3069346064", + "pid=5938 tid=5938 ip=3069637356", + "pid=5938 tid=5938 ip=3069637144", + "pid=5938 tid=5938 ip=3069912036", + "pid=5938 tid=5938 ip=3069912036", + "pid=5938 tid=5938 ip=3069631244", + }; + for (auto str : kSampleEvents3) { + EXPECT_STREQ(str, FormatSampleEvent(samples->sample_event()).c_str()); + ++samples; + } + } + } +}; + +TEST_F(BasicRunWithCannedPerf, Basic) { // // Verify the portion of the daemon that reads and encodes @@ -674,6 +841,10 @@ TEST_F(PerfProfdTest, BasicRunWithCannedPerf) config_reader.overrideUnsignedEntry("collect_cpu_utilization", 0); config_reader.overrideUnsignedEntry("collect_charging_state", 0); config_reader.overrideUnsignedEntry("collect_camera_active", 0); + + // Disable compression. + config_reader.overrideUnsignedEntry("compress", 0); + PerfProfdRunner::LoggingConfig config; config_reader.FillConfig(&config); @@ -684,126 +855,47 @@ TEST_F(PerfProfdTest, BasicRunWithCannedPerf) // Read and decode the resulting perf.data.encoded file android::perfprofd::PerfprofdRecord encodedProfile; - readEncodedProfile(dest_dir, - "BasicRunWithCannedPerf", - encodedProfile); + readEncodedProfile(dest_dir, false, encodedProfile); - ASSERT_TRUE(encodedProfile.has_perf_data()); - const quipper::PerfDataProto& perf_data = encodedProfile.perf_data(); - - // Expect 21108 events. - EXPECT_EQ(21108, perf_data.events_size()) << CreateStats(perf_data); + VerifyBasicCannedProfile(encodedProfile); +} - EXPECT_EQ(48, CountMmapEvents(perf_data)) << CreateStats(perf_data); - EXPECT_EQ(19986, CountSampleEvents(perf_data)) << CreateStats(perf_data); - EXPECT_EQ(1033, CountCommEvents(perf_data)) << CreateStats(perf_data); - EXPECT_EQ(15, CountForkEvents(perf_data)) << CreateStats(perf_data); - EXPECT_EQ(26, CountExitEvents(perf_data)) << CreateStats(perf_data); +TEST_F(BasicRunWithCannedPerf, Compressed) +{ + // + // Verify the portion of the daemon that reads and encodes + // perf.data files. Here we run the encoder on a canned perf.data + // file and verify that the resulting protobuf contains what + // we think it should contain. + // + std::string input_perf_data(test_dir); + input_perf_data += "/canned.perf.data"; - if (HasNonfatalFailure()) { - FAIL(); - } + // Set up config to avoid these annotations (they are tested elsewhere) + ConfigReader config_reader; + config_reader.overrideUnsignedEntry("collect_cpu_utilization", 0); + config_reader.overrideUnsignedEntry("collect_charging_state", 0); + config_reader.overrideUnsignedEntry("collect_camera_active", 0); - { - MmapEventIterator mmap(perf_data); - constexpr std::pair kMmapEvents[] = { - std::make_pair("[kernel.kallsyms]_text", 0), - std::make_pair("/system/lib/libc.so", 3067412480u), - std::make_pair("/system/vendor/lib/libdsutils.so", 3069911040u), - std::make_pair("/system/lib/libc.so", 3067191296u), - std::make_pair("/system/lib/libc++.so", 3069210624u), - std::make_pair("/data/dalvik-cache/arm/system@framework@boot.oat", 1900048384u), - std::make_pair("/system/lib/libjavacore.so", 2957135872u), - std::make_pair("/system/vendor/lib/libqmi_encdec.so", 3006644224u), - std::make_pair("/data/dalvik-cache/arm/system@framework@wifi-service.jar@classes.dex", - 3010351104u), - std::make_pair("/system/lib/libart.so", 3024150528u), - std::make_pair("/system/lib/libz.so", 3056410624u), - std::make_pair("/system/lib/libicui18n.so", 3057610752u), - }; - for (auto& pair : kMmapEvents) { - EXPECT_STREQ(pair.first, mmap->mmap_event().filename().c_str()); - EXPECT_EQ(pair.second, mmap->mmap_event().start()) << pair.first; - ++mmap; - } - } + // Enable compression. + config_reader.overrideUnsignedEntry("compress", 1); - { - CommEventIterator comm(perf_data); - constexpr const char* kCommEvents[] = { - "init", "kthreadd", "ksoftirqd/0", "kworker/u:0H", "migration/0", "khelper", - "netns", "modem_notifier", "smd_channel_clo", "smsm_cb_wq", "rpm-smd", "kworker/u:1H", - }; - for (auto str : kCommEvents) { - EXPECT_STREQ(str, comm->comm_event().comm().c_str()); - ++comm; - } - } + PerfProfdRunner::LoggingConfig config; + config_reader.FillConfig(&config); - { - SampleEventIterator samples(perf_data); - constexpr const char* kSampleEvents[] = { - "pid=0 tid=0 ip=3222720196", - "pid=0 tid=0 ip=3222910876", - "pid=0 tid=0 ip=3222910876", - "pid=0 tid=0 ip=3222910876", - "pid=0 tid=0 ip=3222910876", - "pid=0 tid=0 ip=3222910876", - "pid=0 tid=0 ip=3222910876", - "pid=3 tid=3 ip=3231975108", - "pid=5926 tid=5926 ip=3231964952", - "pid=5926 tid=5926 ip=3225342428", - "pid=5926 tid=5926 ip=3223841448", - "pid=5926 tid=5926 ip=3069807920", - }; - for (auto str : kSampleEvents) { - EXPECT_STREQ(str, FormatSampleEvent(samples->sample_event()).c_str()); - ++samples; - } + // Kick off encoder and check return code + PROFILE_RESULT result = + encode_to_proto(input_perf_data, encoded_file_path(dest_dir, 0).c_str(), config, 0, nullptr); + ASSERT_EQ(OK_PROFILE_COLLECTION, result) << test_logger.JoinTestLog(" "); - // Skip some samples. - for (size_t i = 0; i != 5000; ++i) { - ++samples; - } - constexpr const char* kSampleEvents2[] = { - "pid=5938 tid=5938 ip=3069630992", - "pid=5938 tid=5938 ip=3069626616", - "pid=5938 tid=5938 ip=3069626636", - "pid=5938 tid=5938 ip=3069637212", - "pid=5938 tid=5938 ip=3069637208", - "pid=5938 tid=5938 ip=3069637252", - "pid=5938 tid=5938 ip=3069346040", - "pid=5938 tid=5938 ip=3069637128", - "pid=5938 tid=5938 ip=3069626616", - }; - for (auto str : kSampleEvents2) { - EXPECT_STREQ(str, FormatSampleEvent(samples->sample_event()).c_str()); - ++samples; - } + // Read and decode the resulting perf.data.encoded file + android::perfprofd::PerfprofdRecord encodedProfile; + readEncodedProfile(dest_dir, true, encodedProfile); - // Skip some samples. - for (size_t i = 0; i != 5000; ++i) { - ++samples; - } - constexpr const char* kSampleEvents3[] = { - "pid=5938 tid=5938 ip=3069912036", - "pid=5938 tid=5938 ip=3069637260", - "pid=5938 tid=5938 ip=3069631024", - "pid=5938 tid=5938 ip=3069346064", - "pid=5938 tid=5938 ip=3069637356", - "pid=5938 tid=5938 ip=3069637144", - "pid=5938 tid=5938 ip=3069912036", - "pid=5938 tid=5938 ip=3069912036", - "pid=5938 tid=5938 ip=3069631244", - }; - for (auto str : kSampleEvents3) { - EXPECT_STREQ(str, FormatSampleEvent(samples->sample_event()).c_str()); - ++samples; - } - } + VerifyBasicCannedProfile(encodedProfile); } -TEST_F(PerfProfdTest, DISABLED_BasicRunWithCannedPerfWithSymbolizer) +TEST_F(BasicRunWithCannedPerf, DISABLED_WithSymbolizer) { // // Verify the portion of the daemon that reads and encodes @@ -819,6 +911,10 @@ TEST_F(PerfProfdTest, DISABLED_BasicRunWithCannedPerfWithSymbolizer) config_reader.overrideUnsignedEntry("collect_cpu_utilization", 0); config_reader.overrideUnsignedEntry("collect_charging_state", 0); config_reader.overrideUnsignedEntry("collect_camera_active", 0); + + // Disable compression. + config_reader.overrideUnsignedEntry("compress", 0); + PerfProfdRunner::LoggingConfig config; config_reader.FillConfig(&config); @@ -839,15 +935,9 @@ TEST_F(PerfProfdTest, DISABLED_BasicRunWithCannedPerfWithSymbolizer) // Read and decode the resulting perf.data.encoded file android::perfprofd::PerfprofdRecord encodedProfile; - readEncodedProfile(dest_dir, - "BasicRunWithCannedPerf", - encodedProfile); - - ASSERT_TRUE(encodedProfile.has_perf_data()); - const quipper::PerfDataProto& perf_data = encodedProfile.perf_data(); + readEncodedProfile(dest_dir, false, encodedProfile); - // Expect 21108 events. - EXPECT_EQ(21108, perf_data.events_size()) << CreateStats(perf_data); + VerifyBasicCannedProfile(encodedProfile); // TODO: Re-add symbolization. } @@ -865,6 +955,10 @@ TEST_F(PerfProfdTest, CallchainRunWithCannedPerf) config_reader.overrideUnsignedEntry("collect_cpu_utilization", 0); config_reader.overrideUnsignedEntry("collect_charging_state", 0); config_reader.overrideUnsignedEntry("collect_camera_active", 0); + + // Disable compression. + config_reader.overrideUnsignedEntry("compress", 0); + PerfProfdRunner::LoggingConfig config; config_reader.FillConfig(&config); @@ -875,9 +969,7 @@ TEST_F(PerfProfdTest, CallchainRunWithCannedPerf) // Read and decode the resulting perf.data.encoded file android::perfprofd::PerfprofdRecord encodedProfile; - readEncodedProfile(dest_dir, - "BasicRunWithCannedPerf", - encodedProfile); + readEncodedProfile(dest_dir, false, encodedProfile); ASSERT_TRUE(encodedProfile.has_perf_data()); @@ -950,6 +1042,9 @@ TEST_F(PerfProfdTest, BasicRunWithLivePerf) // Avoid the symbolizer for spurious messages. runner.addToConfig("use_elf_symbolizer=0"); + // Disable compression. + runner.addToConfig("compress=0"); + // Create semaphore file runner.create_semaphore_file(); @@ -961,7 +1056,7 @@ TEST_F(PerfProfdTest, BasicRunWithLivePerf) // Read and decode the resulting perf.data.encoded file android::perfprofd::PerfprofdRecord encodedProfile; - readEncodedProfile(dest_dir, "BasicRunWithLivePerf", encodedProfile); + readEncodedProfile(dest_dir, false, encodedProfile); // Examine what we get back. Since it's a live profile, we can't // really do much in terms of verifying the contents. @@ -1002,6 +1097,10 @@ TEST_F(PerfProfdTest, MultipleRunWithLivePerf) runner.addToConfig("sample_duration=2"); // Avoid the symbolizer for spurious messages. runner.addToConfig("use_elf_symbolizer=0"); + + // Disable compression. + runner.addToConfig("compress=0"); + runner.write_processed_file(1, 2); // Create semaphore file @@ -1015,7 +1114,7 @@ TEST_F(PerfProfdTest, MultipleRunWithLivePerf) // Read and decode the resulting perf.data.encoded file android::perfprofd::PerfprofdRecord encodedProfile; - readEncodedProfile(dest_dir, "BasicRunWithLivePerf", encodedProfile); + readEncodedProfile(dest_dir, false, encodedProfile); // Examine what we get back. Since it's a live profile, we can't // really do much in terms of verifying the contents. @@ -1073,6 +1172,9 @@ TEST_F(PerfProfdTest, CallChainRunWithLivePerf) // Avoid the symbolizer for spurious messages. runner.addToConfig("use_elf_symbolizer=0"); + // Disable compression. + runner.addToConfig("compress=0"); + // Create semaphore file runner.create_semaphore_file(); @@ -1084,7 +1186,7 @@ TEST_F(PerfProfdTest, CallChainRunWithLivePerf) // Read and decode the resulting perf.data.encoded file android::perfprofd::PerfprofdRecord encodedProfile; - readEncodedProfile(dest_dir, "CallChainRunWithLivePerf", encodedProfile); + readEncodedProfile(dest_dir, false, encodedProfile); // Examine what we get back. Since it's a live profile, we can't // really do much in terms of verifying the contents. -- cgit v1.2.3