Add StringView class and switch trace processor to use it
In the TraceProcessor most of the strings derived from
protos are not terminated. Instead of passing a pointer and
a length, just pass a StringView.
Test: perfetto_unittests --gtest_filter=StringViewTest.*
Change-Id: Ibd44f54b921fb0960e6cd06b89d625a0402757e3
diff --git a/Android.bp b/Android.bp
index 71bfd05..aae56a8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3659,6 +3659,7 @@
"src/base/string_splitter_unittest.cc",
"src/base/string_utils.cc",
"src/base/string_utils_unittest.cc",
+ "src/base/string_view_unittest.cc",
"src/base/task_runner_unittest.cc",
"src/base/temp_file.cc",
"src/base/temp_file_unittest.cc",
diff --git a/include/perfetto/base/BUILD.gn b/include/perfetto/base/BUILD.gn
index ae08e9b..ea5fa38 100644
--- a/include/perfetto/base/BUILD.gn
+++ b/include/perfetto/base/BUILD.gn
@@ -24,6 +24,7 @@
"small_set.h",
"string_splitter.h",
"string_utils.h",
+ "string_view.h",
"task_runner.h",
"temp_file.h",
"thread_checker.h",
diff --git a/include/perfetto/base/string_view.h b/include/perfetto/base/string_view.h
new file mode 100644
index 0000000..2c42e91
--- /dev/null
+++ b/include/perfetto/base/string_view.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef INCLUDE_PERFETTO_BASE_STRING_VIEW_H_
+#define INCLUDE_PERFETTO_BASE_STRING_VIEW_H_
+
+#include <string.h>
+
+#include <string>
+
+namespace perfetto {
+namespace base {
+
+// A string-like object that refers to a non-owned piece of memory.
+// Strings are internally NOT null terminated.
+class StringView {
+ public:
+ StringView() : data_(""), size_(0) {}
+ StringView(const StringView&) = default;
+ StringView& operator=(const StringView&) = default;
+ StringView(const char* data, size_t size) : data_(data), size_(size) {}
+
+ // Creates a StringView from a null-terminated C string.
+ // Deliberately not "explicit".
+ StringView(const char* cstr) : data_(cstr), size_(strlen(cstr)) {}
+
+ // This instead has to be explicit, as creating a StringView out of a
+ // std::string can be subtle.
+ explicit StringView(const std::string& str)
+ : data_(str.data()), size_(str.size()) {}
+
+ bool empty() const { return size_ == 0; }
+ size_t size() const { return size_; }
+ const char* data() const { return data_; }
+
+ std::string ToStdString() const { return std::string(data_, size_); }
+
+ uint64_t Hash() const {
+ if (size_ == 0)
+ return 0;
+ uint64_t hash = 0xcbf29ce484222325; // FNV-1a-64 offset basis.
+ for (size_t i = 0; i < size_; ++i) {
+ hash ^= static_cast<decltype(hash)>(data_[i]);
+ hash *= 1099511628211; // FNV-1a-64 prime.
+ }
+ return hash;
+ }
+
+ private:
+ const char* data_ = nullptr;
+ size_t size_ = 0;
+};
+
+inline bool operator==(const StringView& x, const StringView& y) {
+ if (x.size() != y.size())
+ return false;
+ return memcmp(x.data(), y.data(), x.size()) == 0;
+}
+
+inline bool operator!=(const StringView& x, const StringView& y) {
+ return !(x == y);
+}
+
+} // namespace base
+} // namespace perfetto
+
+namespace std {
+
+template <>
+struct hash<::perfetto::base::StringView> {
+ size_t operator()(const ::perfetto::base::StringView& sv) const {
+ return static_cast<size_t>(sv.Hash());
+ }
+};
+
+} // namespace std
+
+#endif // INCLUDE_PERFETTO_BASE_STRING_VIEW_H_
diff --git a/include/perfetto/protozero/proto_decoder.h b/include/perfetto/protozero/proto_decoder.h
index fccef59..077f4c8 100644
--- a/include/perfetto/protozero/proto_decoder.h
+++ b/include/perfetto/protozero/proto_decoder.h
@@ -21,6 +21,7 @@
#include <memory>
#include "perfetto/base/logging.h"
+#include "perfetto/base/string_view.h"
#include "perfetto/protozero/proto_utils.h"
namespace protozero {
@@ -30,6 +31,8 @@
// performance sensitive contexts.
class ProtoDecoder {
public:
+ using StringView = ::perfetto::base::StringView;
+
// The field of a protobuf message. |id| == 0 if the tag is not valid (e.g.
// because the full tag was unable to be read etc.).
struct Field {
@@ -51,10 +54,11 @@
return static_cast<uint32_t>(int_value);
}
- inline const char* as_char_ptr() const {
+ inline StringView as_string() const {
PERFETTO_DCHECK(type ==
proto_utils::FieldType::kFieldTypeLengthDelimited);
- return reinterpret_cast<const char*>(length_limited.data);
+ return StringView(reinterpret_cast<const char*>(length_limited.data),
+ length_limited.length);
}
inline const uint8_t* data() const {
diff --git a/src/base/BUILD.gn b/src/base/BUILD.gn
index e51aaa5..80f9f00 100644
--- a/src/base/BUILD.gn
+++ b/src/base/BUILD.gn
@@ -128,6 +128,7 @@
"scoped_file_unittest.cc",
"string_splitter_unittest.cc",
"string_utils_unittest.cc",
+ "string_view_unittest.cc",
"time_unittest.cc",
"weak_ptr_unittest.cc",
]
diff --git a/src/base/string_view_unittest.cc b/src/base/string_view_unittest.cc
new file mode 100644
index 0000000..b9e97b4
--- /dev/null
+++ b/src/base/string_view_unittest.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include "perfetto/base/string_view.h"
+
+#include <forward_list>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace perfetto {
+namespace base {
+namespace {
+
+TEST(StringViewTest, BasicCases) {
+ EXPECT_EQ(StringView(""), StringView(""));
+ EXPECT_EQ(StringView(""), StringView("", 0));
+ EXPECT_EQ(StringView("ab"), StringView("ab", 2));
+ EXPECT_EQ(StringView("ax", 1), StringView("ay", 1));
+ EXPECT_EQ(StringView("ax", 1), StringView("a"));
+ EXPECT_EQ(StringView("ax", 1), "a");
+ EXPECT_EQ(StringView("foo|", 3).ToStdString(), std::string("foo"));
+ EXPECT_TRUE(StringView("x") != StringView(""));
+ EXPECT_TRUE(StringView("") != StringView("y"));
+ EXPECT_TRUE(StringView("a") != StringView("b"));
+ EXPECT_EQ(StringView("").size(), 0);
+ EXPECT_NE(StringView("").data(), nullptr);
+ EXPECT_TRUE(StringView("").empty());
+ EXPECT_FALSE(StringView("x").empty());
+
+ {
+ StringView x("abc");
+ EXPECT_EQ(x.size(), 3u);
+ EXPECT_EQ(x.data()[0], 'a');
+ EXPECT_EQ(x.data()[2], 'c');
+ EXPECT_TRUE(x == "abc");
+ EXPECT_TRUE(x == StringView("abc"));
+ EXPECT_TRUE(x != StringView("abcd"));
+ }
+}
+
+TEST(StringViewTest, HashCollisions) {
+ std::unordered_map<uint64_t, StringView> hashes;
+ std::unordered_set<StringView> sv_set;
+ auto insert_sv = [&hashes, &sv_set](StringView sv) {
+ hashes.emplace(sv.Hash(), sv);
+ size_t prev_set_size = sv_set.size();
+ sv_set.insert(sv);
+ ASSERT_EQ(sv_set.size(), prev_set_size + 1);
+ };
+
+ insert_sv("");
+ EXPECT_EQ(hashes.size(), 1u);
+ size_t last_size = 1;
+ std::forward_list<std::string> strings;
+ for (uint8_t c = 0; c < 0x80; c++) {
+ char buf[500];
+ memset(buf, static_cast<char>(c), sizeof(buf));
+ for (size_t i = 1; i <= sizeof(buf); i++) {
+ strings.emplace_front(buf, i);
+ StringView sv(strings.front());
+ auto other = hashes.find(sv.Hash());
+ if (other == hashes.end()) {
+ insert_sv(sv);
+ ++last_size;
+ ASSERT_EQ(hashes.size(), last_size);
+ continue;
+ }
+ EXPECT_TRUE(false) << "H(" << sv.ToStdString() << ") = "
+ << "H(" << other->second.ToStdString() << ")";
+ }
+ }
+}
+
+} // namespace
+} // namespace base
+} // namespace perfetto
diff --git a/src/trace_processor/json_trace_parser.cc b/src/trace_processor/json_trace_parser.cc
index 66d204c..ccbb838 100644
--- a/src/trace_processor/json_trace_parser.cc
+++ b/src/trace_processor/json_trace_parser.cc
@@ -127,8 +127,8 @@
uint64_t ts = value["ts"].asLargestUInt() * 1000;
const char* cat = value["cat"].asCString();
const char* name = value["name"].asCString();
- StringId cat_id = storage->InternString(cat, strlen(cat));
- StringId name_id = storage->InternString(name, strlen(name));
+ StringId cat_id = storage->InternString(cat);
+ StringId name_id = storage->InternString(name);
UniqueTid utid = procs->UpdateThread(tid, pid);
SlicesStack& stack = threads_[utid];
@@ -171,12 +171,12 @@
case 'M': { // Metadata events (process and thread names).
if (strcmp(value["name"].asCString(), "thread_name") == 0) {
const char* thread_name = value["args"]["name"].asCString();
- procs->UpdateThreadName(tid, pid, thread_name, strlen(thread_name));
+ procs->UpdateThreadName(tid, pid, thread_name);
break;
}
if (strcmp(value["name"].asCString(), "process_name") == 0) {
const char* proc_name = value["args"]["name"].asCString();
- procs->UpdateProcess(pid, proc_name, strlen(proc_name));
+ procs->UpdateProcess(pid, proc_name);
break;
}
}
diff --git a/src/trace_processor/process_table_unittest.cc b/src/trace_processor/process_table_unittest.cc
index 1ecd984..cab6a67 100644
--- a/src/trace_processor/process_table_unittest.cc
+++ b/src/trace_processor/process_table_unittest.cc
@@ -64,8 +64,8 @@
TEST_F(ProcessTableUnittest, SelectUpidAndName) {
static const char kCommProc1[] = "process1";
static const char kCommProc2[] = "process2";
- context_.process_tracker->UpdateProcess(1, kCommProc1, 8);
- context_.process_tracker->UpdateProcess(2, kCommProc2, 8);
+ context_.process_tracker->UpdateProcess(1, kCommProc1);
+ context_.process_tracker->UpdateProcess(2, kCommProc2);
PrepareValidStatement("SELECT upid, name FROM process");
@@ -83,8 +83,8 @@
TEST_F(ProcessTableUnittest, SelectUpidAndNameWithFilter) {
static const char kCommProc1[] = "process1";
static const char kCommProc2[] = "process2";
- context_.process_tracker->UpdateProcess(1, kCommProc1, 8);
- context_.process_tracker->UpdateProcess(2, kCommProc2, 8);
+ context_.process_tracker->UpdateProcess(1, kCommProc1);
+ context_.process_tracker->UpdateProcess(2, kCommProc2);
PrepareValidStatement("SELECT upid, name FROM process where upid = 2");
@@ -98,8 +98,8 @@
TEST_F(ProcessTableUnittest, SelectUpidAndNameWithOrder) {
static const char kCommProc1[] = "process1";
static const char kCommProc2[] = "process2";
- context_.process_tracker->UpdateProcess(1, kCommProc1, 8);
- context_.process_tracker->UpdateProcess(2, kCommProc2, 8);
+ context_.process_tracker->UpdateProcess(1, kCommProc1);
+ context_.process_tracker->UpdateProcess(2, kCommProc2);
PrepareValidStatement("SELECT upid, name FROM process ORDER BY upid desc");
@@ -117,8 +117,8 @@
TEST_F(ProcessTableUnittest, SelectUpidAndNameFilterGt) {
static const char kCommProc1[] = "process1";
static const char kCommProc2[] = "process2";
- context_.process_tracker->UpdateProcess(1, kCommProc1, 8);
- context_.process_tracker->UpdateProcess(2, kCommProc2, 8);
+ context_.process_tracker->UpdateProcess(1, kCommProc1);
+ context_.process_tracker->UpdateProcess(2, kCommProc2);
PrepareValidStatement("SELECT upid, name FROM process where upid > 1");
@@ -132,8 +132,8 @@
TEST_F(ProcessTableUnittest, SelectUpidAndNameFilterName) {
static const char kCommProc1[] = "process1";
static const char kCommProc2[] = "process2";
- context_.process_tracker->UpdateProcess(1, kCommProc1, 8);
- context_.process_tracker->UpdateProcess(2, kCommProc2, 8);
+ context_.process_tracker->UpdateProcess(1, kCommProc1);
+ context_.process_tracker->UpdateProcess(2, kCommProc2);
PrepareValidStatement(
"SELECT upid, name FROM process where name = \"process2\"");
@@ -148,8 +148,8 @@
TEST_F(ProcessTableUnittest, SelectUpidAndNameFilterDifferentOr) {
static const char kCommProc1[] = "process1";
static const char kCommProc2[] = "process2";
- context_.process_tracker->UpdateProcess(1, kCommProc1, 8);
- context_.process_tracker->UpdateProcess(2, kCommProc2, 8);
+ context_.process_tracker->UpdateProcess(1, kCommProc1);
+ context_.process_tracker->UpdateProcess(2, kCommProc2);
PrepareValidStatement(
"SELECT upid, name FROM process where upid = 2 or name = \"process2\"");
@@ -164,8 +164,8 @@
TEST_F(ProcessTableUnittest, SelectUpidAndNameFilterSameOr) {
static const char kCommProc1[] = "process1";
static const char kCommProc2[] = "process2";
- context_.process_tracker->UpdateProcess(1, kCommProc1, 8);
- context_.process_tracker->UpdateProcess(2, kCommProc2, 8);
+ context_.process_tracker->UpdateProcess(1, kCommProc1);
+ context_.process_tracker->UpdateProcess(2, kCommProc2);
PrepareValidStatement(
"SELECT upid, name FROM process where upid = 1 or upid = 2");
diff --git a/src/trace_processor/process_tracker.cc b/src/trace_processor/process_tracker.cc
index ff76da7..fc10f26 100644
--- a/src/trace_processor/process_tracker.cc
+++ b/src/trace_processor/process_tracker.cc
@@ -54,11 +54,10 @@
void ProcessTracker::UpdateThreadName(uint32_t tid,
uint32_t pid,
- const char* name,
- size_t name_len) {
+ base::StringView name) {
UniqueTid utid = UpdateThread(tid, pid);
auto* thread = context_->storage->GetMutableThread(utid);
- auto name_id = context_->storage->InternString(name, name_len);
+ auto name_id = context_->storage->InternString(name);
thread->name_id = name_id;
}
@@ -103,11 +102,8 @@
return utid;
}
-UniquePid ProcessTracker::UpdateProcess(uint32_t pid,
- const char* process_name,
- size_t process_name_len) {
- auto proc_name_id =
- context_->storage->InternString(process_name, process_name_len);
+UniquePid ProcessTracker::UpdateProcess(uint32_t pid, base::StringView name) {
+ auto proc_name_id = context_->storage->InternString(name);
UniquePid upid;
TraceStorage::Process* process;
std::tie(upid, process) = GetOrCreateProcess(pid, 0 /* start_ns */);
@@ -142,9 +138,10 @@
// because of the ring buffer wrapping over).
if (process->name_id == 0) {
char process_name[64];
- int len = sprintf(process_name, "[pid:%" PRIu32 "]", pid);
+ size_t len =
+ static_cast<size_t>(sprintf(process_name, "[pid:%" PRIu32 "]", pid));
process->name_id =
- context_->storage->InternString(process_name, static_cast<size_t>(len));
+ context_->storage->InternString(base::StringView(process_name, len));
}
return std::make_tuple(upid, process);
diff --git a/src/trace_processor/process_tracker.h b/src/trace_processor/process_tracker.h
index 38ae285..5bd4d2b 100644
--- a/src/trace_processor/process_tracker.h
+++ b/src/trace_processor/process_tracker.h
@@ -19,6 +19,7 @@
#include <tuple>
+#include "perfetto/base/string_view.h"
#include "src/trace_processor/trace_processor_context.h"
#include "src/trace_processor/trace_storage.h"
@@ -59,17 +60,12 @@
virtual UniqueTid UpdateThread(uint32_t tid, uint32_t tgid);
// Sets the name of the thread identified by the tuple (tid,pid).
- void UpdateThreadName(uint32_t tid,
- uint32_t pid,
- const char* name,
- size_t name_len);
+ void UpdateThreadName(uint32_t tid, uint32_t pid, base::StringView name);
// Called when a process is seen in a process tree. Retrieves the UniquePid
// for that pid or assigns a new one.
// Virtual for testing.
- virtual UniquePid UpdateProcess(uint32_t pid,
- const char* process_name,
- size_t process_name_len);
+ virtual UniquePid UpdateProcess(uint32_t pid, base::StringView name);
// Returns the bounds of a range that includes all UniquePids that have the
// requested pid.
diff --git a/src/trace_processor/process_tracker_unittest.cc b/src/trace_processor/process_tracker_unittest.cc
index 2e0b1dd..3db0e57 100644
--- a/src/trace_processor/process_tracker_unittest.cc
+++ b/src/trace_processor/process_tracker_unittest.cc
@@ -43,22 +43,22 @@
TEST_F(ProcessTrackerTest, PushProcess) {
TraceStorage storage;
- context.process_tracker->UpdateProcess(1, "test", 4);
+ context.process_tracker->UpdateProcess(1, "test");
auto pair_it = context.process_tracker->UpidsForPid(1);
ASSERT_EQ(pair_it.first->second, 1);
}
TEST_F(ProcessTrackerTest, PushTwoProcessEntries_SamePidAndName) {
- context.process_tracker->UpdateProcess(1, "test", 4);
- context.process_tracker->UpdateProcess(1, "test", 4);
+ context.process_tracker->UpdateProcess(1, "test");
+ context.process_tracker->UpdateProcess(1, "test");
auto pair_it = context.process_tracker->UpidsForPid(1);
ASSERT_EQ(pair_it.first->second, 1);
ASSERT_EQ(++pair_it.first, pair_it.second);
}
TEST_F(ProcessTrackerTest, PushTwoProcessEntries_DifferentPid) {
- context.process_tracker->UpdateProcess(1, "test", 4);
- context.process_tracker->UpdateProcess(3, "test", 4);
+ context.process_tracker->UpdateProcess(1, "test");
+ context.process_tracker->UpdateProcess(3, "test");
auto pair_it = context.process_tracker->UpidsForPid(1);
ASSERT_EQ(pair_it.first->second, 1);
auto second_pair_it = context.process_tracker->UpidsForPid(3);
@@ -66,7 +66,7 @@
}
TEST_F(ProcessTrackerTest, AddProcessEntry_CorrectName) {
- context.process_tracker->UpdateProcess(1, "test", 4);
+ context.process_tracker->UpdateProcess(1, "test");
ASSERT_EQ(context.storage->GetString(context.storage->GetProcess(1).name_id),
"test");
}
@@ -79,14 +79,14 @@
static const char kCommProc2[] = "process2";
context.sched_tracker->PushSchedSwitch(cpu, timestamp, /*tid=*/1, prev_state,
- kCommProc1, sizeof(kCommProc1) - 1,
+ kCommProc1,
/*tid=*/4);
context.sched_tracker->PushSchedSwitch(cpu, timestamp + 1, /*tid=*/4,
prev_state, kCommProc2,
- sizeof(kCommProc2) - 1,
+
/*tid=*/1);
- context.process_tracker->UpdateProcess(2, "test", strlen("test"));
+ context.process_tracker->UpdateProcess(2, "test");
context.process_tracker->UpdateThread(4, 2);
TraceStorage::Thread thread = context.storage->GetThread(/*utid=*/1);
diff --git a/src/trace_processor/proto_trace_parser.cc b/src/trace_processor/proto_trace_parser.cc
index 96472ce..f11ccc0 100644
--- a/src/trace_processor/proto_trace_parser.cc
+++ b/src/trace_processor/proto_trace_parser.cc
@@ -19,6 +19,7 @@
#include <string>
#include "perfetto/base/logging.h"
+#include "perfetto/base/string_view.h"
#include "perfetto/base/utils.h"
#include "perfetto/protozero/proto_decoder.h"
#include "src/trace_processor/blob_reader.h"
@@ -136,24 +137,21 @@
void ProtoTraceParser::ParseProcess(const uint8_t* data, size_t length) {
ProtoDecoder decoder(data, length);
uint32_t pid = 0;
- const char* process_name = nullptr;
- size_t process_name_len = 0;
+ base::StringView process_name;
for (auto fld = decoder.ReadField(); fld.id != 0; fld = decoder.ReadField()) {
switch (fld.id) {
case protos::ProcessTree::Process::kPidFieldNumber:
pid = fld.as_uint32();
break;
case protos::ProcessTree::Process::kCmdlineFieldNumber:
- if (process_name == nullptr) {
- process_name = fld.as_char_ptr();
- process_name_len = fld.size();
- }
+ if (process_name.empty())
+ process_name = fld.as_string();
break;
default:
break;
}
}
- context_->process_tracker->UpdateProcess(pid, process_name, process_name_len);
+ context_->process_tracker->UpdateProcess(pid, process_name);
PERFETTO_DCHECK(decoder.IsEndOfBuffer());
}
@@ -214,8 +212,7 @@
uint32_t prev_pid = 0;
uint32_t prev_state = 0;
- const char* prev_comm = nullptr;
- size_t prev_comm_len = 0;
+ base::StringView prev_comm;
uint32_t next_pid = 0;
for (auto fld = decoder.ReadField(); fld.id != 0; fld = decoder.ReadField()) {
switch (fld.id) {
@@ -226,8 +223,7 @@
prev_state = fld.as_uint32();
break;
case protos::SchedSwitchFtraceEvent::kPrevCommFieldNumber:
- prev_comm = fld.as_char_ptr();
- prev_comm_len = fld.size();
+ prev_comm = fld.as_string();
break;
case protos::SchedSwitchFtraceEvent::kNextPidFieldNumber:
next_pid = fld.as_uint32();
@@ -237,7 +233,7 @@
}
}
context_->sched_tracker->PushSchedSwitch(cpu, timestamp, prev_pid, prev_state,
- prev_comm, prev_comm_len, next_pid);
+ prev_comm, next_pid);
PERFETTO_DCHECK(decoder.IsEndOfBuffer());
}
diff --git a/src/trace_processor/proto_trace_parser_unittest.cc b/src/trace_processor/proto_trace_parser_unittest.cc
index 3f33b56..cd2326a 100644
--- a/src/trace_processor/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/proto_trace_parser_unittest.cc
@@ -29,11 +29,11 @@
namespace trace_processor {
namespace {
+using ::testing::_;
using ::testing::Args;
using ::testing::ElementsAreArray;
using ::testing::Eq;
using ::testing::Pointwise;
-using ::testing::_;
class FakeStringBlobReader : public BlobReader {
public:
@@ -57,13 +57,12 @@
MockSchedTracker(TraceProcessorContext* context) : SchedTracker(context) {}
virtual ~MockSchedTracker() = default;
- MOCK_METHOD7(PushSchedSwitch,
+ MOCK_METHOD6(PushSchedSwitch,
void(uint32_t cpu,
uint64_t timestamp,
uint32_t prev_pid,
uint32_t prev_state,
- const char* prev_comm,
- size_t prev_comm_len,
+ base::StringView prev_comm,
uint32_t next_pid));
};
@@ -72,10 +71,8 @@
MockProcessTracker(TraceProcessorContext* context)
: ProcessTracker(context) {}
- MOCK_METHOD3(UpdateProcess,
- UniquePid(uint32_t pid,
- const char* process_name,
- size_t process_name_len));
+ MOCK_METHOD2(UpdateProcess,
+ UniquePid(uint32_t pid, base::StringView process_name));
MOCK_METHOD2(UpdateThread, UniqueTid(uint32_t tid, uint32_t tgid));
};
@@ -99,8 +96,8 @@
TraceProcessorContext context;
MockSchedTracker* sched = new MockSchedTracker(&context);
context.sched_tracker.reset(sched);
- EXPECT_CALL(*sched, PushSchedSwitch(10, 1000, 10, 32, _, _, 100))
- .With(Args<4, 5>(ElementsAreArray(kProcName, sizeof(kProcName) - 1)));
+ EXPECT_CALL(*sched, PushSchedSwitch(10, 1000, 10, 32,
+ base::StringView(kProcName), 100));
FakeStringBlobReader reader(trace.SerializeAsString());
ProtoTraceParser parser(&reader, &context);
@@ -136,11 +133,11 @@
TraceProcessorContext context;
MockSchedTracker* sched = new MockSchedTracker(&context);
context.sched_tracker.reset(sched);
- EXPECT_CALL(*sched, PushSchedSwitch(10, 1000, 10, 32, _, _, 100))
- .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));
+ EXPECT_CALL(*sched, PushSchedSwitch(10, 1000, 10, 32,
+ base::StringView(kProcName1), 100));
- EXPECT_CALL(*sched, PushSchedSwitch(10, 1001, 100, 32, _, _, 10))
- .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));
+ EXPECT_CALL(*sched, PushSchedSwitch(10, 1001, 100, 32,
+ base::StringView(kProcName2), 10));
FakeStringBlobReader reader(trace.SerializeAsString());
ProtoTraceParser parser(&reader, &context);
@@ -179,11 +176,11 @@
TraceProcessorContext context;
MockSchedTracker* sched = new MockSchedTracker(&context);
context.sched_tracker.reset(sched);
- EXPECT_CALL(*sched, PushSchedSwitch(10, 1000, 10, 32, _, _, 100))
- .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));
+ EXPECT_CALL(*sched, PushSchedSwitch(10, 1000, 10, 32,
+ base::StringView(kProcName1), 100));
- EXPECT_CALL(*sched, PushSchedSwitch(10, 1001, 100, 32, _, _, 10))
- .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));
+ EXPECT_CALL(*sched, PushSchedSwitch(10, 1001, 100, 32,
+ base::StringView(kProcName2), 10));
FakeStringBlobReader reader(trace.SerializeAsString());
ProtoTraceParser parser(&reader, &context);
@@ -225,16 +222,16 @@
TraceProcessorContext context;
MockSchedTracker* sched = new MockSchedTracker(&context);
context.sched_tracker.reset(sched);
- EXPECT_CALL(*sched, PushSchedSwitch(10, 1000, 10, 32, _, _, 100))
- .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));
+ EXPECT_CALL(*sched, PushSchedSwitch(10, 1000, 10, 32,
+ base::StringView(kProcName1), 100));
FakeStringBlobReader reader(trace.SerializeAsString());
ProtoTraceParser parser(&reader, &context);
parser.set_chunk_size_for_testing(chunk_size);
parser.ParseNextChunk();
- EXPECT_CALL(*sched, PushSchedSwitch(10, 1001, 100, 32, _, _, 10))
- .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));
+ EXPECT_CALL(*sched, PushSchedSwitch(10, 1001, 100, 32,
+ base::StringView(kProcName2), 10));
parser.ParseNextChunk();
}
@@ -253,8 +250,7 @@
TraceProcessorContext context;
MockProcessTracker* process_tracker = new MockProcessTracker(&context);
context.process_tracker.reset(process_tracker);
- EXPECT_CALL(*process_tracker, UpdateProcess(1, _, _))
- .With(Args<1, 2>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));
+ EXPECT_CALL(*process_tracker, UpdateProcess(1, base::StringView(kProcName1)));
FakeStringBlobReader reader(trace.SerializeAsString());
ProtoTraceParser parser(&reader, &context);
parser.ParseNextChunk();
@@ -276,8 +272,7 @@
TraceProcessorContext context;
MockProcessTracker* process_tracker = new MockProcessTracker(&context);
context.process_tracker.reset(process_tracker);
- EXPECT_CALL(*process_tracker, UpdateProcess(1, _, _))
- .With(Args<1, 2>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));
+ EXPECT_CALL(*process_tracker, UpdateProcess(1, base::StringView(kProcName1)));
FakeStringBlobReader reader(trace.SerializeAsString());
ProtoTraceParser parser(&reader, &context);
parser.ParseNextChunk();
diff --git a/src/trace_processor/sched_slice_table_unittest.cc b/src/trace_processor/sched_slice_table_unittest.cc
index 8109a5f..6237e5b 100644
--- a/src/trace_processor/sched_slice_table_unittest.cc
+++ b/src/trace_processor/sched_slice_table_unittest.cc
@@ -71,17 +71,13 @@
static const char kCommProc2[] = "process2";
uint32_t pid_2 = 4;
context_.sched_tracker->PushSchedSwitch(cpu, timestamp, pid_1, prev_state,
- kCommProc1, sizeof(kCommProc1) - 1,
- pid_2);
+ kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu, timestamp + 3, pid_2, prev_state,
- kCommProc2, sizeof(kCommProc2) - 1,
- pid_1);
+ kCommProc2, pid_1);
context_.sched_tracker->PushSchedSwitch(cpu, timestamp + 4, pid_1, prev_state,
- kCommProc1, sizeof(kCommProc1) - 1,
- pid_2);
+ kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu, timestamp + 10, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
PrepareValidStatement("SELECT dur, ts, cpu FROM sched ORDER BY dur");
@@ -114,23 +110,17 @@
static const char kCommProc2[] = "process2";
uint32_t pid_2 = 4;
context_.sched_tracker->PushSchedSwitch(cpu_3, timestamp - 2, pid_1,
- prev_state, kCommProc1,
- sizeof(kCommProc1) - 1, pid_2);
+ prev_state, kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu_3, timestamp - 1, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
context_.sched_tracker->PushSchedSwitch(cpu_1, timestamp, pid_1, prev_state,
- kCommProc1, sizeof(kCommProc1) - 1,
- pid_2);
+ kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu_2, timestamp + 3, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
context_.sched_tracker->PushSchedSwitch(cpu_1, timestamp + 4, pid_1,
- prev_state, kCommProc1,
- sizeof(kCommProc1) - 1, pid_2);
+ prev_state, kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu_2, timestamp + 10, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
PrepareValidStatement("SELECT dur, ts, cpu FROM sched ORDER BY dur desc");
@@ -162,17 +152,13 @@
static const char kCommProc2[] = "process2";
uint32_t pid_2 = 4;
context_.sched_tracker->PushSchedSwitch(cpu_1, timestamp, pid_1, prev_state,
- kCommProc1, sizeof(kCommProc1) - 1,
- pid_2);
+ kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu_2, timestamp + 3, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
context_.sched_tracker->PushSchedSwitch(cpu_1, timestamp + 4, pid_1,
- prev_state, kCommProc1,
- sizeof(kCommProc1) - 1, pid_2);
+ prev_state, kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu_2, timestamp + 10, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
PrepareValidStatement("SELECT dur, ts, cpu FROM sched WHERE cpu = 3");
@@ -194,17 +180,13 @@
static const char kCommProc2[] = "process2";
uint32_t pid_2 = 4;
context_.sched_tracker->PushSchedSwitch(cpu_2, timestamp, pid_1, prev_state,
- kCommProc1, sizeof(kCommProc1) - 1,
- pid_2);
+ kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu_1, timestamp + 3, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
context_.sched_tracker->PushSchedSwitch(cpu_2, timestamp + 4, pid_1,
- prev_state, kCommProc1,
- sizeof(kCommProc1) - 1, pid_2);
+ prev_state, kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu_1, timestamp + 10, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
PrepareValidStatement(
"SELECT dur, ts, cpu FROM sched WHERE _quantum MATCH 5 ORDER BY cpu");
@@ -240,17 +222,13 @@
static const char kCommProc2[] = "process2";
uint32_t pid_2 = 4;
context_.sched_tracker->PushSchedSwitch(cpu_1, timestamp, pid_1, prev_state,
- kCommProc1, sizeof(kCommProc1) - 1,
- pid_2);
+ kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu_2, timestamp + 3, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
context_.sched_tracker->PushSchedSwitch(cpu_1, timestamp + 4, pid_1,
- prev_state, kCommProc1,
- sizeof(kCommProc1) - 1, pid_2);
+ prev_state, kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu_2, timestamp + 10, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
PrepareValidStatement(
"SELECT dur, ts, cpu FROM sched WHERE _quantum match 5 ORDER BY dur");
@@ -286,17 +264,13 @@
static const char kCommProc2[] = "process2";
uint32_t pid_2 = 4;
context_.sched_tracker->PushSchedSwitch(cpu_1, timestamp, pid_1, prev_state,
- kCommProc1, sizeof(kCommProc1) - 1,
- pid_2);
+ kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu_2, timestamp + 3, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
context_.sched_tracker->PushSchedSwitch(cpu_1, timestamp + 4, pid_1,
- prev_state, kCommProc1,
- sizeof(kCommProc1) - 1, pid_2);
+ prev_state, kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu_2, timestamp + 10, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
PrepareValidStatement(
"SELECT SUM(dur) as sum_dur "
@@ -323,17 +297,13 @@
static const char kCommProc2[] = "process2";
uint32_t pid_2 = 4;
context_.sched_tracker->PushSchedSwitch(cpu, timestamp, pid_1, prev_state,
- kCommProc1, sizeof(kCommProc1) - 1,
- pid_2);
+ kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu, timestamp + 3, pid_2, prev_state,
- kCommProc2, sizeof(kCommProc2) - 1,
- pid_1);
+ kCommProc2, pid_1);
context_.sched_tracker->PushSchedSwitch(cpu, timestamp + 4, pid_1, prev_state,
- kCommProc1, sizeof(kCommProc1) - 1,
- pid_2);
+ kCommProc1, pid_2);
context_.sched_tracker->PushSchedSwitch(cpu, timestamp + 10, pid_2,
- prev_state, kCommProc2,
- sizeof(kCommProc2) - 1, pid_1);
+ prev_state, kCommProc2, pid_1);
PrepareValidStatement("SELECT utid FROM sched ORDER BY utid");
diff --git a/src/trace_processor/sched_tracker.cc b/src/trace_processor/sched_tracker.cc
index f52938a..ae2eefe 100644
--- a/src/trace_processor/sched_tracker.cc
+++ b/src/trace_processor/sched_tracker.cc
@@ -31,8 +31,7 @@
uint64_t timestamp,
uint32_t prev_pid,
uint32_t prev_state,
- const char* prev_comm,
- size_t prev_comm_len,
+ base::StringView prev_comm,
uint32_t next_pid) {
PERFETTO_DCHECK(cpu < base::kMaxCpus);
SchedSwitchEvent* prev = &last_sched_per_cpu_[cpu];
@@ -40,8 +39,7 @@
// slice.
if (prev->valid() && prev->next_pid != 0 /* Idle process (swapper/N) */) {
uint64_t duration = timestamp - prev->timestamp;
- StringId prev_thread_name_id =
- context_->storage->InternString(prev_comm, prev_comm_len);
+ StringId prev_thread_name_id = context_->storage->InternString(prev_comm);
UniqueTid utid = context_->process_tracker->UpdateThread(
prev->timestamp, prev->next_pid /* == prev_pid */, prev_thread_name_id);
context_->storage->AddSliceToCpu(cpu, prev->timestamp, duration, utid);
diff --git a/src/trace_processor/sched_tracker.h b/src/trace_processor/sched_tracker.h
index 3688d8e..ce059d4 100644
--- a/src/trace_processor/sched_tracker.h
+++ b/src/trace_processor/sched_tracker.h
@@ -19,6 +19,7 @@
#include <array>
+#include "perfetto/base/string_view.h"
#include "perfetto/base/utils.h"
#include "src/trace_processor/trace_storage.h"
@@ -53,8 +54,7 @@
uint64_t timestamp,
uint32_t prev_pid,
uint32_t prev_state,
- const char* prev_comm,
- size_t prev_comm_len,
+ base::StringView prev_comm,
uint32_t next_pid);
private:
diff --git a/src/trace_processor/sched_tracker_unittest.cc b/src/trace_processor/sched_tracker_unittest.cc
index 0344446..82e7406 100644
--- a/src/trace_processor/sched_tracker_unittest.cc
+++ b/src/trace_processor/sched_tracker_unittest.cc
@@ -52,13 +52,11 @@
const auto& timestamps = context.storage->SlicesForCpu(cpu).start_ns();
context.sched_tracker->PushSchedSwitch(cpu, timestamp, pid_1, prev_state,
- kCommProc1, sizeof(kCommProc1) - 1,
- pid_2);
+ kCommProc1, pid_2);
ASSERT_EQ(timestamps.size(), 0);
context.sched_tracker->PushSchedSwitch(cpu, timestamp + 1, pid_2, prev_state,
- kCommProc2, sizeof(kCommProc2) - 1,
- pid_1);
+ kCommProc2, pid_1);
ASSERT_EQ(timestamps.size(), 1ul);
ASSERT_EQ(timestamps[0], timestamp);
@@ -78,21 +76,18 @@
const auto& timestamps = context.storage->SlicesForCpu(cpu).start_ns();
context.sched_tracker->PushSchedSwitch(cpu, timestamp, /*tid=*/4, prev_state,
- kCommProc1, sizeof(kCommProc1) - 1,
+ kCommProc1,
/*tid=*/2);
ASSERT_EQ(timestamps.size(), 0);
context.sched_tracker->PushSchedSwitch(cpu, timestamp + 1, /*tid=*/2,
prev_state, kCommProc1,
- sizeof(kCommProc1) - 1,
/*tid=*/4);
context.sched_tracker->PushSchedSwitch(cpu, timestamp + 11, /*tid=*/4,
prev_state, kCommProc2,
- sizeof(kCommProc2) - 1,
/*tid=*/2);
context.sched_tracker->PushSchedSwitch(cpu, timestamp + 31, /*tid=*/4,
prev_state, kCommProc1,
- sizeof(kCommProc1) - 1,
/*tid=*/2);
ASSERT_EQ(timestamps.size(), 3ul);
diff --git a/src/trace_processor/thread_table_unittest.cc b/src/trace_processor/thread_table_unittest.cc
index 854a58f..cf4843c 100644
--- a/src/trace_processor/thread_table_unittest.cc
+++ b/src/trace_processor/thread_table_unittest.cc
@@ -72,15 +72,11 @@
static const char kThreadName2[] = "thread2";
context_.sched_tracker->PushSchedSwitch(cpu, timestamp, /*tid=*/1, prev_state,
- kThreadName1,
- sizeof(kThreadName1) - 1,
- /*tid=*/4);
+ kThreadName1, /*tid=*/4);
context_.sched_tracker->PushSchedSwitch(cpu, timestamp + 1, /*tid=*/4,
- prev_state, kThreadName2,
- sizeof(kThreadName2) - 1,
- /*tid=*/1);
+ prev_state, kThreadName2, /*tid=*/1);
- context_.process_tracker->UpdateProcess(2, "test", strlen("test"));
+ context_.process_tracker->UpdateProcess(2, "test");
context_.process_tracker->UpdateThread(4 /*tid*/, 2 /*pid*/);
PrepareValidStatement("SELECT utid, upid, tid, name FROM thread where tid=4");
@@ -102,18 +98,14 @@
context_.sched_tracker->PushSchedSwitch(cpu, timestamp, /*tid=*/1, prev_state,
kThreadName1,
- sizeof(kThreadName1) - 1,
/*tid=*/4);
context_.sched_tracker->PushSchedSwitch(cpu, timestamp + 1, /*tid=*/4,
prev_state, kThreadName2,
- sizeof(kThreadName2) - 1,
/*tid=*/1);
context_.sched_tracker->PushSchedSwitch(cpu, timestamp + 2, /*tid=*/1,
- prev_state, kThreadName1,
- sizeof(kThreadName1) - 1,
- /*tid=*/4);
+ prev_state, kThreadName1, /*tid=*/4);
- context_.process_tracker->UpdateProcess(2, "test", strlen("test"));
+ context_.process_tracker->UpdateProcess(2, "test");
context_.process_tracker->UpdateThread(4 /*tid*/, 2 /*pid*/);
context_.process_tracker->UpdateThread(1 /*tid*/, 2 /*pid*/);
PrepareValidStatement(
@@ -137,17 +129,17 @@
context_.sched_tracker->PushSchedSwitch(cpu, timestamp, /*tid=*/1, prev_state,
kThreadName1,
- sizeof(kThreadName1) - 1,
+
/*tid=*/4);
context_.sched_tracker->PushSchedSwitch(cpu, timestamp + 1, /*tid=*/4,
prev_state, kThreadName2,
- sizeof(kThreadName2) - 1,
+
/*tid=*/1);
// Also create a process for which we haven't seen any thread.
- context_.process_tracker->UpdateProcess(7, "pid7", strlen("pid7"));
+ context_.process_tracker->UpdateProcess(7, "pid7");
- context_.process_tracker->UpdateProcess(2, "pid2", strlen("pid2"));
+ context_.process_tracker->UpdateProcess(2, "pid2");
context_.process_tracker->UpdateThread(/*tid=*/4, /*pid=*/2);
PrepareValidStatement(
diff --git a/src/trace_processor/trace_storage.cc b/src/trace_processor/trace_storage.cc
index 38cb414..2c2242c 100644
--- a/src/trace_processor/trace_storage.cc
+++ b/src/trace_processor/trace_storage.cc
@@ -27,7 +27,7 @@
unique_threads_.emplace_back(0);
// Reserve string ID 0 for the empty string.
- InternString("", 0);
+ InternString("");
}
TraceStorage::~TraceStorage() {}
@@ -39,21 +39,14 @@
cpu_events_[cpu].AddSlice(start_ns, duration_ns, utid);
};
-StringId TraceStorage::InternString(const char* data, size_t length) {
- uint32_t hash = 0x811c9dc5; // FNV-1a-32 offset basis.
- for (size_t i = 0; i < length; ++i) {
- hash ^= static_cast<decltype(hash)>(data[i]);
- hash *= 16777619; // FNV-1a-32 prime.
- }
+StringId TraceStorage::InternString(base::StringView str) {
+ auto hash = str.Hash();
auto id_it = string_index_.find(hash);
if (id_it != string_index_.end()) {
- // TODO(lalitm): check if this DCHECK happens and if so, then change hash
- // to 64bit.
- PERFETTO_DCHECK(
- strncmp(string_pool_[id_it->second].c_str(), data, length) == 0);
+ PERFETTO_DCHECK(base::StringView(string_pool_[id_it->second]) == str);
return id_it->second;
}
- string_pool_.emplace_back(data, length);
+ string_pool_.emplace_back(str.ToStdString());
StringId string_id = string_pool_.size() - 1;
string_index_.emplace(hash, string_id);
return string_id;
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index b45defe..98e796f 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -25,6 +25,7 @@
#include <vector>
#include "perfetto/base/logging.h"
+#include "perfetto/base/string_view.h"
#include "perfetto/base/utils.h"
namespace perfetto {
@@ -165,7 +166,7 @@
// Return an unqiue identifier for the contents of each string.
// The string is copied internally and can be destroyed after this called.
- StringId InternString(const char* data, size_t length);
+ StringId InternString(base::StringView);
Process* GetMutableProcess(UniquePid upid) {
PERFETTO_DCHECK(upid > 0 && upid < unique_processes_.size());
@@ -215,7 +216,7 @@
private:
TraceStorage& operator=(const TraceStorage&) = default;
- using StringHash = uint32_t;
+ using StringHash = uint64_t;
// Metadata counters for events being added.
Stats stats_;