summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--perfprofd/Android.mk2
-rw-r--r--perfprofd/perfprofdcore.cc5
-rw-r--r--perfprofd/quipper/perf_internals.h9
-rw-r--r--perfprofd/quipper/perf_parser.cc16
-rw-r--r--perfprofd/quipper/perf_reader.cc54
-rw-r--r--perfprofd/quipper/perf_utils.cc4
-rw-r--r--perfprofd/tests/Android.mk13
-rw-r--r--perfprofd/tests/callchain.canned.perf.databin0 -> 256412 bytes
-rw-r--r--perfprofd/tests/perfprofd_test.cc74
9 files changed, 166 insertions, 11 deletions
diff --git a/perfprofd/Android.mk b/perfprofd/Android.mk
index 6409f834..0a07949e 100644
--- a/perfprofd/Android.mk
+++ b/perfprofd/Android.mk
@@ -73,3 +73,5 @@ include $(BUILD_EXECUTABLE)
# Clean temp vars
perfprofd_cppflags :=
proto_header_dir :=
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/perfprofd/perfprofdcore.cc b/perfprofd/perfprofdcore.cc
index 134c05c2..746ed410 100644
--- a/perfprofd/perfprofdcore.cc
+++ b/perfprofd/perfprofdcore.cc
@@ -549,7 +549,7 @@ static PROFILE_RESULT invoke_perf(const std::string &perf_path,
}
// marshall arguments
- constexpr unsigned max_args = 12;
+ constexpr unsigned max_args = 13;
const char *argv[max_args];
unsigned slot = 0;
argv[slot++] = perf_path.c_str();
@@ -571,6 +571,9 @@ static PROFILE_RESULT invoke_perf(const std::string &perf_path,
// system wide profiling
argv[slot++] = "-a";
+ // no need for kernel symbols
+ argv[slot++] = "--no-dump-kernel-symbols";
+
// sleep <duration>
argv[slot++] = "/system/bin/sleep";
std::string d_str = android::base::StringPrintf("%u", duration);
diff --git a/perfprofd/quipper/perf_internals.h b/perfprofd/quipper/perf_internals.h
index ef5a785d..6b2113e4 100644
--- a/perfprofd/quipper/perf_internals.h
+++ b/perfprofd/quipper/perf_internals.h
@@ -61,4 +61,13 @@ class PerfSampleCustodian {
typedef perf_event event_t;
+//
+// Custom / user-specific records emitted by simpleperf.
+// These need to be kept in sync with the simpleperf sources.
+//
+enum simpleperf_record_type {
+ SIMPLE_PERF_RECORD_TYPE_START = 32768,
+ SIMPLE_PERF_RECORD_KERNEL_SYMBOL,
+};
+
#endif
diff --git a/perfprofd/quipper/perf_parser.cc b/perfprofd/quipper/perf_parser.cc
index 504b4f01..0821612c 100644
--- a/perfprofd/quipper/perf_parser.cc
+++ b/perfprofd/quipper/perf_parser.cc
@@ -215,6 +215,8 @@ bool PerfParser::ProcessEvents() {
VLOG(1) << "Parsed event type: " << event.header.type
<< ". Doing nothing.";
break;
+ case SIMPLE_PERF_RECORD_KERNEL_SYMBOL:
+ break;
default:
LOG(ERROR) << "Unknown event type: " << event.header.type;
return false;
@@ -286,12 +288,14 @@ bool PerfParser::MapSampleEvent(ParsedEvent* parsed_event) {
mapping_failed = true;
}
- // Write the remapped data back to the raw event regardless of whether it was
- // entirely successfully remapped. A single failed remap should not
- // invalidate all the other remapped entries.
- if (!WritePerfSampleInfo(sample_info, parsed_event->raw_event)) {
- LOG(ERROR) << "Failed to write back remapped sample info.";
- return false;
+ if (options_.do_remap) {
+ // Write the remapped data back to the raw event regardless of
+ // whether it was entirely successfully remapped. A single failed
+ // remap should not invalidate all the other remapped entries.
+ if (!WritePerfSampleInfo(sample_info, parsed_event->raw_event)) {
+ LOG(ERROR) << "Failed to write back remapped sample info.";
+ return false;
+ }
}
return !mapping_failed;
diff --git a/perfprofd/quipper/perf_reader.cc b/perfprofd/quipper/perf_reader.cc
index 99731d45..1b397ac1 100644
--- a/perfprofd/quipper/perf_reader.cc
+++ b/perfprofd/quipper/perf_reader.cc
@@ -353,6 +353,8 @@ size_t ReadPerfSampleFromData(const perf_event_type event_type,
const uint64_t sample_fields,
const uint64_t read_format,
bool swap_bytes,
+ const perf_event_attr &attr0,
+ size_t n_attrs,
struct perf_sample* sample) {
const uint64_t* initial_array_ptr = array;
@@ -460,9 +462,34 @@ size_t ReadPerfSampleFromData(const perf_event_type event_type,
array = ReadBranchStack(array, swap_bytes, sample);
}
+ // { u64 abi,
+ // u64 regs[nr]; } && PERF_SAMPLE_REGS_USER
+ if (sample_fields & PERF_SAMPLE_REGS_USER) {
+ uint64_t abi = MaybeSwap(*array++, swap_bytes);
+ if (abi != 0) {
+ assert(n_attrs == 1);
+ uint64_t reg_mask = attr0.sample_regs_user;
+ size_t bit_nr = 0;
+ for (size_t i = 0; i < 64; ++i) {
+ if ((reg_mask >> i) & 1) {
+ bit_nr++;
+ }
+ }
+ array += bit_nr;
+ }
+ }
+
+ // { u64 size,
+ // u64 regs[nr]; } && PERF_SAMPLE_STACK_USER
+ if (sample_fields & PERF_SAMPLE_STACK_USER) {
+ uint64_t size = MaybeSwap(*array++, swap_bytes);
+ if (size != 0) {
+ array += (size / sizeof(uint64_t));
+ array += 1; // for dyn_size
+ }
+ }
+
static const u64 kUnimplementedSampleFields =
- PERF_SAMPLE_REGS_USER |
- PERF_SAMPLE_STACK_USER |
PERF_SAMPLE_WEIGHT |
PERF_SAMPLE_DATA_SRC |
PERF_SAMPLE_TRANSACTION;
@@ -616,6 +643,11 @@ size_t WritePerfSampleToData(const perf_event_type event_type,
}
}
+ //
+ // Unsupported sample types.
+ //
+ CHECK(!(sample_fields & PERF_SAMPLE_STACK_USER|PERF_SAMPLE_REGS_USER));
+
return (array - initial_array_ptr) * sizeof(uint64_t);
}
@@ -769,6 +801,7 @@ bool PerfReader::IsSupportedEventType(uint32_t type) {
case PERF_RECORD_LOST:
case PERF_RECORD_THROTTLE:
case PERF_RECORD_UNTHROTTLE:
+ case SIMPLE_PERF_RECORD_KERNEL_SYMBOL:
return true;
case PERF_RECORD_READ:
case PERF_RECORD_MAX:
@@ -788,6 +821,10 @@ bool PerfReader::ReadPerfSampleInfo(const event_t& event,
return false;
}
+ // We want to completely ignore these records
+ if (event.header.type == SIMPLE_PERF_RECORD_KERNEL_SYMBOL)
+ return true;
+
uint64_t sample_format = GetSampleFieldsForEventType(event.header.type,
sample_type_);
uint64_t offset = GetPerfSampleDataOffset(event);
@@ -797,6 +834,8 @@ bool PerfReader::ReadPerfSampleInfo(const event_t& event,
sample_format,
read_format_,
is_cross_endian_,
+ attrs_[0].attr,
+ attrs_.size(),
sample);
size_t expected_size = event.header.size - offset;
@@ -1391,7 +1430,14 @@ bool PerfReader::ReadPerfEventBlock(const event_t& event) {
if (is_cross_endian_)
ByteSwap(&size);
- if (size > sizeof(event_t)) {
+ //
+ // Special case for kernel symbol record, which may be very
+ // large -- this is safe to do since we will be skipping over
+ // the kernel symbols entirely later on.
+ //
+ if (event.header.type == SIMPLE_PERF_RECORD_KERNEL_SYMBOL)
+ size = sizeof(event_t);
+ else if (size > sizeof(event_t)) {
LOG(INFO) << "Data size: " << size << " sizeof(event_t): "
<< sizeof(event_t);
return false;
@@ -1452,6 +1498,8 @@ bool PerfReader::ReadPerfEventBlock(const event_t& event) {
ByteSwap(&event_copy->read.time_running);
ByteSwap(&event_copy->read.id);
break;
+ case SIMPLE_PERF_RECORD_KERNEL_SYMBOL:
+ break;
default:
LOG(FATAL) << "Unknown event type: " << type;
}
diff --git a/perfprofd/quipper/perf_utils.cc b/perfprofd/quipper/perf_utils.cc
index 02fa9e06..4f6fdc3d 100644
--- a/perfprofd/quipper/perf_utils.cc
+++ b/perfprofd/quipper/perf_utils.cc
@@ -105,6 +105,7 @@ uint64_t GetSampleFieldsForEventType(uint32_t event_type,
PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER;
break;
case PERF_RECORD_SAMPLE:
+ case SIMPLE_PERF_RECORD_KERNEL_SYMBOL:
break;
default:
LOG(FATAL) << "Unknown event type " << event_type;
@@ -140,6 +141,9 @@ uint64_t GetPerfSampleDataOffset(const event_t& event) {
offset = sizeof(event.mmap2) - sizeof(event.mmap2.filename) +
GetUint64AlignedStringLength(event.mmap2.filename);
break;
+ case SIMPLE_PERF_RECORD_KERNEL_SYMBOL:
+ offset = 0;
+ break;
default:
LOG(FATAL) << "Unknown/unsupported event type " << event.header.type;
break;
diff --git a/perfprofd/tests/Android.mk b/perfprofd/tests/Android.mk
index bdd82e07..45c2779e 100644
--- a/perfprofd/tests/Android.mk
+++ b/perfprofd/tests/Android.mk
@@ -17,7 +17,7 @@ LOCAL_SRC_FILES := perfprofdmockutils.cc
include $(BUILD_STATIC_LIBRARY)
#
-# Canned perf.data files needed by unit test.
+# Canned perf.data file needed by unit test.
#
include $(CLEAR_VARS)
LOCAL_MODULE := canned.perf.data
@@ -28,6 +28,17 @@ LOCAL_SRC_FILES := canned.perf.data
include $(BUILD_PREBUILT)
#
+# Second canned perf.data file needed by unit test.
+#
+include $(CLEAR_VARS)
+LOCAL_MODULE := callchain.canned.perf.data
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := DATA
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest/perfprofd_test
+LOCAL_SRC_FILES := callchain.canned.perf.data
+include $(BUILD_PREBUILT)
+
+#
# Unit test for perfprofd
#
include $(CLEAR_VARS)
diff --git a/perfprofd/tests/callchain.canned.perf.data b/perfprofd/tests/callchain.canned.perf.data
new file mode 100644
index 00000000..8d843935
--- /dev/null
+++ b/perfprofd/tests/callchain.canned.perf.data
Binary files differ
diff --git a/perfprofd/tests/perfprofd_test.cc b/perfprofd/tests/perfprofd_test.cc
index 3a32204b..36a59ca1 100644
--- a/perfprofd/tests/perfprofd_test.cc
+++ b/perfprofd/tests/perfprofd_test.cc
@@ -570,6 +570,80 @@ TEST_F(PerfProfdTest, BasicRunWithCannedPerf)
}
}
+TEST_F(PerfProfdTest, CallchainRunWithCannedPerf)
+{
+ // This test makes sure that the perf.data converter
+ // can handle call chains.
+ //
+ std::string input_perf_data(test_dir);
+ input_perf_data += "/callchain.canned.perf.data";
+
+ // Set up config to avoid these annotations (they are tested elsewhere)
+ ConfigReader config;
+ config.overrideUnsignedEntry("collect_cpu_utilization", 0);
+ config.overrideUnsignedEntry("collect_charging_state", 0);
+ config.overrideUnsignedEntry("collect_camera_active", 0);
+
+ // Kick off encoder and check return code
+ PROFILE_RESULT result =
+ encode_to_proto(input_perf_data, encoded_file_path(0).c_str(), config, 0);
+ EXPECT_EQ(OK_PROFILE_COLLECTION, result);
+
+ // Read and decode the resulting perf.data.encoded file
+ wireless_android_play_playlog::AndroidPerfProfile encodedProfile;
+ readEncodedProfile("BasicRunWithCannedPerf",
+ encodedProfile);
+
+
+ // Expect 29 load modules
+ EXPECT_EQ(4, encodedProfile.programs_size());
+
+ // Check a couple of load modules
+ { const auto &lm0 = encodedProfile.load_modules(0);
+ std::string act_lm0 = encodedLoadModuleToString(lm0);
+ std::string sqact0 = squeezeWhite(act_lm0, "actual for lm 0");
+ const std::string expected_lm0 = RAW_RESULT(
+ name: "/system/bin/dex2oat"
+ build_id: "ee12bd1a1de39422d848f249add0afc4"
+ );
+ std::string sqexp0 = squeezeWhite(expected_lm0, "expected_lm0");
+ EXPECT_STREQ(sqexp0.c_str(), sqact0.c_str());
+ }
+ { const auto &lm1 = encodedProfile.load_modules(1);
+ std::string act_lm1 = encodedLoadModuleToString(lm1);
+ std::string sqact1 = squeezeWhite(act_lm1, "actual for lm 1");
+ const std::string expected_lm1 = RAW_RESULT(
+ name: "/system/bin/linker"
+ build_id: "a36715f673a4a0aa76ef290124c516cc"
+ );
+ std::string sqexp1 = squeezeWhite(expected_lm1, "expected_lm1");
+ EXPECT_STREQ(sqexp1.c_str(), sqact1.c_str());
+ }
+
+ // Examine some of the samples now
+ { const auto &p1 = encodedProfile.programs(0);
+ const auto &lm1 = p1.modules(0);
+ std::string act_lm1 = encodedModuleSamplesToString(lm1);
+ std::string sqact1 = squeezeWhite(act_lm1, "actual for lm1");
+ const std::string expected_lm1 = RAW_RESULT(
+ load_module_id: 0
+ address_samples { address: 108460 count: 2 }
+ );
+ std::string sqexp1 = squeezeWhite(expected_lm1, "expected_lm1");
+ EXPECT_STREQ(sqexp1.c_str(), sqact1.c_str());
+ }
+ { const auto &p1 = encodedProfile.programs(1);
+ const auto &lm2 = p1.modules(2);
+ std::string act_lm2 = encodedModuleSamplesToString(lm2);
+ std::string sqact2 = squeezeWhite(act_lm2, "actual for lm2");
+ const std::string expected_lm2 = RAW_RESULT(
+ load_module_id: 3 address_samples { address: 686690 count: 1 } address_samples { address: 693516 count: 1 } address_samples { address: 693770 count: 1 } address_samples { address: 694362 count: 1 } address_samples { address: 695874 count: 1 } address_samples { address: 720318 count: 2 } address_samples { address: 1510368 count: 1 } address_samples { address: 1715444 count: 1 } address_samples { address: 2809724 count: 1 } address_samples { address: 3200568 count: 1 }
+ );
+ std::string sqexp2 = squeezeWhite(expected_lm2, "expected_lm2");
+ EXPECT_STREQ(sqexp2.c_str(), sqact2.c_str());
+ }
+}
+
TEST_F(PerfProfdTest, BasicRunWithLivePerf)
{
//