Merge "tp: parse sched blocked reason from proto and systrace"
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index 93c3ff8..1d6f0f0 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -96,7 +96,10 @@
       gpu_mem_total_global_desc_id_(context->storage->InternString(
           "Total GPU memory used by the entire system")),
       gpu_mem_total_proc_desc_id_(context->storage->InternString(
-          "Total GPU memory used by this process")) {
+          "Total GPU memory used by this process")),
+      sched_blocked_reason_id_(
+          context->storage->InternString("sched_blocked_reason")),
+      io_wait_id_(context->storage->InternString("io_wait")) {
   // Build the lookup table for the strings inside ftrace events (e.g. the
   // name of ftrace event fields and the names of their args).
   for (size_t i = 0; i < GetDescriptorsSize(); i++) {
@@ -469,6 +472,10 @@
         ParseCdevUpdate(ts, data);
         break;
       }
+      case FtraceEvent::kSchedBlockedReasonFieldNumber: {
+        ParseSchedBlockedReason(ts, data);
+        break;
+      }
       default:
         break;
     }
@@ -1168,5 +1175,17 @@
       timestamp, static_cast<double>(evt.target()), track);
 }
 
+void FtraceParser::ParseSchedBlockedReason(int64_t timestamp,
+                                           protozero::ConstBytes blob) {
+  protos::pbzero::SchedBlockedReasonFtraceEvent::Decoder evt(blob);
+  uint32_t pid = static_cast<uint32_t>(evt.pid());
+  auto utid = context_->process_tracker->GetOrCreateThread(pid);
+  InstantId id = context_->event_tracker->PushInstant(
+      timestamp, sched_blocked_reason_id_, utid, RefType::kRefUtid, false);
+
+  auto args_tracker = context_->args_tracker->AddArgsTo(id);
+  args_tracker.AddArg(io_wait_id_, Variadic::Boolean(evt.io_wait()));
+}
+
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.h b/src/trace_processor/importers/ftrace/ftrace_parser.h
index 4f1289b..51340df 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.h
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.h
@@ -124,6 +124,7 @@
   void ParseGpuMemTotal(int64_t timestamp, protozero::ConstBytes);
   void ParseThermalTemperature(int64_t timestamp, protozero::ConstBytes);
   void ParseCdevUpdate(int64_t timestamp, protozero::ConstBytes);
+  void ParseSchedBlockedReason(int64_t timestamp, protozero::ConstBytes);
   TraceProcessorContext* context_;
   RssStatTracker rss_stat_tracker_;
 
@@ -151,6 +152,8 @@
   const StringId gpu_mem_total_unit_id_;
   const StringId gpu_mem_total_global_desc_id_;
   const StringId gpu_mem_total_proc_desc_id_;
+  const StringId sched_blocked_reason_id_;
+  const StringId io_wait_id_;
 
   struct FtraceMessageStrings {
     // The string id of name of the event field (e.g. sched_switch's id).
diff --git a/src/trace_processor/importers/systrace/systrace_line_parser.cc b/src/trace_processor/importers/systrace/systrace_line_parser.cc
index 8654eef..5c25461 100644
--- a/src/trace_processor/importers/systrace/systrace_line_parser.cc
+++ b/src/trace_processor/importers/systrace/systrace_line_parser.cc
@@ -40,7 +40,10 @@
     : context_(ctx),
       sched_wakeup_name_id_(ctx->storage->InternString("sched_wakeup")),
       cpuidle_name_id_(ctx->storage->InternString("cpuidle")),
-      workqueue_name_id_(ctx->storage->InternString("workqueue")) {}
+      workqueue_name_id_(ctx->storage->InternString("workqueue")),
+      sched_blocked_reason_id_(
+          ctx->storage->InternString("sched_blocked_reason")),
+      io_wait_id_(ctx->storage->InternString("io_wait")) {}
 
 util::Status SystraceLineParser::ParseLine(const SystraceLine& line) {
   auto utid = context_->process_tracker->UpdateThreadName(
@@ -218,6 +221,18 @@
       return util::Status("Could not convert target");
     }
     context_->event_tracker->PushCounter(line.ts, target.value(), track);
+  } else if (line.event_name == "sched_blocked_reason") {
+    uint32_t wakee_pid = *base::StringToUInt32(args["pid"]);
+    auto wakee_utid = context_->process_tracker->GetOrCreateThread(wakee_pid);
+
+    InstantId id = context_->event_tracker->PushInstant(
+        line.ts, sched_blocked_reason_id_, wakee_utid, RefType::kRefUtid,
+        false);
+
+    auto inserter = context_->args_tracker->AddArgsTo(id);
+    bool io_wait = *base::StringToInt32(args["iowait"]);
+    inserter.AddArg(io_wait_id_, Variadic::Boolean(io_wait));
+    context_->args_tracker->Flush();
   }
 
   return util::OkStatus();
diff --git a/src/trace_processor/importers/systrace/systrace_line_parser.h b/src/trace_processor/importers/systrace/systrace_line_parser.h
index bd8adc0..9024fd4 100644
--- a/src/trace_processor/importers/systrace/systrace_line_parser.h
+++ b/src/trace_processor/importers/systrace/systrace_line_parser.h
@@ -37,6 +37,8 @@
   const StringId sched_wakeup_name_id_ = kNullStringId;
   const StringId cpuidle_name_id_ = kNullStringId;
   const StringId workqueue_name_id_ = kNullStringId;
+  const StringId sched_blocked_reason_id_ = kNullStringId;
+  const StringId io_wait_id_ = kNullStringId;
 };
 
 }  // namespace trace_processor
diff --git a/test/synth_common.py b/test/synth_common.py
index 90b4aa6..4398563 100644
--- a/test/synth_common.py
+++ b/test/synth_common.py
@@ -406,6 +406,12 @@
     gpu_mem_total_event.pid = pid
     gpu_mem_total_event.size = size
 
+  def add_sched_blocked_reason(self, ts, pid, io_wait, unblock_pid):
+    ftrace = self.__add_ftrace_event(ts, unblock_pid)
+    sched_blocked_reason = ftrace.sched_blocked_reason
+    sched_blocked_reason.pid = pid
+    sched_blocked_reason.io_wait = io_wait
+
 
 def create_trace():
   parser = argparse.ArgumentParser()
diff --git a/test/trace_processor/parsing/index b/test/trace_processor/parsing/index
index b695337..19a1d2d 100644
--- a/test/trace_processor/parsing/index
+++ b/test/trace_processor/parsing/index
@@ -138,3 +138,6 @@
 # Importing displayTimeUnit
 ../../data/display_time_unit.json slices.sql display_time_unit_slices.out
 
+# Parsing sched_blocked_reason
+sched_blocked_proto.py sched_blocked_reason.sql sched_blocked_proto_sched_blocked_reason.out
+sched_blocked_systrace.systrace sched_blocked_reason.sql sched_blocked_systrace_sched_blocked_reason.out
diff --git a/test/trace_processor/parsing/sched_blocked_proto.py b/test/trace_processor/parsing/sched_blocked_proto.py
new file mode 100644
index 0000000..a6589f8
--- /dev/null
+++ b/test/trace_processor/parsing/sched_blocked_proto.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python3
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from os import sys, path
+
+import synth_common
+
+file_member = 0
+anon_member = 1
+
+trace = synth_common.create_trace()
+trace.add_packet()
+trace.add_process(1, 0, "init")
+trace.add_process(2, 0, "init2")
+trace.add_process(3, 0, "unblocker")
+
+trace.add_ftrace_packet(0)
+trace.add_sched_blocked_reason(ts=100, pid=1, io_wait=0, unblock_pid=3)
+trace.add_sched_blocked_reason(ts=110, pid=2, io_wait=1, unblock_pid=3)
+
+sys.stdout.buffer.write(trace.trace.SerializeToString())
diff --git a/test/trace_processor/parsing/sched_blocked_proto_sched_blocked_reason.out b/test/trace_processor/parsing/sched_blocked_proto_sched_blocked_reason.out
new file mode 100644
index 0000000..910c51c
--- /dev/null
+++ b/test/trace_processor/parsing/sched_blocked_proto_sched_blocked_reason.out
@@ -0,0 +1,3 @@
+"ts","tid","io_wait"
+100,1,0
+110,2,1
diff --git a/test/trace_processor/parsing/sched_blocked_reason.sql b/test/trace_processor/parsing/sched_blocked_reason.sql
new file mode 100644
index 0000000..59e26e6
--- /dev/null
+++ b/test/trace_processor/parsing/sched_blocked_reason.sql
@@ -0,0 +1,4 @@
+select ts, tid, EXTRACT_ARG(arg_set_id, 'io_wait') as io_wait
+from instants
+join thread on instants.ref = thread.utid
+where instants.name = 'sched_blocked_reason'
\ No newline at end of file
diff --git a/test/trace_processor/parsing/sched_blocked_systrace.systrace b/test/trace_processor/parsing/sched_blocked_systrace.systrace
new file mode 100644
index 0000000..81046bf
--- /dev/null
+++ b/test/trace_processor/parsing/sched_blocked_systrace.systrace
@@ -0,0 +1,2 @@
+           <...>-3694  ( 3694) [006] d..3    20.258854: sched_blocked_reason: pid=269 iowait=0 caller=worker_thread+0x534/0x820
+          <idle>-0     (-----) [000] d.s4    21.123838: sched_blocked_reason: pid=2172 iowait=1 caller=__filemap_fdatawait_range+0x134/0x150
diff --git a/test/trace_processor/parsing/sched_blocked_systrace_sched_blocked_reason.out b/test/trace_processor/parsing/sched_blocked_systrace_sched_blocked_reason.out
new file mode 100644
index 0000000..87f718c
--- /dev/null
+++ b/test/trace_processor/parsing/sched_blocked_systrace_sched_blocked_reason.out
@@ -0,0 +1,3 @@
+"ts","tid","io_wait"
+20258854000,269,0
+21123838000,2172,1