Merge "trace_processor: add heap profiling tables"
diff --git a/src/trace_processor/proto_trace_parser.cc b/src/trace_processor/proto_trace_parser.cc
index fed87e6..50bd57f 100644
--- a/src/trace_processor/proto_trace_parser.cc
+++ b/src/trace_processor/proto_trace_parser.cc
@@ -131,24 +131,23 @@
     }
     case 'C': {
       size_t name_index = 2 + tgid_length + 1;
-      size_t name_length = 0;
+      base::Optional<size_t> name_length;
       for (size_t i = name_index; i < len; i++) {
-        if (s[i] == '|' || s[i] == '\n') {
+        if (s[i] == '|') {
           name_length = i - name_index;
           break;
         }
       }
-      out->name = base::StringView(s + name_index, name_length);
-
-      size_t value_index = name_index + name_length + 1;
-      size_t value_len = len - value_index;
-      char value_str[32];
-      if (value_len >= sizeof(value_str)) {
+      if (!name_length.has_value())
         return SystraceParseResult::kFailure;
-      }
-      memcpy(value_str, s + value_index, value_len);
-      value_str[value_len] = 0;
-      out->value = std::stod(value_str);
+      out->name = base::StringView(s + name_index, name_length.value());
+
+      size_t value_index = name_index + name_length.value() + 1;
+      size_t value_len = len - value_index;
+      if (value_len == 0)
+        return SystraceParseResult::kFailure;
+      std::string value_str(s + value_index, value_len);
+      out->value = std::stod(value_str.c_str());
       return SystraceParseResult::kSuccess;
     }
     default:
@@ -670,8 +669,10 @@
                                                 ConstBytes blob,
                                                 bool grow) {
   protos::pbzero::IonHeapGrowFtraceEvent::Decoder ion(blob.data, blob.size);
-  int64_t total_bytes = ion.total_allocated();
   int64_t change_bytes = static_cast<int64_t>(ion.len()) * (grow ? 1 : -1);
+  // The total_allocated ftrace event reports the value before the
+  // atomic_long_add / sub takes place.
+  int64_t total_bytes = ion.total_allocated() + change_bytes;
   StringId global_name_id = ion_total_unknown_id_;
   StringId change_name_id = ion_change_unknown_id_;
 
diff --git a/src/trace_processor/proto_trace_parser_unittest.cc b/src/trace_processor/proto_trace_parser_unittest.cc
index c7f4ad6..05f6dec 100644
--- a/src/trace_processor/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/proto_trace_parser_unittest.cc
@@ -979,6 +979,8 @@
             SystraceParseResult::kSuccess);
   EXPECT_EQ(result, (SystraceTracePoint{'B', 42, base::StringView("Bar"), 0}));
 
+  ASSERT_EQ(ParseSystraceTracePoint(base::StringView("C|543|foo|"), &result),
+            SystraceParseResult::kFailure);
   ASSERT_EQ(ParseSystraceTracePoint(base::StringView("C|543|foo|8"), &result),
             SystraceParseResult::kSuccess);
   EXPECT_EQ(result, (SystraceTracePoint{'C', 543, base::StringView("foo"), 8}));
diff --git a/src/trace_processor/span_join_operator_table.cc b/src/trace_processor/span_join_operator_table.cc
index 38ae073..dcb2b15 100644
--- a/src/trace_processor/span_join_operator_table.cc
+++ b/src/trace_processor/span_join_operator_table.cc
@@ -568,7 +568,7 @@
   if (defn_->IsPartitioned()) {
     while (partition_ < target_partition) {
       if (IsFullPartitionShadowSlice() &&
-          target_partition < CursorPartition()) {
+          (cursor_eof_ || target_partition < CursorPartition())) {
         partition_ = target_partition;
         return StepRet(StepRet::Code::kRow);
       }
diff --git a/test/trace_processor/index b/test/trace_processor/index
index 395b602..20d6c4b 100644
--- a/test/trace_processor/index
+++ b/test/trace_processor/index
@@ -75,6 +75,7 @@
 ../data/android_sched_and_ps.pb span_left_join_left_unpartitioned.sql span_left_join_left_unpartitioned.out
 ../data/android_sched_and_ps.pb span_left_join_left_partitioned.sql span_left_join_left_partitioned.out
 ../data/android_sched_and_ps.pb span_outer_join.sql span_outer_join.out
+../data/android_sched_and_ps.pb span_left_join_empty_right.sql span_left_join_empty_right.out
 
 # Window table
 ../data/android_sched_and_ps.pb smoke_window.sql android_sched_and_ps_smoke_window.out
diff --git a/test/trace_processor/span_left_join_empty_right.out b/test/trace_processor/span_left_join_empty_right.out
new file mode 100644
index 0000000..de527a7
--- /dev/null
+++ b/test/trace_processor/span_left_join_empty_right.out
@@ -0,0 +1,6 @@
+
+
+
+
+"ts","dur","part"
+500,500,100
diff --git a/test/trace_processor/span_left_join_empty_right.sql b/test/trace_processor/span_left_join_empty_right.sql
new file mode 100644
index 0000000..011fb5f
--- /dev/null
+++ b/test/trace_processor/span_left_join_empty_right.sql
@@ -0,0 +1,22 @@
+create table t1(
+  ts BIG INT,
+  dur BIG INT,
+  part BIG INT,
+  PRIMARY KEY (part, ts)
+) without rowid;
+
+create table t2(
+  ts BIG INT,
+  dur BIG INT,
+  part BIG INT,
+  PRIMARY KEY (part, ts)
+) without rowid;
+
+INSERT INTO t1(ts, dur, part)
+VALUES
+(500, 500, 100);
+
+create virtual table sp using span_left_join(t1 PARTITIONED part, 
+                                             t2 PARTITIONED part);
+
+select * from sp;
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index 88b5081..e6905cd 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -259,7 +259,9 @@
           cpu,
         }
       }));
+    }
 
+    for (let cpu = 0; cpu < numCpus; cpu++) {
       // Only add a cpu freq track if we have
       // cpu freq data.
       // TODO(taylori): Find a way to display cpu idle