Reland "android: Remove the legacy orderfile instrumentation."
This reverts commit 2b33f7e21ffa29e67a02d27161c0e03486287744.
Reason for reland: The initial CL wasn't related to
crbug.com/814627.
Original change's description:
> Revert "android: Remove the legacy orderfile instrumentation."
>
> This reverts commit 5ecdb8cf939ff1d3b53a34e45e283e0975ba8283.
>
> Reason for revert: Speculative revert for crbug.com/814627
>
> Original change's description:
> > android: Remove the legacy orderfile instrumentation.
> >
> > Bug: 813597
> > Change-Id: Ie4838ed3b816b483b3b44325f4159856c3b81d4e
> > Reviewed-on: https://chromium-review.googlesource.com/925424
> > Reviewed-by: Egor Pasko <pasko@chromium.org>
> > Reviewed-by: agrieve <agrieve@chromium.org>
> > Reviewed-by: Matthew Cary <mattcary@chromium.org>
> > Commit-Queue: Benoit L <lizeb@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#538082}
>
> TBR=pasko@chromium.org,agrieve@chromium.org,lizeb@chromium.org,mattcary@chromium.org
>
> Change-Id: I161ebcdaf105d561d4b4ad5ebb21a065ebc9be14
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: 813597
> Reviewed-on: https://chromium-review.googlesource.com/931381
> Reviewed-by: Tien-Ren Chen <trchen@chromium.org>
> Commit-Queue: Tien-Ren Chen <trchen@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#538414}
TBR=pasko@chromium.org,trchen@chromium.org,agrieve@chromium.org,lizeb@chromium.org,mattcary@chromium.org
# Not skipping CQ checks because original CL landed > 1 day ago.
Bug: 813597
Change-Id: I22daf61b6441336d9158124be3cc71959e426613
Reviewed-on: https://chromium-review.googlesource.com/951422
Reviewed-by: Benoit L <lizeb@chromium.org>
Reviewed-by: Egor Pasko <pasko@chromium.org>
Reviewed-by: Matthew Cary <mattcary@chromium.org>
Commit-Queue: Benoit L <lizeb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#541111}
diff --git a/BUILD.gn b/BUILD.gn
index 0f2e28a..37cf59b 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -309,7 +309,6 @@
"//tools/android/customtabs_benchmark:customtabs_benchmark_apk",
"//tools/android/errorprone_plugin:errorprone_plugin_java",
"//tools/android/kerberos/SpnegoAuthenticator:spnego_authenticator_apk",
- "//tools/cygprofile:cygprofile_unittests",
"//ui/android:ui_junit_tests",
]
deps -= [
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
index dda25778a..fefbb5e 100644
--- a/base/android/library_loader/library_prefetcher.cc
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -184,9 +184,9 @@
// static
bool NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary() {
- // Avoid forking with cygprofile instrumentation because the latter performs
- // memory allocations.
#if defined(CYGPROFILE_INSTRUMENTATION)
+ // Avoid forking with cygprofile instrumentation because the child process
+ // would create a dump as well.
return false;
#endif
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn
index 4e73318..fabde6c 100644
--- a/build/config/android/BUILD.gn
+++ b/build/config/android/BUILD.gn
@@ -216,11 +216,7 @@
config("cygprofile_instrumentation") {
defines = [ "CYGPROFILE_INSTRUMENTATION=1" ]
- if (use_lightweight_order_profiling) {
- cflags = [ "-finstrument-function-entry-bare" ]
- } else {
- cflags = [ "-finstrument-functions-after-inlining" ]
- }
+ cflags = [ "-finstrument-function-entry-bare" ]
}
config("no_cygprofile_instrumentation") {
diff --git a/build/config/android/abi.gni b/build/config/android/abi.gni
index 24bef19..877c3f74 100644
--- a/build/config/android/abi.gni
+++ b/build/config/android/abi.gni
@@ -12,11 +12,6 @@
# functions are called at startup.
use_order_profiling = false
- # Use a lightweight variant of order profiling. Does nothing without
- # use_order_profiling set above. Will either replace use_order_profiling
- # or be removed.
- use_lightweight_order_profiling = false
-
# Builds secondary abi for APKs, supports build 32-bit arch as secondary
# abi in 64-bit Monochrome and WebView.
build_apk_secondary_abi = true
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index efd4954c..bdff8d3 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -778,8 +778,8 @@
deps += [ "//tools/cygprofile" ]
}
- # See crbug.com/705088, crbug.com/717815.
- if (target_cpu == "arm" && (is_asan || use_order_profiling)) {
+ # See crbug.com/705088.
+ if (target_cpu == "arm" && is_asan) {
ldflags = [ "-Wl,--long-plt" ]
}
diff --git a/tools/cygprofile/BUILD.gn b/tools/cygprofile/BUILD.gn
index f5f9016..0ba8b6a 100644
--- a/tools/cygprofile/BUILD.gn
+++ b/tools/cygprofile/BUILD.gn
@@ -5,8 +5,9 @@
import("//build/config/android/config.gni")
if (target_cpu == "arm") {
- static_library("lightweight_cygprofile") {
+ static_library("cygprofile") {
sources = [
+ "delayed_dumper.cc",
"lightweight_cygprofile.cc",
"lightweight_cygprofile.h",
]
@@ -17,71 +18,8 @@
configs -= [ "//build/config/android:default_cygprofile_instrumentation" ]
configs += [ "//build/config/android:no_cygprofile_instrumentation" ]
}
-}
-static_library("cygprofile") {
- deps = [
- # This adds uninstrumented symbols to the static library from base.
- # These symbols are likely *not* to be used because there are many other
- # duplicates in other objects/libraries.
- "//base",
- ]
-
- if (use_lightweight_order_profiling) {
- assert(use_order_profiling)
- assert(target_cpu == "arm")
- sources = [
- "delayed_dumper.cc",
- ]
- deps += [ ":lightweight_cygprofile" ]
- } else {
- sources = [
- "cygprofile.cc",
- "cygprofile.h",
- ]
- }
-
- configs -= [ "//build/config/android:default_cygprofile_instrumentation" ]
- configs += [ "//build/config/android:no_cygprofile_instrumentation" ]
-}
-
-executable("cygprofile_unittests") {
- testonly = true
-
- sources = [
- "cygprofile_unittest.cc",
- ]
-
- configs -= [ "//build/config/android:default_cygprofile_instrumentation" ]
- configs += [ "//build/config/android:no_cygprofile_instrumentation" ]
-
- deps = [
- ":cygprofile",
- "//base",
- "//testing/gtest",
- ]
-}
-
-executable("cygprofile_perftests") {
- testonly = true
-
- sources = [
- "cygprofile_perftest.cc",
- ]
-
- configs -= [ "//build/config/android:default_cygprofile_instrumentation" ]
- configs += [ "//build/config/android:no_cygprofile_instrumentation" ]
-
- deps = [
- ":cygprofile",
- "//base",
- "//testing/gtest",
- "//testing/perf",
- ]
-}
-
-if (target_cpu == "arm") {
- executable("lightweight_cygprofile_perftests") {
+ executable("cygprofile_perftests") {
testonly = true
sources = [
@@ -92,7 +30,7 @@
configs += [ "//build/config/android:no_cygprofile_instrumentation" ]
deps = [
- ":lightweight_cygprofile",
+ ":cygprofile",
"//base",
"//testing/gtest",
"//testing/perf",
diff --git a/tools/cygprofile/cyglog_to_orderfile.py b/tools/cygprofile/cyglog_to_orderfile.py
index 0fb2e90..aecb101 100755
--- a/tools/cygprofile/cyglog_to_orderfile.py
+++ b/tools/cygprofile/cyglog_to_orderfile.py
@@ -13,7 +13,6 @@
import multiprocessing
import os
import re
-import string
import sys
import tempfile
@@ -123,6 +122,7 @@
symbol_infos_nested = pool.map(
symbol_extractor.SymbolInfosFromBinary, obj_files)
pool.close()
+ pool.join()
result = []
for symbol_infos in symbol_infos_nested:
result += symbol_infos
@@ -201,47 +201,6 @@
raise _SymbolNotFoundException(offset)
-def _ParseLogLines(log_file_lines):
- """Parses a merged cyglog produced by mergetraces.py.
-
- Args:
- log_file_lines: array of lines in log file produced by profiled run
-
- Below is an example of a small log file:
- 5086e000-52e92000 r-xp 00000000 b3:02 51276 libchromeview.so
- secs usecs pid:threadid func
- START
- 1314897086 795828 3587:1074648168 0x509e105c
- 1314897086 795874 3587:1074648168 0x509e0eb4
- 1314897086 796326 3587:1074648168 0x509e0e3c
- 1314897086 796552 3587:1074648168 0x509e07bc
- END
-
- Returns:
- An ordered list of callee offsets.
- """
- call_lines = []
- vm_start = 0
- line = log_file_lines[0]
- assert 'r-xp' in line
- end_index = line.find('-')
- vm_start = int(line[:end_index], 16)
- for line in log_file_lines[3:]:
- fields = line.split()
- if len(fields) == 4:
- call_lines.append(fields)
- else:
- assert fields[0] == 'END'
- # Convert strings to int in fields.
- call_info = []
- for call_line in call_lines:
- addr = int(call_line[3], 16)
- if vm_start < addr:
- addr -= vm_start
- call_info.append(addr)
- return call_info
-
-
def _WarnAboutDuplicates(offsets):
"""Warns about duplicate offsets.
@@ -275,9 +234,7 @@
parser.add_argument('--target-arch', required=False,
choices=['arm', 'arm64', 'x86', 'x86_64', 'x64', 'mips'],
help='The target architecture for libchrome.so')
- parser.add_argument('--merged-cyglog', type=str, required=False,
- help='Path to the merged cyglog')
- parser.add_argument('--reached-offsets', type=str, required=False,
+ parser.add_argument('--reached-offsets', type=str, required=True,
help='Path to the reached offsets')
parser.add_argument('--native-library', type=str, required=True,
help='Path to the unstripped instrumented library')
@@ -290,20 +247,13 @@
parser = _CreateArgumentParser()
args = parser.parse_args()
- assert bool(args.merged_cyglog) ^ bool(args.reached_offsets)
-
if not args.target_arch:
args.arch = cygprofile_utils.DetectArchitecture()
symbol_extractor.SetArchitecture(args.target_arch)
obj_dir = cygprofile_utils.GetObjDir(args.native_library)
- offsets = []
- if args.merged_cyglog:
- log_file_lines = map(string.rstrip, open(args.merged_cyglog).readlines())
- offsets = _ParseLogLines(log_file_lines)
- else:
- offsets = _ReadReachedOffsets(args.reached_offsets)
+ offsets = _ReadReachedOffsets(args.reached_offsets)
assert offsets
_WarnAboutDuplicates(offsets)
diff --git a/tools/cygprofile/cyglog_to_orderfile_unittest.py b/tools/cygprofile/cyglog_to_orderfile_unittest.py
index 37722570..2aae4d4 100755
--- a/tools/cygprofile/cyglog_to_orderfile_unittest.py
+++ b/tools/cygprofile/cyglog_to_orderfile_unittest.py
@@ -76,17 +76,6 @@
if failure_items:
raise self.failureException('\n'.join(failure_items))
- def testParseLogLines(self):
- lines = """5086e000-52e92000 r-xp 00000000 b3:02 51276 libchromeview.so
-secs usecs pid:threadid func
-START
-1314897086 795828 3587:1074648168 0x509e105c
-1314897086 795874 3587:1074648168 0x509e0eb4
-END""".split('\n')
- offsets = cyglog_to_orderfile._ParseLogLines(lines)
- self.assertListEqual(
- offsets, [0x509e105c - 0x5086e000, 0x509e0eb4 - 0x5086e000])
-
def testWarnAboutDuplicates(self):
offsets = [0x1, 0x2, 0x3]
self.assertTrue(cyglog_to_orderfile._WarnAboutDuplicates(offsets))
diff --git a/tools/cygprofile/cygprofile.cc b/tools/cygprofile/cygprofile.cc
deleted file mode 100644
index 7c04fed..0000000
--- a/tools/cygprofile/cygprofile.cc
+++ /dev/null
@@ -1,400 +0,0 @@
-// Copyright (c) 2011 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 "tools/cygprofile/cygprofile.h"
-
-#include <fcntl.h>
-#include <pthread.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <cstdio>
-#include <fstream>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/containers/hash_tables.h"
-#include "base/files/scoped_file.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/stringprintf.h"
-#include "base/synchronization/lock.h"
-
-namespace cygprofile {
-namespace {
-
-// Allow 8 MBytes of data for each thread log.
-const size_t kMaxBufferSize = 8 * 1024 * 1024 / sizeof(LogEntry);
-
-// Have the background internal thread do its flush every 15 sec.
-const int kFlushThreadIdleTimeSec = 15;
-
-const char kLogFileNamePrefix[] = "/data/local/tmp/chrome/cyglog/";
-
-// "cyglog.PID.LWP.PPID"
-const char kLogFilenameFormat[] = "%scyglog.%d.%d-%d";
-
-// Magic value of above to prevent instrumentation. Used when ThreadLog is being
-// constructed (to prevent reentering by malloc, for example) and by the flush
-// log thread (to prevent it from being logged0.
-ThreadLog* const kMagicBeingConstructed = reinterpret_cast<ThreadLog*>(1);
-
-// Per-thread pointer to the current log object.
-pthread_key_t g_tls_slot;
-
-// Used to initialize the tls slot, once per the entire process.
-pthread_once_t g_tls_slot_initializer_once = PTHREAD_ONCE_INIT;
-
-// This variable is to prevent re-entrancy in the __cyg_profile_func_enter()
-// while the TLS slot itself is being initialized. Volatile here is required
-// to avoid compiler optimizations as this need to be read in a re-entrant way.
-// This variable is written by one thread only, which is the first thread that
-// happens to run the TLSSlotInitializer(). In practice this will happen very
-// early in the startup process, as soon as the first instrumented function is
-// called.
-volatile bool g_tls_slot_being_initialized = false;
-
-// Initializes the global TLS slot. This is invoked only once per process.
-static void TLSSlotInitializer()
-{
- g_tls_slot_being_initialized = true;
- PCHECK(0 == pthread_key_create(&g_tls_slot, NULL));
- g_tls_slot_being_initialized = false;
-}
-
-// Returns light-weight process ID. On Linux, this is a system-wide unique
-// thread id.
-pid_t GetTID() {
- return syscall(__NR_gettid);
-}
-
-timespec GetCurrentTime() {
- timespec timestamp;
- clock_gettime(CLOCK_MONOTONIC, ×tamp);
- return timestamp;
-}
-
-// Sleeps for |sec| seconds.
-void SleepSec(int sec) {
- for (int secs_to_sleep = sec; secs_to_sleep != 0;)
- secs_to_sleep = sleep(secs_to_sleep);
-}
-
-// Exposes the string header that will appear at the top of every trace file.
-// This string contains memory mapping information for the mapped
-// library/executable which is used offline during symbolization. Note that
-// this class is meant to be instantiated once per process and lazily (during
-// the first flush).
-struct ImmutableFileHeaderLine {
- ImmutableFileHeaderLine() : value(MakeFileHeaderLine()) {}
-
- const std::string value;
-
- private:
- // Returns whether the integer representation of the hexadecimal address
- // stored in |line| at position |start_offset| was successfully stored in
- // |result|.
- static bool ParseAddress(const std::string& line,
- size_t start_offset,
- size_t length,
- uint64_t* result) {
- if (start_offset >= line.length())
- return false;
-
- uint64_t address;
- const bool ret = HexStringToUInt64(
- base::StringPiece(line.c_str() + start_offset, length), &address);
- if (!ret)
- return false;
-
- *result = address;
- return true;
- }
-
- // Parses /proc/self/maps and returns a two line string such as:
- // 758c6000-79f4b000 r-xp 00000000 b3:17 309475 libchrome.2009.0.so
- // secs usecs pid:threadid func
- static std::string MakeFileHeaderLine() {
- std::ifstream mapsfile("/proc/self/maps");
- CHECK(mapsfile.good());
- std::string result;
-
- for (std::string line; std::getline(mapsfile, line); ) {
- if (line.find("r-xp") == std::string::npos)
- continue;
-
- const size_t address_length = line.find('-');
- uint64_t start_address = 0;
- CHECK(ParseAddress(line, 0, address_length, &start_address));
-
- uint64_t end_address = 0;
- CHECK(ParseAddress(line, address_length + 1, address_length,
- &end_address));
-
- const uintptr_t current_func_addr = reinterpret_cast<uintptr_t>(
- &MakeFileHeaderLine);
- if (current_func_addr >= start_address &&
- current_func_addr < end_address) {
- result.swap(line);
- break;
- }
- }
- CHECK(!result.empty());
- result.append("\nsecs\tusecs\tpid:threadid\tfunc\n");
- return result;
- }
-};
-
-base::LazyInstance<ThreadLogsManager>::Leaky g_logs_manager =
- LAZY_INSTANCE_INITIALIZER;
-
-base::LazyInstance<ImmutableFileHeaderLine>::Leaky g_file_header_line =
- LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-// Custom thread implementation that joins on destruction. Note that
-// base::Thread has non-trivial dependencies on e.g. AtExitManager which makes
-// it hard to use it early.
-class Thread {
- public:
- Thread(const base::Closure& thread_callback)
- : thread_callback_(thread_callback) {
- PCHECK(0 == pthread_create(&handle_, NULL, &Thread::EntryPoint, this));
- }
-
- ~Thread() {
- PCHECK(0 == pthread_join(handle_, NULL));
- }
-
- private:
- static void* EntryPoint(void* data) {
- // Disable logging on this thread. Although this routine is not instrumented
- // (cygprofile.gyp provides that), the called routines are and thus will
- // call instrumentation.
- pthread_once(&g_tls_slot_initializer_once, TLSSlotInitializer);
- ThreadLog* thread_log = reinterpret_cast<ThreadLog*>(
- pthread_getspecific(g_tls_slot));
- CHECK(thread_log == NULL); // Must be 0 as this is a new thread.
- PCHECK(0 == pthread_setspecific(g_tls_slot, kMagicBeingConstructed));
-
- Thread* const instance = reinterpret_cast<Thread*>(data);
- instance->thread_callback_.Run();
- return NULL;
- }
-
- const base::Closure thread_callback_;
- pthread_t handle_;
-
- DISALLOW_COPY_AND_ASSIGN(Thread);
-};
-
-// Single log entry recorded for each function call.
-LogEntry::LogEntry(const void* address, pid_t pid, pid_t tid)
- : time(GetCurrentTime()), pid(pid), tid(tid), address(address) {}
-
-ThreadLog::ThreadLog()
- : pid_(getpid()),
- tid_(GetTID()),
- in_use_(false),
- flush_callback_(
- base::Bind(&ThreadLog::FlushInternal, base::Unretained(this))) {}
-
-ThreadLog::ThreadLog(const FlushCallback& flush_callback)
- : pid_(getpid()),
- tid_(GetTID()),
- in_use_(false),
- flush_callback_(flush_callback) {}
-
-ThreadLog::~ThreadLog() {
- PCHECK(0 == pthread_setspecific(g_tls_slot, NULL));
-}
-
-void ThreadLog::AddEntry(void* address) {
- if (in_use_)
- return;
- in_use_ = true;
-
- DCHECK_EQ(tid_, GetTID());
- bool did_insert = called_functions_.insert(address).second;
-
- if (did_insert) {
- base::AutoLock auto_lock(lock_);
- entries_.emplace_back(address, pid_, tid_);
- // Crash in a quickly understandable way instead of crashing (or maybe not
- // though) due to OOM.
- CHECK_LE(entries_.size(), kMaxBufferSize);
- }
-
- in_use_ = false;
-}
-
-void ThreadLog::TakeEntries(std::vector<LogEntry>* destination) {
- base::AutoLock auto_lock(lock_);
- destination->swap(entries_);
- base::STLClearObject(&entries_);
-}
-
-void ThreadLog::Flush(std::vector<LogEntry>* entries) const {
- flush_callback_.Run(entries);
-}
-
-void ThreadLog::FlushInternal(std::vector<LogEntry>* entries) const {
- const std::string log_filename(
- base::StringPrintf(
- kLogFilenameFormat, kLogFileNamePrefix, getpid(), tid_, getppid()));
- const base::ScopedFILE file(fopen(log_filename.c_str(), "a"));
- CHECK(file.get());
-
- const long offset = ftell(file.get());
- if (offset == 0)
- fprintf(file.get(), "%s", g_file_header_line.Get().value.c_str());
-
- for (std::vector<LogEntry>::const_iterator it = entries->begin();
- it != entries->end(); ++it) {
- fprintf(file.get(), "%ld %ld\t%d:%d\t%p\n", it->time.tv_sec,
- it->time.tv_nsec / 1000, it->pid, it->tid, it->address);
- }
-
- base::STLClearObject(entries);
-}
-
-ThreadLogsManager::ThreadLogsManager()
- : wait_callback_(base::Bind(&SleepSec, kFlushThreadIdleTimeSec)) {
-}
-
-ThreadLogsManager::ThreadLogsManager(const base::Closure& wait_callback,
- const base::Closure& notify_callback)
-
- : wait_callback_(wait_callback),
- notify_callback_(notify_callback) {
-}
-
-ThreadLogsManager::~ThreadLogsManager() {
- // Note that the internal thread does some work until it sees |flush_thread_|
- // = NULL.
- std::unique_ptr<Thread> flush_thread;
- {
- base::AutoLock auto_lock(lock_);
- flush_thread_.swap(flush_thread);
- }
- flush_thread.reset(); // Joins the flush thread.
-}
-
-void ThreadLogsManager::AddLog(std::unique_ptr<ThreadLog> new_log) {
- base::AutoLock auto_lock(lock_);
-
- if (logs_.empty())
- StartInternalFlushThread_Locked();
-
- logs_.push_back(std::move(new_log));
-}
-
-void ThreadLogsManager::StartInternalFlushThread_Locked() {
- lock_.AssertAcquired();
- CHECK(!flush_thread_);
- // Note that the |flush_thread_| joins at destruction which guarantees that it
- // will never outlive |this|, i.e. it's safe not to use ref-counting.
- flush_thread_.reset(
- new Thread(base::Bind(&ThreadLogsManager::FlushAllLogsOnFlushThread,
- base::Unretained(this))));
-}
-
-// Type used below for flushing.
-struct LogData {
- LogData(ThreadLog* thread_log) : thread_log(thread_log) {}
-
- ThreadLog* const thread_log;
- std::vector<LogEntry> entries;
-};
-
-void ThreadLogsManager::FlushAllLogsOnFlushThread() {
- while (true) {
- {
- base::AutoLock auto_lock(lock_);
- // The |flush_thread_| field is reset during destruction.
- if (!flush_thread_)
- return;
- }
- // Sleep for a few secs and then flush all thread's buffers. There is a
- // danger that, when quitting Chrome, this thread may see unallocated data
- // and segfault. We do not care because we need logs when Chrome is working.
- wait_callback_.Run();
-
- // Copy the ThreadLog pointers to avoid acquiring both the logs manager's
- // lock and the one for individual thread logs.
- std::vector<ThreadLog*> thread_logs_copy;
- {
- base::AutoLock auto_lock(lock_);
- for (const auto& log : logs_)
- thread_logs_copy.push_back(log.get());
- }
-
- // Move the logs' data before flushing them so that the mutexes are not
- // acquired for too long.
- std::vector<LogData> logs;
- for (std::vector<ThreadLog*>::const_iterator it =
- thread_logs_copy.begin();
- it != thread_logs_copy.end(); ++it) {
- ThreadLog* const thread_log = *it;
- LogData log_data(thread_log);
- logs.push_back(log_data);
- thread_log->TakeEntries(&logs.back().entries);
- }
-
- for (std::vector<LogData>::iterator it = logs.begin();
- it != logs.end(); ++it) {
- if (!it->entries.empty())
- it->thread_log->Flush(&it->entries);
- }
-
- if (!notify_callback_.is_null())
- notify_callback_.Run();
- }
-}
-
-extern "C" {
-
-// The GCC compiler callbacks, called on every function invocation providing
-// addresses of caller and callee codes.
-void __cyg_profile_func_enter(void* this_fn, void* call_site)
- __attribute__((no_instrument_function));
-void __cyg_profile_func_exit(void* this_fn, void* call_site)
- __attribute__((no_instrument_function));
-
-void __cyg_profile_func_enter(void* this_fn, void* callee_unused) {
- // Avoid re-entrancy while initializing the TLS slot (once per process).
- if (g_tls_slot_being_initialized)
- return;
-
- pthread_once(&g_tls_slot_initializer_once, TLSSlotInitializer);
- ThreadLog* thread_log = reinterpret_cast<ThreadLog*>(
- pthread_getspecific(g_tls_slot));
-
- if (thread_log == NULL) {
- PCHECK(0 == pthread_setspecific(g_tls_slot, kMagicBeingConstructed));
- thread_log = new ThreadLog();
- CHECK(thread_log);
- g_logs_manager.Pointer()->AddLog(base::WrapUnique(thread_log));
- PCHECK(0 == pthread_setspecific(g_tls_slot, thread_log));
- }
-
- if (thread_log != kMagicBeingConstructed)
- thread_log->AddEntry(this_fn);
-}
-
-void __cyg_profile_func_exit(void* this_fn, void* call_site) {}
-
-} // extern "C"
-} // namespace cygprofile
diff --git a/tools/cygprofile/cygprofile.h b/tools/cygprofile/cygprofile.h
deleted file mode 100644
index 97684e78..0000000
--- a/tools/cygprofile/cygprofile.h
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2014 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.
-//
-// Tool to log the execution of the process (Chrome). Writes logs containing
-// time and address of the callback being called for the first time.
-//
-// For performance reasons logs are buffered. Every thread has its own buffer
-// and log file so the contention between threads is minimal. As a side-effect,
-// functions called might be mentioned in many thread logs.
-//
-// A special thread is created in the process to periodically flush logs for all
-// threads in case the thread had stopped before flushing its logs.
-//
-// Also note that the instrumentation code is self-activated. It begins to
-// record the log data when it is called first, including the run-time startup.
-// Have it in mind when modifying it, in particular do not use global objects
-// with constructors as they are called during startup (too late for us).
-
-#ifndef TOOLS_CYGPROFILE_CYGPROFILE_H_
-#define TOOLS_CYGPROFILE_CYGPROFILE_H_
-
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/containers/hash_tables.h"
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "build/build_config.h"
-
-#if !defined(OS_ANDROID)
-// This is only supported on Android thanks to the fact that on Android
-// processes (other than the system's zygote) don't fork.
-//
-// To make cygprofile truly work (i.e. without any deadlock) on Chrome
-// platforms that use fork(), cygprofile.cc should be written in a way that
-// guarantees that:
-// - No lock is acquired by a foreign thread during fork(). In particular this
-// means that cygprofile.cc should not perform any heap allocation (since heap
-// allocators, including TCMalloc generally use locks).
-// - Only cygprofile.cc uses pthread_atfork() in the whole process. Unlike POSIX
-// signals, pthread_atfork() doesn't provide a way to install multiple handlers.
-// Calling pthread_atfork() in cygprofile.cc would override any handler that
-// could have been installed previously.
-//
-// Chrome happens to violate the first requirement at least once by having its
-// process launcher thread fork. However the child process in that case, when
-// it's not instrumented with cygprofile, directly calls exec(). This is safe
-// since the child process doesn't try to release a lock acquired by another
-// thread in the parent process which would lead to a deadlock. This problem was
-// actually observed by trying to port the current version of cygprofile.cc to
-// Linux.
-#error This is only supported on Android.
-#endif
-
-// The following is only exposed for testing.
-namespace cygprofile {
-
-class Thread;
-
-// Single log entry recorded for each function call.
-struct LogEntry {
- LogEntry(const void* address, pid_t pid, pid_t tid);
-
- const timespec time;
- const pid_t pid;
- const pid_t tid;
- const void* const address;
-};
-
-// Per-thread function calls log.
-class ThreadLog {
- public:
- // Callback invoked for flushing that can be provided for testing.
- typedef base::Callback<void (std::vector<LogEntry>*)> FlushCallback;
-
- ThreadLog();
-
- // Used for testing.
- ThreadLog(const FlushCallback& flush_callback);
-
- ~ThreadLog();
-
- // Must only be called from the thread this ThreadLog instance is watching.
- void AddEntry(void* address);
-
- // Can be called from any thread.
- void TakeEntries(std::vector<LogEntry>* output);
-
- // Flushes the provided vector of entries to a file and clears it. Note that
- // this can be called from any thread.
- void Flush(std::vector<LogEntry>* entries) const;
-
- private:
- // Default implementation (that can be overridden for testing) of the method
- // above.
- void FlushInternal(std::vector<LogEntry>* entries) const;
-
- // Process ID, as returned by getpid().
- const pid_t pid_;
-
- // Thread identifier as Linux kernel shows it. LWP (light-weight process) is
- // a unique ID of the thread in the system, unlike pthread_self() which is the
- // same for fork()-ed threads.
- const pid_t tid_;
-
- // Current thread is inside the instrumentation routine.
- bool in_use_;
-
- // Callback used to flush entries.
- const FlushCallback flush_callback_;
-
- // Keeps track of all functions that have been logged on this thread so we do
- // not record duplicates.
- base::hash_set<void*> called_functions_;
-
- // A lock that guards |entries_| usage between per-thread instrumentation
- // routine and timer flush callback. So the contention could happen only
- // during the flush, every 15 secs.
- base::Lock lock_;
-
- std::vector<LogEntry> entries_;
-
- DISALLOW_COPY_AND_ASSIGN(ThreadLog);
-};
-
-// Manages a list of per-thread logs.
-class ThreadLogsManager {
- public:
- ThreadLogsManager();
-
- // Used for testing. The provided callbacks are used for testing to
- // synchronize the internal thread with the unit test running on the main
- // thread.
- ThreadLogsManager(const base::Closure& wait_callback,
- const base::Closure& notify_callback);
-
- ~ThreadLogsManager();
-
- // Can be called from any thread.
- void AddLog(std::unique_ptr<ThreadLog> new_log);
-
- private:
- void StartInternalFlushThread_Locked();
-
- // Flush thread's entry point.
- void FlushAllLogsOnFlushThread();
-
- // Used to make the internal thread sleep before each flush iteration.
- const base::Closure wait_callback_;
- // Used to trigger a notification when a flush happened on the internal
- // thread.
- const base::Closure notify_callback_;
-
- // Protects the state below.
- base::Lock lock_;
- std::unique_ptr<Thread> flush_thread_;
- std::vector<std::unique_ptr<ThreadLog>> logs_;
-
- DISALLOW_COPY_AND_ASSIGN(ThreadLogsManager);
-};
-
-} // namespace cygprofile
-
-#endif // TOOLS_CYGPROFILE_CYGPROFILE_H_
diff --git a/tools/cygprofile/cygprofile_perftest.cc b/tools/cygprofile/cygprofile_perftest.cc
deleted file mode 100644
index ae8fe3e7..0000000
--- a/tools/cygprofile/cygprofile_perftest.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2017 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 "tools/cygprofile/cygprofile.h"
-
-#include <cstdint>
-#include <vector>
-
-#include "base/strings/stringprintf.h"
-#include "base/time/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/perf/perf_test.h"
-
-namespace cygprofile {
-
-namespace {
-
-void AddEntryCost(int iterations, int addresses_count) {
- // This is intentionally leaky. ThreadLog() destructor would call abort(),
- // limiting us to a single test. Leaking ThreadLog is fine as long as we clean
- // up the entries.
- auto* thread_log = new ThreadLog();
-
- auto tick = base::TimeTicks::Now();
- for (int i = 0; i < iterations; i++) {
- for (int address = 0; address < addresses_count; address++) {
- thread_log->AddEntry(reinterpret_cast<void*>(address));
- }
- }
- auto tock = base::TimeTicks::Now();
- double nanos = static_cast<double>((tock - tick).InNanoseconds());
- auto ns_per_call =
- nanos / (iterations * static_cast<double>(addresses_count));
- auto modifier = base::StringPrintf("_%d_%d", iterations, addresses_count);
- perf_test::PrintResult("AddEntryCostPerCall", modifier, "", ns_per_call, "ns",
- true);
-
- // Entries cleanup, see comment at the beginning of the function.
- std::vector<LogEntry> entries;
- thread_log->TakeEntries(&entries);
-}
-} // namespace
-
-TEST(CygprofilePerfTest, CreateEntries_10_10000) {
- AddEntryCost(10, 10000);
-}
-
-TEST(CygprofilePerfTest, CreateEntries_100_10000) {
- AddEntryCost(100, 10000);
-}
-
-TEST(CygprofilePerfTest, CreateEntries_10_100000) {
- AddEntryCost(10, 100000);
-}
-
-TEST(CygprofilePerfTest, CreateEntries_100_1000000) {
- AddEntryCost(100, 100000);
-}
-
-} // namespace cygprofile
-
-// Custom runner implementation since base's one requires JNI on Android.
-int main(int argc, char** argv) {
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/tools/cygprofile/cygprofile_unittest.cc b/tools/cygprofile/cygprofile_unittest.cc
deleted file mode 100644
index 5be4804..0000000
--- a/tools/cygprofile/cygprofile_unittest.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2014 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 "tools/cygprofile/cygprofile.h"
-
-#include <stdint.h>
-#include <sys/time.h>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/synchronization/waitable_event.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cygprofile {
-namespace {
-
-void FlushEntries(std::vector<LogEntry>* destination,
- std::vector<LogEntry>* entries) {
- CHECK_EQ(0U, destination->size());
- // Move the provided |entries| vector to the provided |destination| so that
- // the unit test that triggered the flush can check it.
- destination->swap(*entries);
-}
-
-// Flush callback that should not be invoked.
-void CheckFlushDoesNotHappen(std::vector<LogEntry>* entries) {
- NOTREACHED();
-}
-
-uint64_t GetUsecSecTimeFromTimeSpec(struct timespec timespec) {
- return timespec.tv_sec * 1000 * 1000 + timespec.tv_nsec / 1000;
-}
-
-TEST(CygprofileTest, ThreadLogBasic) {
- ThreadLog thread_log(base::Bind(&CheckFlushDoesNotHappen));
-
- thread_log.AddEntry(reinterpret_cast<void*>(0x2));
- thread_log.AddEntry(reinterpret_cast<void*>(0x1));
-
- std::vector<LogEntry> entries;
- thread_log.TakeEntries(&entries);
-
- ASSERT_EQ(2U, entries.size());
- // The entries should appear in their insertion order.
- const LogEntry& first_entry = entries[0];
- ASSERT_EQ(reinterpret_cast<uintptr_t>(first_entry.address), 2U);
- ASSERT_EQ(getpid(), first_entry.pid);
- ASSERT_LT(0, first_entry.tid);
-
- const LogEntry& second_entry = entries[1];
- ASSERT_EQ(1U, reinterpret_cast<uintptr_t>(second_entry.address));
- ASSERT_EQ(first_entry.pid, second_entry.pid);
- ASSERT_EQ(first_entry.tid, second_entry.tid);
-
- ASSERT_GE(GetUsecSecTimeFromTimeSpec(second_entry.time),
- GetUsecSecTimeFromTimeSpec(first_entry.time));
-}
-
-TEST(CygprofileTest, ManagerBasic) {
- base::WaitableEvent wait_event(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- base::WaitableEvent notify_event(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
-
- ThreadLogsManager manager(
- base::Bind(&base::WaitableEvent::Wait, base::Unretained(&wait_event)),
- base::Bind(&base::WaitableEvent::Signal,
- base::Unretained(¬ify_event)));
-
- std::vector<LogEntry> entries;
- std::unique_ptr<ThreadLog> thread_log(
- new ThreadLog(base::Bind(&FlushEntries, base::Unretained(&entries))));
-
- thread_log->AddEntry(reinterpret_cast<void*>(0x2));
- thread_log->AddEntry(reinterpret_cast<void*>(0x3));
-
- // This should make the manager spawn its internal flush thread which will
- // wait for a notification before it starts doing some work.
- manager.AddLog(std::move(thread_log));
-
- EXPECT_EQ(0U, entries.size());
- // This will wake up the internal thread.
- wait_event.Signal();
- // Now it's our turn to wait until it performed the flush.
- notify_event.Wait();
-
- // The flush should have moved the data to the local vector of entries.
- EXPECT_EQ(2U, entries.size());
- ASSERT_EQ(2U, reinterpret_cast<uintptr_t>(entries[0].address));
- ASSERT_EQ(3U, reinterpret_cast<uintptr_t>(entries[1].address));
-}
-
-} // namespace
-} // namespace cygprofile
-
-// Custom runner implementation since base's one requires JNI on Android.
-int main(int argc, char** argv) {
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/tools/cygprofile/mergetraces.py b/tools/cygprofile/mergetraces.py
deleted file mode 100755
index 2ac8393..0000000
--- a/tools/cygprofile/mergetraces.py
+++ /dev/null
@@ -1,254 +0,0 @@
-#!/usr/bin/python
-# Copyright 2013 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.
-
-# Use: ../mergetraces.py `ls cyglog.* -Sr` > merged_cyglog
-
-""""Merge multiple logs files from different processes into a single log.
-
-Given two log files of execution traces, merge the traces into a single trace.
-Merging will use timestamps (i.e. the first two columns of logged calls) to
-create a single log that is an ordered trace of calls by both processes.
-"""
-
-import optparse
-import string
-import sys
-
-
-def ParseLogLines(lines):
- """Parse log file lines.
-
- Args:
- lines: lines from log file produced by profiled run
-
- Below is an example of a small log file:
- 5086e000-52e92000 r-xp 00000000 b3:02 51276 libchromeview.so
- secs usecs pid:threadid func
- START
- 1314897086 795828 3587:1074648168 0x509e105c
- 1314897086 795874 3587:1074648168 0x509e0eb4
- 1314897086 796326 3587:1074648168 0x509e0e3c
- 1314897086 796552 3587:1074648168 0x509e07bc
- END
-
- Returns:
- tuple conisiting of 1) an ordered list of the logged calls, as an array of
- fields, 2) the virtual start address of the library, used to compute the
- offset of the symbol in the library and 3) the virtual end address
- """
- call_lines = []
- vm_start = 0
- vm_end = 0
- dash_index = lines[0].find ('-')
- space_index = lines[0].find (' ')
- vm_start = int (lines[0][:dash_index], 16)
- vm_end = int (lines[0][dash_index+1:space_index], 16)
- for line in lines[2:]:
- line = line.strip()
- fields = line.split()
- call_lines.append (fields)
-
- return (call_lines, vm_start, vm_end)
-
-
-def HasDuplicates(calls):
- """Makes sure that calls are only logged once.
-
- Args:
- calls: list of calls logged
-
- Returns:
- boolean indicating if calls has duplicate calls
- """
- seen = set([])
- for call in calls:
- if call[3] in seen:
- return True
- seen.add(call[3])
- return False
-
-def CheckTimestamps(calls):
- """Prints warning to stderr if the call timestamps are not in order.
-
- Args:
- calls: list of calls logged
- """
- index = 0
- last_timestamp_secs = -1
- last_timestamp_us = -1
- while (index < len (calls)):
- timestamp_secs = int (calls[index][0])
- timestamp_us = int (calls[index][1])
- timestamp = (timestamp_secs * 1000000) + timestamp_us
- last_timestamp = (last_timestamp_secs * 1000000) + last_timestamp_us
- if (timestamp < last_timestamp):
- raise Exception("last_timestamp: " + str(last_timestamp_secs)
- + " " + str(last_timestamp_us) + " timestamp: "
- + str(timestamp_secs) + " " + str(timestamp_us) + "\n")
- last_timestamp_secs = timestamp_secs
- last_timestamp_us = timestamp_us
- index = index + 1
-
-
-def Convert(call_lines, start_address, end_address):
- """Converts the call addresses to static offsets and removes invalid calls.
-
- Removes profiled calls not in shared library using start and end virtual
- addresses, converts strings to integer values, coverts virtual addresses to
- address in shared library.
-
- Returns:
- list of calls as tuples (sec, usec, pid:tid, callee)
- """
- converted_calls = []
- call_addresses = set()
- for fields in call_lines:
- secs = int (fields[0])
- usecs = int (fields[1])
- callee = int (fields[3], 16)
- # Eliminate repetitions of the same function.
- if callee in call_addresses:
- continue
- # Eliminate small addresses. It should be safe to do so because these point
- # before the .text section (it is in .plt or earlier).
- # TODO(pasko): understand why __cyg_profile_func_enter may output a small
- # offset sometimes.
- if callee < start_address + 4096:
- sys.stderr.write('WARNING: ignoring small address: %s' %
- hex(callee - start_address))
- call_addresses.add(callee)
- continue
- if start_address <= callee < end_address:
- converted_calls.append((secs, usecs, fields[2], (callee - start_address)))
- call_addresses.add(callee)
- return converted_calls
-
-
-def Timestamp(trace_entry):
- return int (trace_entry[0]) * 1000000 + int(trace_entry[1])
-
-
-def AddTrace (tracemap, trace):
- """Adds a trace to the tracemap.
-
- Adds entries in the trace to the tracemap. All new calls will be added to
- the tracemap. If the calls already exist in the tracemap then they will be
- replaced if they happened sooner in the new trace.
-
- Args:
- tracemap: the tracemap
- trace: the trace
-
- """
- for trace_entry in trace:
- call = trace_entry[3]
- if (not call in tracemap) or (
- Timestamp(tracemap[call]) > Timestamp(trace_entry)):
- tracemap[call] = trace_entry
-
-
-def GroupByProcessAndThreadId(input_trace):
- """Returns an array of traces grouped by pid and tid.
-
- This is used to make the order of functions not depend on thread scheduling
- which can be greatly impacted when profiling is done with cygprofile. As a
- result each thread has its own contiguous segment of code (ordered by
- timestamp) and processes also have their code isolated (i.e. not interleaved).
- """
- def MakeTimestamp(sec, usec):
- return sec * 1000000 + usec
-
- def PidAndTidFromString(pid_and_tid):
- strings = pid_and_tid.split(':')
- return (int(strings[0]), int(strings[1]))
-
- tid_to_pid_map = {}
- pid_first_seen = {}
- tid_first_seen = {}
-
- for (sec, usec, pid_and_tid, _) in input_trace:
- (pid, tid) = PidAndTidFromString(pid_and_tid)
-
- # Make sure that thread IDs are unique since this is a property we rely on.
- if tid_to_pid_map.setdefault(tid, pid) != pid:
- raise Exception(
- 'Seen PIDs %d and %d for TID=%d. Thread-IDs must be unique' % (
- tid_to_pid_map[tid], pid, tid))
-
- if not pid in pid_first_seen:
- pid_first_seen[pid] = MakeTimestamp(sec, usec)
- if not tid in tid_first_seen:
- tid_first_seen[tid] = MakeTimestamp(sec, usec)
-
- def CompareEvents(event1, event2):
- (sec1, usec1, pid_and_tid, _) = event1
- (pid1, tid1) = PidAndTidFromString(pid_and_tid)
- (sec2, usec2, pid_and_tid, _) = event2
- (pid2, tid2) = PidAndTidFromString(pid_and_tid)
-
- pid_cmp = cmp(pid_first_seen[pid1], pid_first_seen[pid2])
- if pid_cmp != 0:
- return pid_cmp
- tid_cmp = cmp(tid_first_seen[tid1], tid_first_seen[tid2])
- if tid_cmp != 0:
- return tid_cmp
- return cmp(MakeTimestamp(sec1, usec1), MakeTimestamp(sec2, usec2))
-
- return sorted(input_trace, cmp=CompareEvents)
-
-
-def Main():
- """Merge two traces for code in specified library and write to stdout.
-
- Merges the two traces and coverts the virtual addresses to the offsets in the
- library. First line of merged trace has dummy virtual address of 0-ffffffff
- so that symbolizing the addresses uses the addresses in the log, since the
- addresses have already been converted to static offsets.
- """
- parser = optparse.OptionParser('usage: %prog trace1 ... traceN')
- (_, args) = parser.parse_args()
- if len(args) <= 1:
- parser.error('expected at least the following args: trace1 trace2')
-
- step = 0
-
- # Maps function addresses to their corresponding trace entry.
- tracemap = dict()
-
- for trace_file in args:
- step += 1
- sys.stderr.write(" " + str(step) + "/" + str(len(args)) +
- ": " + trace_file + ":\n")
-
- trace_lines = map(string.rstrip, open(trace_file).readlines())
- (trace_calls, trace_start, trace_end) = ParseLogLines(trace_lines)
- CheckTimestamps(trace_calls)
- sys.stderr.write("Len: " + str(len(trace_calls)) +
- ". Start: " + hex(trace_start) +
- ", end: " + hex(trace_end) + '\n')
-
- trace_calls = Convert(trace_calls, trace_start, trace_end)
- sys.stderr.write("Converted len: " + str(len(trace_calls)) + "\n")
-
- AddTrace(tracemap, trace_calls)
- sys.stderr.write("Merged len: " + str(len(tracemap)) + "\n")
-
- # Extract the resulting trace from the tracemap
- merged_trace = []
- for call in tracemap:
- merged_trace.append(tracemap[call])
- merged_trace.sort(key=Timestamp)
-
- grouped_trace = GroupByProcessAndThreadId(merged_trace)
-
- print "0-ffffffff r-xp 00000000 xx:00 00000 ./"
- print "secs\tusecs\tpid:threadid\tfunc"
- for call in grouped_trace:
- print (str(call[0]) + "\t" + str(call[1]) + "\t" + call[2] + "\t" +
- hex(call[3]))
-
-
-if __name__ == '__main__':
- Main()
diff --git a/tools/cygprofile/mergetraces_unittest.py b/tools/cygprofile/mergetraces_unittest.py
deleted file mode 100644
index de88137..0000000
--- a/tools/cygprofile/mergetraces_unittest.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright 2014 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.
-
-import unittest
-
-import mergetraces
-
-class GroupByProcessAndThreadIdTestBasic(unittest.TestCase):
- def runTest(self):
- # (sec, usec, 'pid:tid', function address).
- input_trace = [
- (100, 10, '2000:2001', 0x5),
- (100, 11, '2000:2001', 0x3),
- (100, 13, '2000:1999', 0x8),
- (100, 14, '2000:2000', 0x7),
- (120, 13, '2001:2003', 0x9),
- (150, 12, '2001:2004', 0x6),
- (180, 11, '2000:2000', 0x1),
- ]
-
- # Functions should be grouped by thread-id and PIDs should not be
- # interleaved.
- expected_trace = [
- (100, 10, '2000:2001', 0x5),
- (100, 11, '2000:2001', 0x3),
- (100, 13, '2000:1999', 0x8),
- (100, 14, '2000:2000', 0x7),
- (180, 11, '2000:2000', 0x1),
- (120, 13, '2001:2003', 0x9),
- (150, 12, '2001:2004', 0x6),
- ]
-
- grouped_trace = mergetraces.GroupByProcessAndThreadId(input_trace)
-
- self.assertEqual(grouped_trace, expected_trace)
-
-class GroupByProcessAndThreadIdFailsWithNonUniqueTIDs(unittest.TestCase):
- def runTest(self):
- # (sec, usec, 'pid:tid', function address).
- input_trace = [
- (100, 10, '1999:2001', 0x5),
- (100, 10, '1988:2001', 0x5),
- ]
-
- try:
- mergetraces.GroupByProcessAndThreadId(input_trace)
- except Exception:
- return
-
- self.fail('Multiple processes should not have a same thread-ID.')
diff --git a/tools/cygprofile/orderfile_generator_backend.py b/tools/cygprofile/orderfile_generator_backend.py
index 147a067..96348a5 100755
--- a/tools/cygprofile/orderfile_generator_backend.py
+++ b/tools/cygprofile/orderfile_generator_backend.py
@@ -250,7 +250,7 @@
"""Handles compilation of clank."""
def __init__(self, out_dir, step_recorder, arch, jobs, max_load, use_goma,
- goma_dir, lightweight_instrumentation):
+ goma_dir):
self._out_dir = out_dir
self._step_recorder = step_recorder
self._arch = arch
@@ -258,7 +258,6 @@
self._max_load = max_load
self._use_goma = use_goma
self._goma_dir = goma_dir
- self._lightweight_instrumentation = lightweight_instrumentation
lib_chrome_so_dir = 'lib.unstripped'
self.lib_chrome_so = os.path.join(
self._out_dir, 'Release', lib_chrome_so_dir, 'libchrome.so')
@@ -288,8 +287,6 @@
'use_goma=' + str(self._use_goma).lower(),
'use_order_profiling=' + str(instrumented).lower(),
]
- if instrumented and self._lightweight_instrumentation:
- args.append('use_lightweight_order_profiling=true')
if self._goma_dir:
args += ['goma_dir="%s"' % self._goma_dir]
@@ -420,8 +417,6 @@
generates an updated orderfile.
"""
_CLANK_REPO = os.path.join(constants.DIR_SOURCE_ROOT, 'clank')
- _MERGE_TRACES_SCRIPT = os.path.join(
- constants.DIR_SOURCE_ROOT, 'tools', 'cygprofile', 'mergetraces.py')
_CYGLOG_TO_ORDERFILE_SCRIPT = os.path.join(
constants.DIR_SOURCE_ROOT, 'tools', 'cygprofile',
'cyglog_to_orderfile.py')
@@ -460,18 +455,12 @@
if options.profile:
output_directory = os.path.join(self._instrumented_out_dir, 'Release')
host_cyglog_dir = os.path.join(output_directory, 'cyglog_data')
- # Only override the defaults when using lightweight instrumentation,
- # as the regular profiling code is likely too slow for these.
urls = [profile_android_startup.AndroidProfileTool.TEST_URL]
use_wpr = True
simulate_user = False
- if options.simulate_user and not options.lightweight_instrumentation:
- logging.error(
- '--simulate-user required --lightweight-instrumentation, ignoring.')
- if options.lightweight_instrumentation:
- urls = options.urls
- use_wpr = not options.no_wpr
- simulate_user = options.simulate_user
+ urls = options.urls
+ use_wpr = not options.no_wpr
+ simulate_user = options.simulate_user
self._profiler = profile_android_startup.AndroidProfileTool(
output_directory, host_cyglog_dir, use_wpr, urls, simulate_user)
@@ -486,27 +475,6 @@
assert os.path.isdir(constants.DIR_SOURCE_ROOT), 'No src directory found'
symbol_extractor.SetArchitecture(options.arch)
- def _RunCygprofileUnitTests(self):
- """Builds, deploys and runs cygprofile_unittests."""
- # There an no unittests (yet) for the lightweight instrumentation.
- # TODO(lizeb): Fix this.
- if self._options.lightweight_instrumentation:
- return
- tools_compiler = ClankCompiler(
- os.path.dirname(constants.GetOutDirectory()),
- self._step_recorder, self._options.arch, self._options.jobs,
- self._options.max_load, self._options.use_goma, self._options.goma_dir,
- self._options.lightweight_instrumentation)
- tools_compiler.Build(instrumented=False, target='android_tools')
- self._compiler.Build(instrumented=True, target='cygprofile_unittests')
-
- self._step_recorder.BeginStep('Deploy and run cygprofile_unittests')
- exit_code = self._profiler.RunCygprofileTests()
-
- if exit_code != 0:
- self._step_recorder.FailStep(
- 'cygprofile_unittests exited with non-0 status: %d' % exit_code)
-
@staticmethod
def _RemoveBlanks(src_file, dest_file):
"""A utility to remove blank lines from a file.
@@ -537,20 +505,14 @@
self._compiler.chrome_apk,
constants.PACKAGE_INFO['chrome'])
self._step_recorder.BeginStep('Process cyglog')
- if self._options.lightweight_instrumentation:
- assert os.path.exists(self._compiler.lib_chrome_so)
- offsets = process_profiles.GetReachedOffsetsFromDumpFiles(
- files, self._compiler.lib_chrome_so)
- if not offsets:
- raise Exception('No profiler offsets found in {}'.format(
- '\n'.join(files)))
- with open(self._MERGED_CYGLOG_FILENAME, 'w') as f:
- f.write('\n'.join(map(str, offsets)))
- else:
- with open(self._MERGED_CYGLOG_FILENAME, 'w') as merged_cyglog:
- self._step_recorder.RunCommand([self._MERGE_TRACES_SCRIPT] + files,
- constants.DIR_SOURCE_ROOT,
- stdout=merged_cyglog)
+ assert os.path.exists(self._compiler.lib_chrome_so)
+ offsets = process_profiles.GetReachedOffsetsFromDumpFiles(
+ files, self._compiler.lib_chrome_so)
+ if not offsets:
+ raise Exception('No profiler offsets found in {}'.format(
+ '\n'.join(files)))
+ with open(self._MERGED_CYGLOG_FILENAME, 'w') as f:
+ f.write('\n'.join(map(str, offsets)))
except Exception:
for f in files:
self._SaveForDebugging(f)
@@ -564,10 +526,7 @@
'--target-arch=' + self._options.arch,
'--native-library=' + self._compiler.lib_chrome_so,
'--output=' + self._GetUnpatchedOrderfileFilename()]
- if self._options.lightweight_instrumentation:
- command_args.append('--reached-offsets=' + self._MERGED_CYGLOG_FILENAME)
- else:
- command_args.append('--merged-cyglog=' + self._MERGED_CYGLOG_FILENAME)
+ command_args.append('--reached-offsets=' + self._MERGED_CYGLOG_FILENAME)
self._step_recorder.RunCommand(
[self._CYGLOG_TO_ORDERFILE_SCRIPT] + command_args)
except CommandError:
@@ -688,13 +647,9 @@
self._instrumented_out_dir,
self._step_recorder, self._options.arch, self._options.jobs,
self._options.max_load, self._options.use_goma,
- self._options.goma_dir,
- self._options.lightweight_instrumentation)
- self._RunCygprofileUnitTests()
- if self._options.lightweight_instrumentation:
- _EnsureOrderfileStartsWithAnchorSection(self._GetPathToOrderfile())
- self._compiler.CompileChromeApk(
- True, self._options.lightweight_instrumentation)
+ self._options.goma_dir)
+ _EnsureOrderfileStartsWithAnchorSection(self._GetPathToOrderfile())
+ self._compiler.CompileChromeApk(True)
self._GenerateAndProcessProfile()
self._MaybeArchiveOrderfile(self._GetUnpatchedOrderfileFilename())
profile_uploaded = True
@@ -710,8 +665,7 @@
self._compiler = ClankCompiler(
self._uninstrumented_out_dir, self._step_recorder,
self._options.arch, self._options.jobs, self._options.max_load,
- self._options.use_goma, self._options.goma_dir,
- self._options.lightweight_instrumentation)
+ self._options.use_goma, self._options.goma_dir)
self._compiler.CompileLibchrome(False)
self._PatchOrderfile()
# Because identical code folding is a bit different with and without
@@ -748,10 +702,6 @@
"""Creates and returns the argument parser."""
parser = argparse.ArgumentParser()
parser.add_argument(
- '--regular-instrumentation', action='store_false',
- dest='lightweight_instrumentation',
- help='Use the regular instrumentation path')
- parser.add_argument(
'--buildbot', action='store_true',
help='If true, the script expects to be run on a buildbot')
parser.add_argument(
diff --git a/tools/cygprofile/profile_android_startup.py b/tools/cygprofile/profile_android_startup.py
index ba96bce8..c71fb53 100755
--- a/tools/cygprofile/profile_android_startup.py
+++ b/tools/cygprofile/profile_android_startup.py
@@ -393,6 +393,9 @@
cyglog_dir = os.path.join(self._host_cyglog_dir, 'cyglog')
files = os.listdir(cyglog_dir)
+ if len(files) == 0:
+ raise NoCyglogDataError('No cyglog data was collected')
+
return [os.path.join(cyglog_dir, x) for x in files]