Update from https://crrev.com/318214
TBR=qsr@chromium.org
Review URL: https://codereview.chromium.org/960873002
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index 6da9132..5363db5 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -10,7 +10,8 @@
namespace base {
namespace trace_event {
-ProcessMemoryDump::ProcessMemoryDump() : has_process_totals_(false) {
+ProcessMemoryDump::ProcessMemoryDump()
+ : has_process_totals_(false), has_process_mmaps_(false) {
}
ProcessMemoryDump::~ProcessMemoryDump() {
@@ -23,6 +24,11 @@
process_totals_.AsValueInto(value);
value->EndDictionary();
}
+ if (has_process_mmaps_) {
+ value->BeginDictionary("process_mmaps");
+ process_mmaps_.AsValueInto(value);
+ value->EndDictionary();
+ }
}
} // namespace trace_event
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index f70537b..4256c4c 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -6,6 +6,7 @@
#define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
#include "base/base_export.h"
+#include "base/trace_event/process_memory_maps.h"
#include "base/trace_event/process_memory_totals.h"
namespace base {
@@ -31,10 +32,17 @@
bool has_process_totals() const { return has_process_totals_; }
void set_has_process_totals() { has_process_totals_ = true; }
+ ProcessMemoryMaps* process_mmaps() { return &process_mmaps_; }
+ bool has_process_mmaps() const { return has_process_mmaps_; }
+ void set_has_process_mmaps() { has_process_mmaps_ = true; }
+
private:
ProcessMemoryTotals process_totals_;
bool has_process_totals_;
+ ProcessMemoryMaps process_mmaps_;
+ bool has_process_mmaps_;
+
DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
};
diff --git a/base/trace_event/process_memory_maps.cc b/base/trace_event/process_memory_maps.cc
new file mode 100644
index 0000000..bf3c5a0
--- /dev/null
+++ b/base/trace_event/process_memory_maps.cc
@@ -0,0 +1,45 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_maps.h"
+
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsRead = 4;
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
+
+ProcessMemoryMaps::ProcessMemoryMaps() {
+}
+
+ProcessMemoryMaps::~ProcessMemoryMaps() {
+}
+
+void ProcessMemoryMaps::AsValueInto(TracedValue* value) const {
+ value->BeginArray("vm_regions");
+ for (const auto& region : vm_regions_) {
+ value->BeginDictionary();
+
+ value->SetDouble("start_address", region.start_address);
+ value->SetDouble("size_in_bytes", region.size_in_bytes);
+ value->SetInteger("protection_flags", region.protection_flags);
+ value->SetString("mapped_file", region.mapped_file);
+ value->SetDouble("mapped_file_offset", region.mapped_file_offset);
+
+ value->BeginDictionary("byte_stats");
+ value->SetDouble("resident", region.byte_stats_resident);
+ value->SetDouble("anonymous", region.byte_stats_anonymous);
+ value->EndDictionary();
+
+ value->EndDictionary();
+ }
+ value->EndArray();
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/process_memory_maps.h b/base/trace_event/process_memory_maps.h
new file mode 100644
index 0000000..70f6610
--- /dev/null
+++ b/base/trace_event/process_memory_maps.h
@@ -0,0 +1,54 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace trace_event {
+
+class TracedValue;
+
+// Data model for process-wide memory stats.
+class BASE_EXPORT ProcessMemoryMaps {
+ public:
+ struct VMRegion {
+ static const uint32 kProtectionFlagsRead;
+ static const uint32 kProtectionFlagsWrite;
+ static const uint32 kProtectionFlagsExec;
+
+ uint64 start_address;
+ uint64 size_in_bytes;
+ uint32 protection_flags;
+ std::string mapped_file;
+ uint64 mapped_file_offset;
+ uint64 byte_stats_resident;
+ uint64 byte_stats_anonymous;
+ };
+
+ ProcessMemoryMaps();
+ ~ProcessMemoryMaps();
+
+ void AddVMRegion(const VMRegion& region) { vm_regions_.push_back(region); }
+ const std::vector<VMRegion>& vm_regions() const { return vm_regions_; }
+
+ // Called at trace generation time to populate the TracedValue.
+ void AsValueInto(TracedValue* value) const;
+
+ private:
+ std::vector<VMRegion> vm_regions_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMaps);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
diff --git a/base/trace_event/process_memory_maps_dump_provider.cc b/base/trace_event/process_memory_maps_dump_provider.cc
new file mode 100644
index 0000000..e1cefc3
--- /dev/null
+++ b/base/trace_event/process_memory_maps_dump_provider.cc
@@ -0,0 +1,176 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_maps_dump_provider.h"
+
+#include <cctype>
+#include <fstream>
+
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_maps.h"
+
+namespace base {
+namespace trace_event {
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+// static
+std::istream* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr;
+
+namespace {
+
+const uint32 kMaxLineSize = 4096;
+
+bool ParseSmapsHeader(std::istream* smaps,
+ ProcessMemoryMaps::VMRegion* region) {
+ // e.g., "00400000-00421000 r-xp 00000000 fc:01 1234 /foo.so\n"
+ bool res = true; // Whether this region should be appended or skipped.
+ uint64 end_addr;
+ std::string protection_flags;
+ std::string ignored;
+ *smaps >> std::hex >> region->start_address;
+ smaps->ignore(1);
+ *smaps >> std::hex >> end_addr;
+ if (end_addr > region->start_address) {
+ region->size_in_bytes = end_addr - region->start_address;
+ } else {
+ // This is not just paranoia, it can actually happen (See crbug.com/461237).
+ region->size_in_bytes = 0;
+ res = false;
+ }
+
+ region->protection_flags = 0;
+ *smaps >> protection_flags;
+ CHECK(4UL == protection_flags.size());
+ if (protection_flags[0] == 'r') {
+ region->protection_flags |=
+ ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+ }
+ if (protection_flags[1] == 'w') {
+ region->protection_flags |=
+ ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+ }
+ if (protection_flags[2] == 'x') {
+ region->protection_flags |=
+ ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+ }
+ *smaps >> std::hex >> region->mapped_file_offset;
+ *smaps >> ignored; // Ignore device maj-min (fc:01 in the example above).
+ *smaps >> ignored; // Ignore inode number (1234 in the example above).
+
+ while (smaps->peek() == ' ')
+ smaps->ignore(1);
+ char mapped_file[kMaxLineSize];
+ smaps->getline(mapped_file, sizeof(mapped_file));
+ region->mapped_file = mapped_file;
+
+ return res;
+}
+
+uint32 ParseSmapsCounter(std::istream* smaps,
+ ProcessMemoryMaps::VMRegion* region) {
+ // e.g., "RSS: 0 Kb\n"
+ uint32 res = 0;
+ std::string counter_name;
+ *smaps >> counter_name;
+
+ // TODO(primiano): "Swap" should also be accounted as resident. Check
+ // whether Rss isn't already counting swapped and fix below if that is
+ // the case.
+ if (counter_name == "Rss:") {
+ *smaps >> std::dec >> region->byte_stats_resident;
+ region->byte_stats_resident *= 1024;
+ res = 1;
+ } else if (counter_name == "Anonymous:") {
+ *smaps >> std::dec >> region->byte_stats_anonymous;
+ region->byte_stats_anonymous *= 1024;
+ res = 1;
+ }
+
+#ifndef NDEBUG
+ // Paranoid check against changes of the Kernel /proc interface.
+ if (res) {
+ std::string unit;
+ *smaps >> unit;
+ DCHECK_EQ("kB", unit);
+ }
+#endif
+
+ smaps->ignore(kMaxLineSize, '\n');
+
+ return res;
+}
+
+uint32 ReadLinuxProcSmapsFile(std::istream* smaps, ProcessMemoryMaps* pmm) {
+ if (!smaps->good()) {
+ LOG(ERROR) << "Could not read smaps file.";
+ return 0;
+ }
+ const uint32 kNumExpectedCountersPerRegion = 2;
+ uint32 counters_parsed_for_current_region = 0;
+ uint32 num_valid_regions = 0;
+ ProcessMemoryMaps::VMRegion region;
+ bool should_add_current_region = false;
+ for (;;) {
+ int next = smaps->peek();
+ if (next == std::ifstream::traits_type::eof() || next == '\n')
+ break;
+ if (isxdigit(next) && !isupper(next)) {
+ region = {0};
+ counters_parsed_for_current_region = 0;
+ should_add_current_region = ParseSmapsHeader(smaps, ®ion);
+ } else {
+ counters_parsed_for_current_region += ParseSmapsCounter(smaps, ®ion);
+ DCHECK_LE(counters_parsed_for_current_region,
+ kNumExpectedCountersPerRegion);
+ if (counters_parsed_for_current_region == kNumExpectedCountersPerRegion) {
+ if (should_add_current_region) {
+ pmm->AddVMRegion(region);
+ ++num_valid_regions;
+ should_add_current_region = false;
+ }
+ }
+ }
+ }
+ return num_valid_regions;
+}
+
+} // namespace
+#endif // defined(OS_LINUX) || defined(OS_ANDROID)
+
+// static
+ProcessMemoryMapsDumpProvider* ProcessMemoryMapsDumpProvider::GetInstance() {
+ return Singleton<ProcessMemoryMapsDumpProvider,
+ LeakySingletonTraits<ProcessMemoryMapsDumpProvider>>::get();
+}
+
+ProcessMemoryMapsDumpProvider::ProcessMemoryMapsDumpProvider() {
+}
+
+ProcessMemoryMapsDumpProvider::~ProcessMemoryMapsDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory maps for the
+// current process.
+void ProcessMemoryMapsDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+ uint32 res = 0;
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+ if (UNLIKELY(proc_smaps_for_testing)) {
+ res = ReadLinuxProcSmapsFile(proc_smaps_for_testing, pmd->process_mmaps());
+ } else {
+ std::ifstream proc_self_smaps("/proc/self/smaps");
+ res = ReadLinuxProcSmapsFile(&proc_self_smaps, pmd->process_mmaps());
+ }
+#else
+ LOG(ERROR) << "ProcessMemoryMaps dump provider is supported only on Linux";
+#endif
+
+ if (res > 0)
+ pmd->set_has_process_mmaps();
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/process_memory_maps_dump_provider.h b/base/trace_event/process_memory_maps_dump_provider.h
new file mode 100644
index 0000000..543f7fd
--- /dev/null
+++ b/base/trace_event/process_memory_maps_dump_provider.h
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
+
+#include <istream>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT ProcessMemoryMapsDumpProvider : public MemoryDumpProvider {
+ public:
+ static ProcessMemoryMapsDumpProvider* GetInstance();
+
+ // MemoryDumpProvider implementation.
+ void DumpInto(ProcessMemoryDump* pmd) override;
+
+ private:
+ friend struct DefaultSingletonTraits<ProcessMemoryMapsDumpProvider>;
+ FRIEND_TEST_ALL_PREFIXES(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps);
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+ static std::istream* proc_smaps_for_testing;
+#endif
+
+ ProcessMemoryMapsDumpProvider();
+ ~ProcessMemoryMapsDumpProvider() override;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMapsDumpProvider);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
new file mode 100644
index 0000000..02fd136
--- /dev/null
+++ b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -0,0 +1,175 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_maps_dump_provider.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_maps.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+namespace {
+const char kTestSmaps1[] =
+ "00400000-004be000 r-xp 00000000 fc:01 1234 /file/1\n"
+ "Size: 760 kB\n"
+ "Rss: 296 kB\n"
+ "Pss: 162 kB\n"
+ "Shared_Clean: 228 kB\n"
+ "Shared_Dirty: 0 kB\n"
+ "Private_Clean: 0 kB\n"
+ "Private_Dirty: 68 kB\n"
+ "Referenced: 296 kB\n"
+ "Anonymous: 68 kB\n"
+ "AnonHugePages: 0 kB\n"
+ "Swap: 0 kB\n"
+ "KernelPageSize: 4 kB\n"
+ "MMUPageSize: 4 kB\n"
+ "Locked: 0 kB\n"
+ "VmFlags: rd ex mr mw me dw sd\n"
+ "ff000000-ff800000 -w-p 00001080 fc:01 0 /file/name with space\n"
+ "Size: 0 kB\n"
+ "Rss: 128 kB\n"
+ "Pss: 128 kB\n"
+ "Shared_Clean: 124 kB\n"
+ "Shared_Dirty: 0 kB\n"
+ "Private_Clean: 68 kB\n"
+ "Private_Dirty: 0 kB\n"
+ "Referenced: 296 kB\n"
+ "Anonymous: 0 kB\n"
+ "AnonHugePages: 0 kB\n"
+ "Swap: 0 kB\n"
+ "KernelPageSize: 4 kB\n"
+ "MMUPageSize: 4 kB\n"
+ "Locked: 0 kB\n"
+ "VmFlags: rd ex mr mw me dw sd";
+
+const char kTestSmaps2[] =
+ // An invalid region, with zero size and overlapping with the last one
+ // (See crbug.com/461237).
+ "7fe7ce79c000-7fe7ce79c000 ---p 00000000 00:00 0 \n"
+ "Size: 4 kB\n"
+ "Rss: 0 kB\n"
+ "Pss: 0 kB\n"
+ "Shared_Clean: 0 kB\n"
+ "Shared_Dirty: 0 kB\n"
+ "Private_Clean: 0 kB\n"
+ "Private_Dirty: 0 kB\n"
+ "Referenced: 0 kB\n"
+ "Anonymous: 0 kB\n"
+ "AnonHugePages: 0 kB\n"
+ "Swap: 0 kB\n"
+ "KernelPageSize: 4 kB\n"
+ "MMUPageSize: 4 kB\n"
+ "Locked: 0 kB\n"
+ "VmFlags: rd ex mr mw me dw sd\n"
+ // A invalid region with its range going backwards.
+ "00400000-00200000 ---p 00000000 00:00 0 \n"
+ "Size: 4 kB\n"
+ "Rss: 0 kB\n"
+ "Pss: 0 kB\n"
+ "Shared_Clean: 0 kB\n"
+ "Shared_Dirty: 0 kB\n"
+ "Private_Clean: 0 kB\n"
+ "Private_Dirty: 0 kB\n"
+ "Referenced: 0 kB\n"
+ "Anonymous: 0 kB\n"
+ "AnonHugePages: 0 kB\n"
+ "Swap: 0 kB\n"
+ "KernelPageSize: 4 kB\n"
+ "MMUPageSize: 4 kB\n"
+ "Locked: 0 kB\n"
+ "VmFlags: rd ex mr mw me dw sd\n"
+ // A good anonymous region at the end.
+ "7fe7ce79c000-7fe7ce7a8000 ---p 00000000 00:00 0 \n"
+ "Size: 48 kB\n"
+ "Rss: 40 kB\n"
+ "Pss: 0 kB\n"
+ "Shared_Clean: 16 kB\n"
+ "Shared_Dirty: 12 kB\n"
+ "Private_Clean: 8 kB\n"
+ "Private_Dirty: 4 kB\n"
+ "Referenced: 40 kB\n"
+ "Anonymous: 16 kB\n"
+ "AnonHugePages: 0 kB\n"
+ "Swap: 0 kB\n"
+ "KernelPageSize: 4 kB\n"
+ "MMUPageSize: 4 kB\n"
+ "Locked: 0 kB\n"
+ "VmFlags: rd wr mr mw me ac sd\n";
+} // namespace
+
+TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) {
+ const uint32 kProtR = ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+ const uint32 kProtW = ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+ const uint32 kProtX = ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+
+ auto pmmdp = ProcessMemoryMapsDumpProvider::GetInstance();
+
+ // Emulate a non-existent /proc/self/smaps.
+ ProcessMemoryDump pmd_invalid;
+ std::ifstream non_existent_file("/tmp/does-not-exist");
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &non_existent_file;
+ CHECK_EQ(false, non_existent_file.good());
+ pmmdp->DumpInto(&pmd_invalid);
+ ASSERT_FALSE(pmd_invalid.has_process_mmaps());
+
+ // Emulate an empty /proc/self/smaps.
+ std::ifstream empty_file("/dev/null");
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &empty_file;
+ CHECK_EQ(true, empty_file.good());
+ pmmdp->DumpInto(&pmd_invalid);
+ ASSERT_FALSE(pmd_invalid.has_process_mmaps());
+
+ // Parse the 1st smaps file.
+ ProcessMemoryDump pmd_1;
+ std::istringstream test_smaps_1(kTestSmaps1);
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_1;
+ pmmdp->DumpInto(&pmd_1);
+ ASSERT_TRUE(pmd_1.has_process_mmaps());
+ const auto& regions_1 = pmd_1.process_mmaps()->vm_regions();
+ ASSERT_EQ(2UL, regions_1.size());
+
+ EXPECT_EQ(0x00400000UL, regions_1[0].start_address);
+ EXPECT_EQ(0x004be000UL - 0x00400000UL, regions_1[0].size_in_bytes);
+ EXPECT_EQ(kProtR | kProtX, regions_1[0].protection_flags);
+ EXPECT_EQ("/file/1", regions_1[0].mapped_file);
+ EXPECT_EQ(0UL, regions_1[0].mapped_file_offset);
+ EXPECT_EQ(296 * 1024UL, regions_1[0].byte_stats_resident);
+ EXPECT_EQ(68 * 1024UL, regions_1[0].byte_stats_anonymous);
+
+ EXPECT_EQ(0xff000000UL, regions_1[1].start_address);
+ EXPECT_EQ(0xff800000UL - 0xff000000UL, regions_1[1].size_in_bytes);
+ EXPECT_EQ(kProtW, regions_1[1].protection_flags);
+ EXPECT_EQ("/file/name with space", regions_1[1].mapped_file);
+ EXPECT_EQ(0x00001080UL, regions_1[1].mapped_file_offset);
+ EXPECT_EQ(128 * 1024UL, regions_1[1].byte_stats_resident);
+ EXPECT_EQ(0UL, regions_1[1].byte_stats_anonymous);
+
+ // Parse the 2nd smaps file.
+ ProcessMemoryDump pmd_2;
+ std::istringstream test_smaps_2(kTestSmaps2);
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_2;
+ pmmdp->DumpInto(&pmd_2);
+ ASSERT_TRUE(pmd_2.has_process_mmaps());
+ const auto& regions_2 = pmd_2.process_mmaps()->vm_regions();
+ ASSERT_EQ(1UL, regions_2.size());
+ EXPECT_EQ(0x7fe7ce79c000UL, regions_2[0].start_address);
+ EXPECT_EQ(0x7fe7ce7a8000UL - 0x7fe7ce79c000UL, regions_2[0].size_in_bytes);
+ EXPECT_EQ(0U, regions_2[0].protection_flags);
+ EXPECT_EQ("", regions_2[0].mapped_file);
+ EXPECT_EQ(0UL, regions_2[0].mapped_file_offset);
+ EXPECT_EQ(40 * 1024UL, regions_2[0].byte_stats_resident);
+ EXPECT_EQ(16 * 1024UL, regions_2[0].byte_stats_anonymous);
+}
+#endif // defined(OS_LINUX) || defined(OS_ANDROID)
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index 07a2afa..e12d8f4 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -1008,7 +1008,8 @@
phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
name, trace_event_trace_id.data(), \
thread_id, base::TimeTicks::FromInternalValue(timestamp), \
- trace_event_flags, ##__VA_ARGS__); \
+ trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
+ ##__VA_ARGS__); \
} \
} while (0)
@@ -1045,9 +1046,11 @@
#define TRACE_EVENT_FLAG_HAS_ID (static_cast<unsigned char>(1 << 1))
#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast<unsigned char>(1 << 2))
#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned char>(1 << 3))
+#define TRACE_EVENT_FLAG_SCOPE_EXTRA (static_cast<unsigned char>(1 << 4))
+#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned char>(1 << 5))
#define TRACE_EVENT_FLAG_SCOPE_MASK (static_cast<unsigned char>( \
- TRACE_EVENT_FLAG_SCOPE_OFFSET | (TRACE_EVENT_FLAG_SCOPE_OFFSET << 1)))
+ TRACE_EVENT_FLAG_SCOPE_OFFSET | TRACE_EVENT_FLAG_SCOPE_EXTRA))
// Type values for identifying types in the TraceValue union.
#define TRACE_VALUE_TYPE_BOOL (static_cast<unsigned char>(1))
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index 9ca0ddc..445cb6d 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -1914,7 +1914,8 @@
id ^= process_id_hash_;
TimeTicks offset_event_timestamp = OffsetTimestamp(timestamp);
- TimeTicks now = OffsetNow();
+ TimeTicks now = flags & TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP ?
+ OffsetNow() : offset_event_timestamp;
TimeTicks thread_now = ThreadNow();
ThreadLocalEventBuffer* thread_local_event_buffer = NULL;
@@ -2035,9 +2036,6 @@
}
}
- // Use |now| instead of |offset_event_timestamp| to compute overhead, because
- // event timestamp may be not the real time that we started to add the event
- // (e.g. event with zero timestamp or that was generated some time ago).
if (thread_local_event_buffer)
thread_local_event_buffer->ReportOverhead(now, thread_now);