OSDN Git Service

simpleperf: add SIMPLE_PERF_RECORD_TRACE_DATA record type.
authorYabin Cui <yabinc@google.com>
Wed, 21 Mar 2018 21:34:29 +0000 (14:34 -0700)
committerYabin Cui <yabinc@google.com>
Wed, 21 Mar 2018 21:44:09 +0000 (14:44 -0700)
PERF_RECORD_TRACE_DATA can't have record size >= 64K. This causes
some aborts when recording tracepoint events, as in
https://github.com/android-ndk/ndk/issues/493.

So fix this by adding a custom type SIMPLE_PERF_RECORD_TRACING_DATA,
which isn't limited by 64K.

Also fix an error parsing formats of tracepoing events.

Bug: http://b/75278602
Test: run simpleperf_unit_test.
Change-Id: Ib5ebd0b6f981b00c2a256d17cdfd0e725d75a272

simpleperf/cmd_kmem.cpp
simpleperf/cmd_report.cpp
simpleperf/cmd_report_test.cpp
simpleperf/cmd_trace_sched.cpp
simpleperf/get_test_data.h
simpleperf/record.cpp
simpleperf/record.h
simpleperf/testdata/perf_with_big_trace_data.data [new file with mode: 0644]
simpleperf/tracing.cpp

index 6ae908d..5d58c39 100644 (file)
@@ -611,7 +611,8 @@ bool KmemCommand::ProcessRecord(std::unique_ptr<Record> record) {
       slab_sample_tree_builder_->ProcessSampleRecord(
           *static_cast<const SampleRecord*>(record.get()));
     }
-  } else if (record->type() == PERF_RECORD_TRACING_DATA) {
+  } else if (record->type() == PERF_RECORD_TRACING_DATA ||
+             record->type() == SIMPLE_PERF_RECORD_TRACING_DATA) {
     const auto& r = *static_cast<TracingDataRecord*>(record.get());
     ProcessTracingData(std::vector<char>(r.data, r.data + r.data_size));
   }
index 9aee30a..6a757f0 100644 (file)
@@ -882,7 +882,8 @@ bool ReportCommand::ProcessRecord(std::unique_ptr<Record> record) {
     } else {
       ProcessSampleRecordInTraceOffCpuMode(std::move(record), attr_id);
     }
-  } else if (record->type() == PERF_RECORD_TRACING_DATA) {
+  } else if (record->type() == PERF_RECORD_TRACING_DATA ||
+             record->type() == SIMPLE_PERF_RECORD_TRACING_DATA) {
     const auto& r = *static_cast<TracingDataRecord*>(record.get());
     if (!ProcessTracingData(std::vector<char>(r.data, r.data + r.data_size))) {
       return false;
index 28f226d..6ebbf31 100644 (file)
@@ -486,6 +486,11 @@ TEST_F(ReportCommandTest, report_offcpu_time) {
   ASSERT_TRUE(found);
 }
 
+TEST_F(ReportCommandTest, report_big_trace_data) {
+  Report(PERF_DATA_WITH_BIG_TRACE_DATA);
+  ASSERT_TRUE(success);
+}
+
 #if defined(__linux__)
 #include "event_selection_set.h"
 
index 7f9b00f..afef072 100644 (file)
@@ -251,7 +251,8 @@ void TraceSchedCommand::ProcessRecord(Record& record) {
       child_thread.name = parent_thread.name;
       break;
     }
-    case PERF_RECORD_TRACING_DATA: {
+    case PERF_RECORD_TRACING_DATA:
+    case SIMPLE_PERF_RECORD_TRACING_DATA: {
       const TracingDataRecord& r = *static_cast<const TracingDataRecord*>(&record);
       Tracing tracing(std::vector<char>(r.data, r.data + r.data_size));
       const EventType* event = FindEventTypeByName("sched:sched_stat_runtime");
index f9a5759..779afcd 100644 (file)
@@ -120,4 +120,7 @@ static const std::string PERF_DATA_NO_UNWIND = "perf_no_unwind.data";
 // generated by `simpleperf record -a -e sched:sched_stat_runtime`.
 static const std::string PERF_DATA_SCHED_STAT_RUNTIME = "perf_sched_stat_runtime.data";
 
+// generated by `simpleperf record -e (about 200 tracepoint events) sleep 1`.
+static const std::string PERF_DATA_WITH_BIG_TRACE_DATA = "perf_with_big_trace_data.data";
+
 #endif  // SIMPLE_PERF_GET_TEST_DATA_H_
index a03f377..5fd762c 100644 (file)
@@ -51,6 +51,7 @@ static std::string RecordTypeToString(int record_type) {
       {SIMPLE_PERF_RECORD_EVENT_ID, "event_id"},
       {SIMPLE_PERF_RECORD_CALLCHAIN, "callchain"},
       {SIMPLE_PERF_RECORD_UNWINDING_RESULT, "unwinding_result"},
+      {SIMPLE_PERF_RECORD_TRACING_DATA, "tracing_data"},
   };
 
   auto it = record_type_names.find(record_type);
@@ -990,7 +991,7 @@ TracingDataRecord::TracingDataRecord(char* p) : Record(p) {
 }
 
 TracingDataRecord::TracingDataRecord(const std::vector<char>& tracing_data) {
-  SetTypeAndMisc(PERF_RECORD_TRACING_DATA, 0);
+  SetTypeAndMisc(SIMPLE_PERF_RECORD_TRACING_DATA, 0);
   data_size = tracing_data.size();
   SetSize(header_size() + sizeof(uint32_t) + Align(tracing_data.size(), 64));
   char* new_binary = new char[size()];
@@ -1193,6 +1194,8 @@ std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, uint32
       return std::unique_ptr<Record>(new CallChainRecord(p));
     case SIMPLE_PERF_RECORD_UNWINDING_RESULT:
       return std::unique_ptr<Record>(new UnwindingResultRecord(p));
+    case SIMPLE_PERF_RECORD_TRACING_DATA:
+      return std::unique_ptr<Record>(new TracingDataRecord(p));
     default:
       return std::unique_ptr<Record>(new UnknownRecord(p));
   }
index b862e40..f9041c5 100644 (file)
@@ -50,6 +50,7 @@ enum user_record_type {
   SIMPLE_PERF_RECORD_EVENT_ID,
   SIMPLE_PERF_RECORD_CALLCHAIN,
   SIMPLE_PERF_RECORD_UNWINDING_RESULT,
+  SIMPLE_PERF_RECORD_TRACING_DATA,
 };
 
 // perf_event_header uses u16 to store record size. However, that is not
diff --git a/simpleperf/testdata/perf_with_big_trace_data.data b/simpleperf/testdata/perf_with_big_trace_data.data
new file mode 100644 (file)
index 0000000..5134ec5
Binary files /dev/null and b/simpleperf/testdata/perf_with_big_trace_data.data differ
index 966bbd0..908402b 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
@@ -295,14 +296,23 @@ static TracingField ParseTracingField(const std::string& s) {
     } else if (s[i] == ';') {
       value = s.substr(start, i - start);
       if (name == "field") {
-        size_t pos = value.find('[');
-        if (pos == std::string::npos) {
+        // Parse value with brackets like "comm[16]", or just a field name.
+        size_t left_bracket_pos = value.find('[');
+        if (left_bracket_pos == std::string::npos) {
           field.name = value;
           field.elem_count = 1;
         } else {
-          field.name = value.substr(0, pos);
-          field.elem_count =
-              static_cast<size_t>(strtoull(&value[pos + 1], nullptr, 10));
+          field.name = value.substr(0, left_bracket_pos);
+          field.elem_count = 1;
+          size_t right_bracket_pos = value.find(']', left_bracket_pos);
+          if (right_bracket_pos != std::string::npos) {
+            size_t len = right_bracket_pos - left_bracket_pos - 1;
+            size_t elem_count;
+            // Array size may not be a number, like field:u32 rates[IEEE80211_NUM_BANDS].
+            if (android::base::ParseUint(value.substr(left_bracket_pos + 1, len), &elem_count)) {
+              field.elem_count = elem_count;
+            }
+          }
         }
       } else if (name == "offset") {
         field.offset =