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, &region);
+    } else {
+      counters_parsed_for_current_region += ParseSmapsCounter(smaps, &region);
+      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);