This commit is contained in:
2021-04-19 20:16:55 +02:00
commit a0ff94dca2
839 changed files with 198976 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
# 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.
def CheckChangeOnUpload(input_api, output_api):
return _CommonChecks(input_api, output_api)
def CheckChangeOnCommit(input_api, output_api):
return _CommonChecks(input_api, output_api)
def _CommonChecks(input_api, output_api):
results = []
results += input_api.RunTests(input_api.canned_checks.GetPylint(
input_api, output_api, extra_paths_list=_GetPathsToPrepend(input_api),
pylintrc='pylintrc'))
return results
def _GetPathsToPrepend(input_api):
project_dir = input_api.PresubmitLocalPath()
catapult_dir = input_api.os_path.join(project_dir, '..')
return [
project_dir,
input_api.os_path.join(catapult_dir, 'common', 'py_trace_event'),
input_api.os_path.join(catapult_dir, 'common', 'py_utils'),
input_api.os_path.join(catapult_dir, 'devil'),
input_api.os_path.join(catapult_dir, 'telemetry'),
input_api.os_path.join(catapult_dir, 'third_party', 'mock'),
input_api.os_path.join(catapult_dir, 'tracing'),
]

View File

@@ -0,0 +1,10 @@
<!-- 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.
-->
Systrace
========
Systrace provides command-line tools to analyze the performance of your
application. It currently includes
[Android Systrace](http://developer.android.com/tools/help/systrace.html).

View File

@@ -0,0 +1,29 @@
<!-- 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.
-->
atrace_helper is an optional binary which can be pushed onto the device running
systrace in order to enrich the traces with further details (memory, I/O, etc).
Which problem is it solving?
---------------------------
Some nice-to-have details are not present in the systrace, specifically:
- Memory snapshots of running processes (PSS/RSS).
- Periodic snapshotting of processes and thread names.
- File paths for filesystem events (today they report only inode numbers).
How is it solving it?
---------------------
atrace_helper is a small userspace binary which is meant to be pushed on the
device and run together with atrace by a dedicated tracing agent. When stopped,
the helper produces a JSON file which contains all the relevant details
(see --help). The JSON file is consumed by the TraceViewer importers and the
extra details are merged into the final model.
Build instructions
------------------
Building the binary requires the Android NDK to be installed. See
[Android NDK page](https://developer.android.com/ndk).
Once installed the binary can be just built as follows:
`$(NDK_HOME)/ndk-build`
The binary will be built in `libs/armeabi-v7a/`

View File

@@ -0,0 +1,7 @@
# 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.
APP_ABI := armeabi-v7a
APP_PLATFORM := android-21
APP_STL := c++_static

View File

@@ -0,0 +1,256 @@
// 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 "atrace_process_dump.h"
#include <inttypes.h>
#include <stdint.h>
#include <limits>
#include "file_utils.h"
#include "logging.h"
#include "procfs_utils.h"
namespace {
const int kMemInfoIntervalMs = 100; // 100ms-ish.
} // namespace
AtraceProcessDump::AtraceProcessDump() {
self_pid_ = static_cast<int>(getpid());
}
AtraceProcessDump::~AtraceProcessDump() {
}
void AtraceProcessDump::SetDumpInterval(int interval_ms) {
CHECK(interval_ms >= kMemInfoIntervalMs);
dump_interval_in_timer_ticks_ = interval_ms / kMemInfoIntervalMs;
// Approximately equals to kMemInfoIntervalMs.
int tick_interval_ms = interval_ms / dump_interval_in_timer_ticks_;
snapshot_timer_ = std::unique_ptr<time_utils::PeriodicTimer>(
new time_utils::PeriodicTimer(tick_interval_ms));
}
void AtraceProcessDump::RunAndPrintJson(FILE* stream) {
out_ = stream;
fprintf(out_, "{\"start_ts\": \"%" PRIu64 "\", \"snapshots\":[\n",
time_utils::GetTimestamp());
CHECK(snapshot_timer_);
snapshot_timer_->Start();
int tick_count = std::numeric_limits<int>::max();
if (dump_count_ > 0)
tick_count = dump_count_ * dump_interval_in_timer_ticks_;
for (int tick = 0; tick < tick_count; tick++) {
if (tick > 0) {
if (!snapshot_timer_->Wait())
break; // Interrupted by signal.
fprintf(out_, ",\n");
}
TakeAndSerializeMemInfo();
if (!(tick % dump_interval_in_timer_ticks_)) {
fprintf(out_, ",\n");
TakeGlobalSnapshot();
SerializeSnapshot();
}
fflush(out_);
}
fprintf(out_, "],\n");
SerializePersistentProcessInfo();
fprintf(out_, "}\n");
fflush(out_);
Cleanup();
}
void AtraceProcessDump::Stop() {
CHECK(snapshot_timer_);
snapshot_timer_->Stop();
}
void AtraceProcessDump::TakeGlobalSnapshot() {
snapshot_.clear();
snapshot_timestamp_ = time_utils::GetTimestamp();
file_utils::ForEachPidInProcPath("/proc", [this](int pid) {
// Skip if not regognized as a process.
if (!UpdatePersistentProcessInfo(pid))
return;
const ProcessInfo* process = processes_[pid].get();
// Snapshot can't be obtained for kernel workers.
if (process->in_kernel)
return;
ProcessSnapshot* process_snapshot = new ProcessSnapshot();
snapshot_[pid] = std::unique_ptr<ProcessSnapshot>(process_snapshot);
process_snapshot->pid = pid;
procfs_utils::ReadOomStats(process_snapshot);
procfs_utils::ReadPageFaultsAndCpuTimeStats(process_snapshot);
if (ShouldTakeFullDump(process)) {
process_snapshot->memory.ReadFullStats(pid);
} else {
process_snapshot->memory.ReadLightStats(pid);
}
if (graphics_stats_ && process->is_app) {
process_snapshot->memory.ReadGpuStats(pid);
}
});
}
bool AtraceProcessDump::UpdatePersistentProcessInfo(int pid) {
if (!processes_.count(pid)) {
if (procfs_utils::ReadTgid(pid) != pid)
return false;
processes_[pid] = procfs_utils::ReadProcessInfo(pid);
}
ProcessInfo* process = processes_[pid].get();
procfs_utils::ReadProcessThreads(process);
if (full_dump_mode_ == FullDumpMode::kOnlyWhitelisted &&
full_dump_whitelist_.count(process->name)) {
full_dump_whitelisted_pids_.insert(pid);
}
return true;
}
bool AtraceProcessDump::ShouldTakeFullDump(const ProcessInfo* process) {
if (full_dump_mode_ == FullDumpMode::kAllProcesses)
return !process->in_kernel && (process->pid != self_pid_);
if (full_dump_mode_ == FullDumpMode::kAllJavaApps)
return process->is_app;
if (full_dump_mode_ == FullDumpMode::kDisabled)
return false;
return full_dump_whitelisted_pids_.count(process->pid) > 0;
}
void AtraceProcessDump::SerializeSnapshot() {
fprintf(out_, "{\"ts\":\"%" PRIu64 "\",\"memdump\":{\n",
snapshot_timestamp_);
for (auto it = snapshot_.begin(); it != snapshot_.end();) {
const ProcessSnapshot* process = it->second.get();
const ProcessMemoryStats* mem = &process->memory;
fprintf(out_, "\"%d\":{", process->pid);
fprintf(out_, "\"vm\":%" PRIu64 ",\"rss\":%" PRIu64,
mem->virt_kb(), mem->rss_kb());
fprintf(out_, ",\"oom_sc\":%d,\"oom_sc_adj\":%d"
",\"min_flt\":%lu,\"maj_flt\":%lu"
",\"utime\":%lu,\"stime\":%lu",
process->oom_score, process->oom_score_adj,
process->minor_faults, process->major_faults,
process->utime, process->stime);
if (mem->full_stats_available()) {
fprintf(out_, ",\"pss\":%" PRIu64 ",\"swp\":%" PRIu64
",\"pc\":%" PRIu64 ",\"pd\":%" PRIu64
",\"sc\":%" PRIu64 ",\"sd\":%" PRIu64,
mem->pss_kb(), mem->swapped_kb(),
mem->private_clean_kb(), mem->private_dirty_kb(),
mem->shared_clean_kb(), mem->shared_dirty_kb());
}
if (mem->gpu_stats_available()) {
fprintf(out_, ",\"gpu_egl\":%" PRIu64 ",\"gpu_egl_pss\":%" PRIu64
",\"gpu_gl\":%" PRIu64 ",\"gpu_gl_pss\":%" PRIu64
",\"gpu_etc\":%" PRIu64 ",\"gpu_etc_pss\":%" PRIu64,
mem->gpu_graphics_kb(), mem->gpu_graphics_pss_kb(),
mem->gpu_gl_kb(), mem->gpu_gl_pss_kb(),
mem->gpu_other_kb(), mem->gpu_other_pss_kb());
}
// Memory maps are too heavy to serialize. Enable only in whitelisting mode.
if (print_smaps_ &&
full_dump_mode_ == FullDumpMode::kOnlyWhitelisted &&
mem->full_stats_available() &&
full_dump_whitelisted_pids_.count(process->pid)) {
fprintf(out_, ", \"mmaps\":[");
size_t n_mmaps = mem->mmaps_count();
for (size_t k = 0; k < n_mmaps; ++k) {
const ProcessMemoryStats::MmapInfo* mm = mem->mmap(k);
fprintf(out_,
"{\"vm\":\"%" PRIx64 "-%" PRIx64 "\","
"\"file\":\"%s\",\"flags\":\"%s\","
"\"pss\":%" PRIu64 ",\"rss\":%" PRIu64 ",\"swp\":%" PRIu64 ","
"\"pc\":%" PRIu64 ",\"pd\":%" PRIu64 ","
"\"sc\":%" PRIu64 ",\"sd\":%" PRIu64 "}",
mm->start_addr, mm->end_addr,
mm->mapped_file, mm->prot_flags,
mm->pss_kb, mm->rss_kb, mm->swapped_kb,
mm->private_clean_kb, mm->private_dirty_kb,
mm->shared_clean_kb, mm->shared_dirty_kb);
if (k < n_mmaps - 1)
fprintf(out_, ", ");
}
fprintf(out_, "]");
}
if (++it != snapshot_.end())
fprintf(out_, "},\n");
else
fprintf(out_, "}}\n");
}
fprintf(out_, "}");
}
void AtraceProcessDump::SerializePersistentProcessInfo() {
fprintf(out_, "\"processes\":{");
for (auto it = processes_.begin(); it != processes_.end();) {
const ProcessInfo* process = it->second.get();
fprintf(out_, "\"%d\":{", process->pid);
fprintf(out_, "\"name\":\"%s\"", process->name);
if (!process->in_kernel) {
fprintf(out_, ",\"exe\":\"%s\",", process->exe);
fprintf(out_, "\"threads\":{\n");
const auto threads = &process->threads;
for (auto thread_it = threads->begin(); thread_it != threads->end();) {
const ThreadInfo* thread = &(thread_it->second);
fprintf(out_, "\"%d\":{", thread->tid);
fprintf(out_, "\"name\":\"%s\"", thread->name);
if (++thread_it != threads->end())
fprintf(out_, "},\n");
else
fprintf(out_, "}\n");
}
fprintf(out_, "}");
}
if (++it != processes_.end())
fprintf(out_, "},\n");
else
fprintf(out_, "}\n");
}
fprintf(out_, "}");
}
void AtraceProcessDump::TakeAndSerializeMemInfo() {
std::map<std::string, uint64_t> mem_info;
CHECK(procfs_utils::ReadMemInfoStats(&mem_info));
fprintf(out_, "{\"ts\":\"%" PRIu64 "\",\"meminfo\":{\n",
time_utils::GetTimestamp());
for (auto it = mem_info.begin(); it != mem_info.end(); ++it) {
if (it != mem_info.begin())
fprintf(out_, ",");
fprintf(out_, "\"%s\":%" PRIu64, it->first.c_str(), it->second);
}
fprintf(out_, "}}");
}
void AtraceProcessDump::Cleanup() {
processes_.clear();
snapshot_.clear();
full_dump_whitelisted_pids_.clear();
snapshot_timer_ = nullptr;
}

View File

@@ -0,0 +1,82 @@
// 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.
#ifndef ATRACE_PROCESS_DUMP_H_
#define ATRACE_PROCESS_DUMP_H_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory>
#include <set>
#include <string>
#include "logging.h"
#include "process_info.h"
#include "time_utils.h"
// Program that collects processes, thread names, per-process memory stats and
// other minor metrics from /proc filesystem. It's aimed to extend systrace
// with more actionable number to hit performance issues.
class AtraceProcessDump {
public:
enum FullDumpMode {
kDisabled,
kAllProcesses,
kAllJavaApps,
kOnlyWhitelisted,
};
AtraceProcessDump();
~AtraceProcessDump();
void RunAndPrintJson(FILE* stream);
void Stop();
void SetDumpInterval(int interval_ms);
// Negative number or zero means unlimited number of dumps.
void set_dump_count(int count) { dump_count_ = count; }
void set_full_dump_mode(FullDumpMode mode) { full_dump_mode_ = mode; }
void set_full_dump_whitelist(const std::set<std::string> &whitelist) {
CHECK(full_dump_mode_ == FullDumpMode::kOnlyWhitelisted);
full_dump_whitelist_ = whitelist;
}
void enable_graphics_stats() { graphics_stats_ = true; }
void enable_print_smaps() { print_smaps_ = true; }
private:
AtraceProcessDump(const AtraceProcessDump&) = delete;
void operator=(const AtraceProcessDump&) = delete;
using ProcessMap = std::map<int, std::unique_ptr<ProcessInfo>>;
using ProcessSnapshotMap = std::map<int, std::unique_ptr<ProcessSnapshot>>;
void TakeGlobalSnapshot();
void TakeAndSerializeMemInfo();
bool UpdatePersistentProcessInfo(int pid);
bool ShouldTakeFullDump(const ProcessInfo* process);
void SerializeSnapshot();
void SerializePersistentProcessInfo();
void Cleanup();
int self_pid_;
int dump_count_;
bool graphics_stats_ = false;
bool print_smaps_ = false;
FullDumpMode full_dump_mode_ = FullDumpMode::kDisabled;
std::set<std::string> full_dump_whitelist_;
FILE* out_;
ProcessMap processes_;
ProcessSnapshotMap snapshot_;
uint64_t snapshot_timestamp_;
std::set<int> full_dump_whitelisted_pids_;
std::unique_ptr<time_utils::PeriodicTimer> snapshot_timer_;
int dump_interval_in_timer_ticks_;
};
#endif // ATRACE_PROCESS_DUMP_H_

View File

@@ -0,0 +1,117 @@
// 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 "file_utils.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
namespace {
bool IsNumeric(const char* str) {
if (!str[0])
return false;
for (const char* c = str; *c; c++) {
if (!isdigit(*c))
return false;
}
return true;
}
} // namespace
namespace file_utils {
void ForEachPidInProcPath(const char* proc_path,
std::function<void(int)> predicate) {
DIR* root_dir = opendir(proc_path);
ScopedDir autoclose(root_dir);
struct dirent* child_dir;
while ((child_dir = readdir(root_dir))) {
if (child_dir->d_type != DT_DIR || !IsNumeric(child_dir->d_name))
continue;
predicate(atoi(child_dir->d_name));
}
}
ssize_t ReadFile(const char* path, char* buf, size_t length) {
buf[0] = '\0';
int fd = open(path, O_RDONLY);
if (fd < 0 && errno == ENOENT)
return -1;
ScopedFD autoclose(fd);
size_t tot_read = 0;
do {
ssize_t rsize = read(fd, buf + tot_read, length - tot_read);
if (rsize == 0)
break;
if (rsize == -1 && errno == EINTR)
continue;
else if (rsize < 0)
return -1;
tot_read += static_cast<size_t>(rsize);
} while (tot_read < length);
buf[tot_read < length ? tot_read : length - 1] = '\0';
return tot_read;
}
bool ReadFileTrimmed(const char* path, char* buf, size_t length) {
ssize_t rsize = ReadFile(path, buf, length);
if (rsize < 0)
return false;
for (ssize_t i = 0; i < rsize; i++) {
const char c = buf[i];
if (c == '\0' || c == '\r' || c == '\n') {
buf[i] = '\0';
break;
}
buf[i] = isprint(c) ? c : '?';
}
return true;
}
ssize_t ReadProcFile(int pid, const char* proc_file, char* buf, size_t length) {
char proc_path[128];
snprintf(proc_path, sizeof(proc_path), "/proc/%d/%s", pid, proc_file);
return ReadFile(proc_path, buf, length);
}
// Reads a single-line proc file, stripping out any \0, \r, \n and replacing
// non-printable charcters with '?'.
bool ReadProcFileTrimmed(int pid,
const char* proc_file,
char* buf,
size_t length) {
char proc_path[128];
snprintf(proc_path, sizeof(proc_path), "/proc/%d/%s", pid, proc_file);
return ReadFileTrimmed(proc_path, buf, length);
}
LineReader::LineReader(char* buf, size_t size)
: ptr_(buf), end_(buf + size) {
}
LineReader::~LineReader() {
}
const char* LineReader::NextLine() {
if (ptr_ >= end_)
return nullptr;
const char* cur = ptr_;
char* next = strchr(ptr_, '\n');
if (next) {
*next = '\0';
ptr_ = next + 1;
} else {
ptr_ = end_;
}
return cur;
}
} // namespace file_utils

View File

@@ -0,0 +1,67 @@
// 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.
#ifndef FILE_UTILS_H_
#define FILE_UTILS_H_
#include <dirent.h>
#include <sys/types.h>
#include <unistd.h>
#include <functional>
#include <map>
#include <memory>
#include "logging.h"
namespace file_utils {
// RAII classes for auto-releasing fd/dirs.
template <typename RESOURCE_TYPE, int (*CLOSE_FN)(RESOURCE_TYPE)>
struct ScopedResource {
explicit ScopedResource(RESOURCE_TYPE r) : r_(r) { CHECK(r); }
~ScopedResource() { CLOSE_FN(r_); }
RESOURCE_TYPE r_;
};
using ScopedFD = ScopedResource<int, close>;
using ScopedDir = ScopedResource<DIR*, closedir>;
// Invokes predicate(pid) for each folder in |proc_path|/[0-9]+ which has
// a numeric name (typically pids and tids).
void ForEachPidInProcPath(const char* proc_path,
std::function<void(int)> predicate);
// Reads the contents of |path| fully into |buf| up to |length| chars.
// |buf| is guaranteed to be null terminated.
ssize_t ReadFile(const char* path, char* buf, size_t length);
// Reads a single-line file, stripping out any \0, \r, \n and replacing
// non-printable charcters with '?'. |buf| is guaranteed to be null terminated.
bool ReadFileTrimmed(const char* path, char* buf, size_t length);
// Convenience wrappers for /proc/|pid|/|proc_file| paths.
ssize_t ReadProcFile(int pid, const char* proc_file, char* buf, size_t length);
bool ReadProcFileTrimmed(int pid,
const char* proc_file,
char* buf,
size_t length);
// Takes a C string buffer and chunks it into lines without creating any
// copies. It modifies the original buffer, by replacing \n with \0.
class LineReader {
public:
LineReader(char* buf, size_t size);
~LineReader();
const char* NextLine();
private:
char* ptr_;
char* end_;
};
} // namespace file_utils
#endif // FILE_UTILS_H_

View File

@@ -0,0 +1,142 @@
// 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 "libmemtrack_wrapper.h"
#include <dlfcn.h>
#include "logging.h"
namespace {
// Init memtrack service. Removed in the latest version.
int (*memtrack_init)(void);
// Allocate and dispose memory stats.
libmemtrack_proc* (*memtrack_proc_new)(void);
void (*memtrack_proc_destroy)(libmemtrack_proc* p);
// Query memory stats for given process.
int (*memtrack_proc_get)(libmemtrack_proc* p, pid_t pid);
// Since memory stats is opaque structure, there are helpers to parse it.
ssize_t (*memtrack_proc_graphics_total)(libmemtrack_proc* p);
ssize_t (*memtrack_proc_graphics_pss)(libmemtrack_proc* p);
ssize_t (*memtrack_proc_gl_total)(libmemtrack_proc* p);
ssize_t (*memtrack_proc_gl_pss)(libmemtrack_proc* p);
ssize_t (*memtrack_proc_other_total)(libmemtrack_proc* p);
ssize_t (*memtrack_proc_other_pss)(libmemtrack_proc* p);
typedef ssize_t (*libmemtrack_getter_t)(libmemtrack_proc*);
bool g_initialized = false;
bool g_broken = false;
template <typename T>
void Import(T** func, void* lib, const char* name) {
*(reinterpret_cast<void**>(func)) = dlsym(lib, name);
}
bool ImportLibmemtrackSymbols(void* handle) {
Import(&memtrack_init, handle, "memtrack_init");
Import(&memtrack_proc_new, handle, "memtrack_proc_new");
Import(&memtrack_proc_destroy, handle, "memtrack_proc_destroy");
Import(&memtrack_proc_get, handle, "memtrack_proc_get");
Import(&memtrack_proc_graphics_total, handle, "memtrack_proc_graphics_total");
Import(&memtrack_proc_graphics_pss, handle, "memtrack_proc_graphics_pss");
Import(&memtrack_proc_gl_total, handle, "memtrack_proc_gl_total");
Import(&memtrack_proc_gl_pss, handle, "memtrack_proc_gl_pss");
Import(&memtrack_proc_other_total, handle, "memtrack_proc_other_total");
Import(&memtrack_proc_other_pss, handle, "memtrack_proc_other_pss");
if (!memtrack_proc_new || !memtrack_proc_destroy || !memtrack_proc_get) {
LogError("Couldn't use libmemtrack. Probably it's API has been changed.");
return false;
}
// Initialization is required on pre-O Android.
if (memtrack_init && memtrack_init() != 0) {
LogError("Failed to initialize libmemtrack. "
"Probably implementation is missing in the ROM.");
return false;
}
return true;
}
bool LazyOpenLibmemtrack() {
if (g_initialized)
return true;
if (g_broken)
return false;
void *handle = dlopen("libmemtrack.so", RTLD_GLOBAL | RTLD_NOW);
if (handle == nullptr) {
LogError("Failed to open libmemtrack library.");
g_broken = true;
return false;
}
if (!ImportLibmemtrackSymbols(handle)) {
dlclose(handle);
g_broken = true;
return false;
}
g_initialized = true;
return true;
}
uint64_t GetOrZero(libmemtrack_getter_t getter, libmemtrack_proc* proc) {
if (!getter || !proc)
return 0;
return static_cast<uint64_t>(getter(proc));
}
} // namespace
MemtrackProc::MemtrackProc(int pid) {
if (!LazyOpenLibmemtrack())
return;
proc_ = memtrack_proc_new();
if (!proc_) {
LogError("Failed to create libmemtrack proc. "
"Probably it's API has been changed.");
return;
}
if (memtrack_proc_get(proc_, pid) != 0) {
// Don't log an error since not every process has memtrack stats.
memtrack_proc_destroy(proc_);
proc_ = nullptr;
}
}
MemtrackProc::~MemtrackProc() {
if (proc_)
memtrack_proc_destroy(proc_);
}
uint64_t MemtrackProc::graphics_total() const {
return GetOrZero(memtrack_proc_graphics_total, proc_);
}
uint64_t MemtrackProc::graphics_pss() const {
return GetOrZero(memtrack_proc_graphics_pss, proc_);
}
uint64_t MemtrackProc::gl_total() const {
return GetOrZero(memtrack_proc_gl_total, proc_);
}
uint64_t MemtrackProc::gl_pss() const {
return GetOrZero(memtrack_proc_gl_pss, proc_);
}
uint64_t MemtrackProc::other_total() const {
return GetOrZero(memtrack_proc_other_total, proc_);
}
uint64_t MemtrackProc::other_pss() const {
return GetOrZero(memtrack_proc_other_pss, proc_);
}

View File

@@ -0,0 +1,39 @@
// 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.
#ifndef LIBMEMTRACK_WRAPPER_H_
#define LIBMEMTRACK_WRAPPER_H_
#include <stdint.h>
// Wrapper on top of libmemtrack API.
// Opaque structure with memory stats.
// See $ANDROID/system/core/libmemtrack/include/memtrack/memtrack.h for details.
struct libmemtrack_proc;
// These numbers are vendor-specific and can't be trusted as a stable metric
// across different hardware or driver versions.
class MemtrackProc {
public:
explicit MemtrackProc(int pid);
~MemtrackProc();
uint64_t graphics_total() const;
uint64_t graphics_pss() const;
uint64_t gl_total() const;
uint64_t gl_pss() const;
uint64_t other_total() const;
uint64_t other_pss() const;
bool has_errors() const { return proc_ == nullptr; };
private:
MemtrackProc(const MemtrackProc&) = delete;
void operator=(const MemtrackProc&) = delete;
libmemtrack_proc* proc_ = nullptr;
};
#endif // LIBMEMTRACK_WRAPPER_H_

View File

@@ -0,0 +1,36 @@
// 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.
#ifndef LOGGING_H_
#define LOGGING_H_
#include <android/log.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CHECK_ARGS(COND, ERR) \
"FAILED CHECK(%s) @ %s:%d (errno: %s)\n", #COND, __FILE__, __LINE__, \
strerror(ERR)
#define CHECK(x) \
do { \
if (!(x)) { \
const int e = errno; \
__android_log_print(ANDROID_LOG_FATAL, "atrace_helper", \
CHECK_ARGS(x, e)); \
fprintf(stderr, "\n" CHECK_ARGS(x, e)); \
fflush(stderr); \
abort(); \
} \
} while (0)
inline void LogError(const char* message) {
__android_log_write(ANDROID_LOG_ERROR, "atrace_helper", message);
fprintf(stderr, "\n%s\n", message);
fflush(stderr);
}
#endif // LOGGING_H_

View File

@@ -0,0 +1,134 @@
// 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 <inttypes.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory>
#include <set>
#include <string>
#include <sstream>
#include "atrace_process_dump.h"
#include "logging.h"
namespace {
std::unique_ptr<AtraceProcessDump> g_prog;
void ParseFullDumpConfig(const std::string& config, AtraceProcessDump* prog) {
using FullDumpMode = AtraceProcessDump::FullDumpMode;
if (config == "all") {
prog->set_full_dump_mode(FullDumpMode::kAllProcesses);
} else if (config == "apps") {
prog->set_full_dump_mode(FullDumpMode::kAllJavaApps);
} else {
std::set<std::string> whitelist;
std::istringstream ss(config);
std::string entry;
while (std::getline(ss, entry, ',')) {
whitelist.insert(entry);
}
if (whitelist.empty())
return;
prog->set_full_dump_mode(FullDumpMode::kOnlyWhitelisted);
prog->set_full_dump_whitelist(whitelist);
}
}
} // namespace
int main(int argc, char** argv) {
if (argc == 2 && !strcmp(argv[1], "--echo-ts")) {
// Used by clock sync marker to correct the difference between
// Linux monotonic clocks on the device and host.
printf("%" PRIu64 "\n", time_utils::GetTimestamp());
return 0;
}
bool background = false;
int dump_interval_ms = 5000;
char out_file[PATH_MAX] = {};
bool dump_to_file = false;
int count = -1;
AtraceProcessDump* prog = new AtraceProcessDump();
g_prog = std::unique_ptr<AtraceProcessDump>(prog);
if (geteuid()) {
fprintf(stderr, "Must run as root\n");
exit(EXIT_FAILURE);
}
int opt;
while ((opt = getopt(argc, argv, "bm:gst:o:c:")) != -1) {
switch (opt) {
case 'b':
background = true;
break;
case 'm':
ParseFullDumpConfig(optarg, prog);
break;
case 'g':
prog->enable_graphics_stats();
break;
case 's':
prog->enable_print_smaps();
break;
case 't':
dump_interval_ms = atoi(optarg);
CHECK(dump_interval_ms > 0);
break;
case 'c':
count = atoi(optarg);
CHECK(count > 0);
break;
case 'o':
strncpy(out_file, optarg, sizeof(out_file));
dump_to_file = true;
break;
default:
fprintf(stderr,
"Usage: %s [-b] [-m full_dump_filter] [-g] [-s] "
"[-t dump_interval_ms] "
"[-c dumps_count] [-o out.json]\n",
argv[0]);
exit(EXIT_FAILURE);
}
}
prog->set_dump_count(count);
prog->SetDumpInterval(dump_interval_ms);
FILE* out_stream = stdout;
char tmp_file[PATH_MAX];
if (dump_to_file) {
unlink(out_file);
sprintf(tmp_file, "%s.tmp", out_file);
out_stream = fopen(tmp_file, "w");
CHECK(out_stream);
}
if (background) {
if (!dump_to_file) {
fprintf(stderr, "-b requires -o for output dump path.\n");
exit(EXIT_FAILURE);
}
printf("Continuing in background. kill -TERM to terminate the daemon.\n");
CHECK(daemon(0 /* nochdir */, 0 /* noclose */) == 0);
}
auto on_exit = [](int) { g_prog->Stop(); };
signal(SIGINT, on_exit);
signal(SIGTERM, on_exit);
prog->RunAndPrintJson(out_stream);
fclose(out_stream);
if (dump_to_file)
rename(tmp_file, out_file);
}

View File

@@ -0,0 +1,40 @@
// 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.
#ifndef PROCESS_INFO_H_
#define PROCESS_INFO_H_
#include <map>
#include "process_memory_stats.h"
struct ThreadInfo {
int tid;
char name[16];
};
struct ProcessInfo {
int pid;
bool in_kernel;
bool is_app;
char name[256];
char exe[256];
std::map<int, ThreadInfo> threads;
};
struct ProcessSnapshot {
int pid;
ProcessMemoryStats memory;
// OOM badness and tolerance (oom_adj is deprecated).
int oom_score;
int oom_score_adj;
// Page faults.
unsigned long minor_faults;
unsigned long major_faults;
// Time spent in userspace and in the kernel.
unsigned long utime;
unsigned long stime;
};
#endif // PROCESS_INFO_H_

View File

@@ -0,0 +1,139 @@
// 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 "process_memory_stats.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory>
#include "file_utils.h"
#include "libmemtrack_wrapper.h"
#include "logging.h"
namespace {
const int kKbPerPage = 4;
const char kRss[] = "Rss";
const char kPss[] = "Pss";
const char kSwap[] = "Swap";
const char kSharedClean[] = "Shared_Clean";
const char kSharedDirty[] = "Shared_Dirty";
const char kPrivateClean[] = "Private_Clean";
const char kPrivateDirty[] = "Private_Dirty";
bool ReadSmapsMetric(
const char* line, const char* metric, int metric_size, uint64_t* res) {
if (strncmp(line, metric, metric_size - 1))
return false;
if (line[metric_size - 1] != ':')
return false;
*res = strtoull(line + metric_size, nullptr, 10);
return true;
}
} // namespace
bool ProcessMemoryStats::ReadLightStats(int pid) {
char buf[64];
if (file_utils::ReadProcFile(pid, "statm", buf, sizeof(buf)) <= 0)
return false;
uint32_t vm_size_pages;
uint32_t rss_pages;
int res = sscanf(buf, "%u %u", &vm_size_pages, &rss_pages);
CHECK(res == 2);
rss_kb_ = rss_pages * kKbPerPage;
virt_kb_ = vm_size_pages * kKbPerPage;
return true;
}
bool ProcessMemoryStats::ReadFullStats(int pid) {
const size_t kBufSize = 8u * 1024 * 1024;
std::unique_ptr<char[]> buf(new char[kBufSize]);
ssize_t rsize = file_utils::ReadProcFile(pid, "smaps", &buf[0], kBufSize);
if (rsize <= 0)
return false;
MmapInfo* last_mmap_entry = nullptr;
std::unique_ptr<MmapInfo> new_mmap(new MmapInfo());
CHECK(mmaps_.empty());
CHECK(rss_kb_ == 0);
// Iterate over all lines in /proc/PID/smaps.
file_utils::LineReader rd(&buf[0], rsize);
for (const char* line = rd.NextLine(); line; line = rd.NextLine()) {
if (!line[0])
continue;
// Performance optimization (hack).
// Any header line starts with lowercase hex digit but subsequent lines
// start with uppercase letter.
if (line[0] < 'A' || line[0] > 'Z') {
// Note that the mapped file name ([stack]) is optional and won't be
// present on anonymous memory maps (hence res >= 3 below).
int res = sscanf(line,
"%" PRIx64 "-%" PRIx64 " %4s %*" PRIx64 " %*[:0-9a-f] "
"%*[0-9a-f]%*[ \t]%127[^\n]",
&new_mmap->start_addr, &new_mmap->end_addr, new_mmap->prot_flags,
new_mmap->mapped_file);
last_mmap_entry = new_mmap.get();
CHECK(new_mmap->end_addr >= new_mmap->start_addr);
new_mmap->virt_kb =
(new_mmap->end_addr - new_mmap->start_addr) / 1024;
if (res == 3)
new_mmap->mapped_file[0] = '\0';
virt_kb_ += new_mmap->virt_kb;
mmaps_.push_back(std::move(new_mmap));
new_mmap.reset(new MmapInfo());
} else {
// The current line is a metrics line within a mmap entry, e.g.:
// Size: 4 kB
uint64_t size = 0;
CHECK(last_mmap_entry);
if (ReadSmapsMetric(line, kRss, sizeof(kRss), &size)) {
last_mmap_entry->rss_kb = size;
rss_kb_ += size;
} else if (ReadSmapsMetric(line, kPss, sizeof(kPss), &size)) {
last_mmap_entry->pss_kb = size;
pss_kb_ += size;
} else if (ReadSmapsMetric(line, kSwap, sizeof(kSwap), &size)) {
last_mmap_entry->swapped_kb = size;
swapped_kb_ += size;
} else if (ReadSmapsMetric(
line, kSharedClean, sizeof(kSharedClean), &size)) {
last_mmap_entry->shared_clean_kb = size;
shared_clean_kb_ += size;
} else if (ReadSmapsMetric(
line, kSharedDirty, sizeof(kSharedDirty), &size)) {
last_mmap_entry->shared_dirty_kb = size;
shared_dirty_kb_ += size;
} else if (ReadSmapsMetric(
line, kPrivateClean, sizeof(kPrivateClean), &size)) {
last_mmap_entry->private_clean_kb = size;
private_clean_kb_ += size;
} else if (ReadSmapsMetric(
line, kPrivateDirty, sizeof(kPrivateDirty), &size)) {
last_mmap_entry->private_dirty_kb = size;
private_dirty_kb_ += size;
}
}
}
full_stats_ = true;
return true;
}
bool ProcessMemoryStats::ReadGpuStats(int pid) {
MemtrackProc mt(pid);
gpu_graphics_kb_ = mt.graphics_total() / 1024;
gpu_graphics_pss_kb_ = mt.graphics_pss() / 1024;
gpu_gl_kb_ = mt.gl_total() / 1024;
gpu_gl_pss_kb_ = mt.gl_pss() / 1024;
gpu_other_kb_ = mt.other_total() / 1024;
gpu_other_pss_kb_ = mt.other_pss() / 1024;
gpu_stats_ = !mt.has_errors() &&
(gpu_graphics_kb_ != 0 || gpu_gl_kb_ != 0 || gpu_other_kb_ != 0);
return gpu_stats_;
}

View File

@@ -0,0 +1,91 @@
// 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.
#ifndef PROCESS_MEMORY_STATS_H_
#define PROCESS_MEMORY_STATS_H_
#include <stdint.h>
#include <memory>
#include <vector>
// Reads process memory stats from /proc/pid/{statm,smaps}.
class ProcessMemoryStats {
public:
struct MmapInfo {
char mapped_file[128] = {};
char prot_flags[5] = {};
uint64_t start_addr = 0;
uint64_t end_addr = 0;
uint64_t virt_kb = 0;
uint64_t pss_kb = 0; // Proportional Set Size.
uint64_t rss_kb = 0; // Resident Set Size.
uint64_t private_clean_kb = 0;
uint64_t private_dirty_kb = 0;
uint64_t shared_clean_kb = 0;
uint64_t shared_dirty_kb = 0;
uint64_t swapped_kb = 0;
};
ProcessMemoryStats() {}
bool ReadLightStats(int pid);
bool ReadFullStats(int pid);
bool ReadGpuStats(int pid);
// Available after ReadLightStats().
uint64_t virt_kb() const { return virt_kb_; }
uint64_t rss_kb() const { return rss_kb_; }
// Available after ReadFullStats().
bool full_stats_available() const { return full_stats_; }
uint64_t pss_kb() const { return pss_kb_; }
uint64_t private_clean_kb() const { return private_clean_kb_; }
uint64_t private_dirty_kb() const { return private_dirty_kb_; }
uint64_t shared_clean_kb() const { return shared_clean_kb_; }
uint64_t shared_dirty_kb() const { return shared_dirty_kb_; }
uint64_t swapped_kb() const { return swapped_kb_; }
// Available after ReadMemtrackStats().
bool gpu_stats_available() const { return gpu_stats_; }
uint64_t gpu_graphics_kb() const { return gpu_graphics_kb_; }
uint64_t gpu_graphics_pss_kb() const { return gpu_graphics_pss_kb_; }
uint64_t gpu_gl_kb() const { return gpu_gl_kb_; }
uint64_t gpu_gl_pss_kb() const { return gpu_gl_pss_kb_; }
uint64_t gpu_other_kb() const { return gpu_other_kb_; }
uint64_t gpu_other_pss_kb() const { return gpu_other_pss_kb_; }
size_t mmaps_count() const { return mmaps_.size(); }
const MmapInfo* mmap(size_t index) const { return mmaps_[index].get(); }
private:
ProcessMemoryStats(const ProcessMemoryStats&) = delete;
void operator=(const ProcessMemoryStats&) = delete;
// Light stats.
uint64_t virt_kb_ = 0;
uint64_t rss_kb_ = 0;
// Full stats.
bool full_stats_ = false;
uint64_t pss_kb_ = 0;
uint64_t private_clean_kb_ = 0;
uint64_t private_dirty_kb_ = 0;
uint64_t shared_clean_kb_ = 0;
uint64_t shared_dirty_kb_ = 0;
uint64_t swapped_kb_ = 0;
// Graphics stats.
bool gpu_stats_ = false;
uint64_t gpu_graphics_kb_ = 0;
uint64_t gpu_graphics_pss_kb_ = 0;
uint64_t gpu_gl_kb_ = 0;
uint64_t gpu_gl_pss_kb_ = 0;
uint64_t gpu_other_kb_ = 0;
uint64_t gpu_other_pss_kb_ = 0;
std::vector<std::unique_ptr<const MmapInfo>> mmaps_;
};
#endif // PROCESS_MEMORY_STATS_H_

View File

@@ -0,0 +1,136 @@
// 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 "procfs_utils.h"
#include <stdio.h>
#include <string.h>
#include "file_utils.h"
#include "logging.h"
using file_utils::ForEachPidInProcPath;
using file_utils::ReadProcFile;
using file_utils::ReadProcFileTrimmed;
namespace procfs_utils {
namespace {
const char kJavaAppPrefix[] = "/system/bin/app_process";
const char kZygotePrefix[] = "zygote";
inline void ReadProcString(int pid, const char* path, char* buf, size_t size) {
if (!file_utils::ReadProcFileTrimmed(pid, path, buf, size))
buf[0] = '\0';
}
inline void ReadExePath(int pid, char* buf, size_t size) {
char exe_path[64];
sprintf(exe_path, "/proc/%d/exe", pid);
ssize_t res = readlink(exe_path, buf, size - 1);
if (res >= 0)
buf[res] = '\0';
else
buf[0] = '\0';
}
inline bool IsApp(const char* name, const char* exe) {
return strncmp(exe, kJavaAppPrefix, sizeof(kJavaAppPrefix) - 1) == 0 &&
strncmp(name, kZygotePrefix, sizeof(kZygotePrefix) - 1) != 0;
}
} // namespace
int ReadTgid(int pid) {
static const char kTgid[] = "\nTgid:";
char buf[512];
ssize_t rsize = ReadProcFile(pid, "status", buf, sizeof(buf));
if (rsize <= 0)
return -1;
const char* tgid_line = strstr(buf, kTgid);
CHECK(tgid_line);
return atoi(tgid_line + sizeof(kTgid) - 1);
}
std::unique_ptr<ProcessInfo> ReadProcessInfo(int pid) {
ProcessInfo* process = new ProcessInfo();
process->pid = pid;
ReadProcString(pid, "cmdline", process->name, sizeof(process->name));
if (process->name[0] != 0) {
ReadExePath(pid, process->exe, sizeof(process->exe));
process->is_app = IsApp(process->name, process->exe);
} else {
ReadProcString(pid, "comm", process->name, sizeof(process->name));
CHECK(process->name[0]);
process->in_kernel = true;
}
return std::unique_ptr<ProcessInfo>(process);
}
void ReadProcessThreads(ProcessInfo* process) {
if (process->in_kernel)
return;
char tasks_path[64];
sprintf(tasks_path, "/proc/%d/task", process->pid);
ForEachPidInProcPath(tasks_path, [process](int tid) {
if (process->threads.count(tid))
return;
ThreadInfo thread = { tid, "" };
char task_comm[64];
sprintf(task_comm, "task/%d/comm", tid);
ReadProcString(process->pid, task_comm, thread.name, sizeof(thread.name));
if (thread.name[0] == '\0' && process->is_app)
strcpy(thread.name, "UI Thread");
process->threads[tid] = thread;
});
}
bool ReadOomStats(ProcessSnapshot* snapshot) {
char buf[64];
if (ReadProcFileTrimmed(snapshot->pid, "oom_score", buf, sizeof(buf)))
snapshot->oom_score = atoi(buf);
else
return false;
if (ReadProcFileTrimmed(snapshot->pid, "oom_score_adj", buf, sizeof(buf)))
snapshot->oom_score_adj = atoi(buf);
else
return false;
return true;
}
bool ReadPageFaultsAndCpuTimeStats(ProcessSnapshot* snapshot) {
char buf[512];
if (!ReadProcFileTrimmed(snapshot->pid, "stat", buf, sizeof(buf)))
return false;
int ret = sscanf(buf,
"%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*u %lu %*lu %lu %*lu %lu %lu",
&snapshot->minor_faults, &snapshot->major_faults,
&snapshot->utime, &snapshot->stime);
CHECK(ret == 4);
return true;
}
bool ReadMemInfoStats(std::map<std::string, uint64_t>* mem_info) {
char buf[1024];
ssize_t rsize = file_utils::ReadFile("/proc/meminfo", buf, sizeof(buf));
if (rsize <= 0)
return false;
file_utils::LineReader reader(buf, rsize);
for (const char* line = reader.NextLine();
line && line[0];
line = reader.NextLine()) {
const char* pos_colon = strstr(line, ":");
if (pos_colon == nullptr)
continue; // Should not happen.
std::string name(line, pos_colon - line);
(*mem_info)[name] = strtoull(&pos_colon[1], nullptr, 10);
}
return true;
}
} // namespace procfs_utils

View File

@@ -0,0 +1,30 @@
// 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.
#ifndef PROCFS_UTILS_H_
#define PROCFS_UTILS_H_
#include <map>
#include <memory>
#include <string>
#include "process_info.h"
namespace procfs_utils {
// ProcFS doesn't necessarly distinguish PID vs. TID, but all threads of a
// process have the same Thread Group ID which is equal to Process ID.
int ReadTgid(int pid);
std::unique_ptr<ProcessInfo> ReadProcessInfo(int pid);
void ReadProcessThreads(ProcessInfo* process);
bool ReadOomStats(ProcessSnapshot* snapshot);
bool ReadPageFaultsAndCpuTimeStats(ProcessSnapshot* snapshot);
bool ReadMemInfoStats(std::map<std::string, uint64_t>* mem_info);
} // namespace procfs_utils
#endif // PROCFS_UTILS_H_

View File

@@ -0,0 +1,62 @@
// 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 "time_utils.h"
#include <sys/time.h>
#include <sys/timerfd.h>
#include <time.h>
#include <unistd.h>
#include "logging.h"
namespace time_utils {
uint64_t GetTimestamp() {
struct timespec ts = {};
CHECK(clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0);
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000ul;
}
PeriodicTimer::PeriodicTimer(int interval_ms) : interval_ms_(interval_ms) {
timer_fd_ = -1;
}
PeriodicTimer::~PeriodicTimer() {
Stop();
}
void PeriodicTimer::Start() {
Stop();
timer_fd_ = timerfd_create(CLOCK_MONOTONIC, 0);
CHECK(timer_fd_ >= 0);
int sec = interval_ms_ / 1000;
int nsec = (interval_ms_ % 1000) * 1000000;
struct itimerspec ts = {};
ts.it_value.tv_nsec = nsec;
ts.it_value.tv_sec = sec;
ts.it_interval.tv_nsec = nsec;
ts.it_interval.tv_sec = sec;
CHECK(timerfd_settime(timer_fd_, 0, &ts, nullptr) == 0);
}
void PeriodicTimer::Stop() {
if (timer_fd_ < 0)
return;
close(timer_fd_);
timer_fd_ = -1;
}
bool PeriodicTimer::Wait() {
if (timer_fd_ < 0)
return false; // Not started yet.
uint64_t stub = 0;
int res = read(timer_fd_, &stub, sizeof(stub));
if (res < 0 && errno == EBADF)
return false; // Interrupted by Stop().
CHECK(res > 0);
return true;
}
} // namespace time_utils

View File

@@ -0,0 +1,34 @@
// 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.
#ifndef TIME_UTILS_H_
#define TIME_UTILS_H_
#include <stdint.h>
namespace time_utils {
uint64_t GetTimestamp();
class PeriodicTimer {
public:
PeriodicTimer(int interval_ms);
~PeriodicTimer();
void Start();
void Stop();
// Wait for next tick. Returns false if interrupted by Stop() or not started.
bool Wait();
private:
PeriodicTimer(const PeriodicTimer&) = delete;
void operator=(const PeriodicTimer&) = delete;
const int interval_ms_;
int timer_fd_;
};
} // namespace time_utils
#endif // TIME_UTILS_

View File

@@ -0,0 +1,14 @@
#!/usr/bin/env python
# Copyright 2016 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 os
import sys
if __name__ == '__main__':
systrace_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(systrace_path)
from profile_chrome import main
sys.exit(main.main())

View File

@@ -0,0 +1,119 @@
#!/usr/bin/env python
#
# 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.
import logging
import optparse
import os
import sys
import webbrowser
_SYSTRACE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(_SYSTRACE_DIR)
from profile_chrome import chrome_startup_tracing_agent
from profile_chrome import flags
from profile_chrome import profiler
from profile_chrome import ui
from systrace import util
from systrace.tracing_agents import atrace_agent
_CATAPULT_DIR = os.path.join(
os.path.dirname(os.path.abspath(__file__)), '..', '..')
sys.path.append(os.path.join(_CATAPULT_DIR, 'devil'))
from devil.android import device_utils
from devil.android.sdk import adb_wrapper
_CHROME_STARTUP_MODULES = [atrace_agent, chrome_startup_tracing_agent]
_DEFAULT_CHROME_CATEGORIES = '_DEFAULT_CHROME_CATEGORIES'
def _CreateOptionParser():
parser = optparse.OptionParser(description='Record about://tracing profiles '
'from Android browsers startup, combined with '
'Android systrace. See http://dev.chromium.org'
'/developers/how-tos/trace-event-profiling-'
'tool for detailed instructions for '
'profiling.', conflict_handler='resolve')
parser = util.get_main_options(parser)
browsers = sorted(util.get_supported_browsers().keys())
parser.add_option('-b', '--browser', help='Select among installed browsers. '
'One of ' + ', '.join(browsers) + ', "stable" is used by '
'default.', type='choice', choices=browsers,
default='stable')
parser.add_option('-v', '--verbose', help='Verbose logging.',
action='store_true')
parser.add_option('-z', '--compress', help='Compress the resulting trace '
'with gzip. ', action='store_true')
parser.add_option('-t', '--time', help='Stops tracing after N seconds, 0 to '
'manually stop (startup trace ends after at most 5s).',
default=5, metavar='N', type='int', dest='trace_time')
parser.add_option('-c', '--chrome_categories', help='Chrome tracing '
'categories to record.', default=_DEFAULT_CHROME_CATEGORIES,
type='string')
parser.add_option('-u', '--atrace-buffer-size', help='Number of bytes to'
' be used for capturing atrace data', type='int',
default=None, dest='trace_buf_size')
parser.add_option_group(chrome_startup_tracing_agent.add_options(parser))
parser.add_option_group(atrace_agent.add_options(parser))
parser.add_option_group(flags.OutputOptions(parser))
return parser
def main():
parser = _CreateOptionParser()
options, _ = parser.parse_args()
if not options.device_serial_number:
devices = [a.GetDeviceSerial() for a in adb_wrapper.AdbWrapper.Devices()]
if len(devices) == 0:
raise RuntimeError('No ADB devices connected.')
elif len(devices) >= 2:
raise RuntimeError('Multiple devices connected, serial number required')
options.device_serial_number = devices[0]
if options.verbose:
logging.getLogger().setLevel(logging.DEBUG)
devices = device_utils.DeviceUtils.HealthyDevices()
if len(devices) != 1:
logging.error('Exactly 1 device must be attached.')
return 1
device = devices[0]
package_info = util.get_supported_browsers()[options.browser]
options.device = device
options.package_info = package_info
# TODO(washingtonp): Once Systrace uses all of the profile_chrome agents,
# manually setting these options will no longer be necessary and should be
# removed.
options.ring_buffer = False
options.trace_memory = False
if options.atrace_categories in ['list', 'help']:
atrace_agent.list_categories(atrace_agent.get_config(options))
print '\n'
return 0
result = profiler.CaptureProfile(options,
options.trace_time,
_CHROME_STARTUP_MODULES,
output=options.output_file,
compress=options.compress,
write_json=options.write_json)
if options.view:
if sys.platform == 'darwin':
os.system('/usr/bin/open %s' % os.path.abspath(result))
else:
webbrowser.open(result)
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env python2.7
# 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.
"""Runs the unit test suite for systrace."""
import optparse
import os
import sys
import unittest
_SYSTRACE_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.path.pardir))
sys.path.insert(0, _SYSTRACE_DIR)
from systrace import decorators
def main():
parser = optparse.OptionParser()
parser.add_option("-d", "--device", dest="device",
help="device the test runs on", metavar="DEVICE")
options, _args = parser.parse_args() # pylint: disable=unused-variable
unfiltered_suite = unittest.TestLoader().discover(
_SYSTRACE_DIR,
pattern = '*_unittest.py',
top_level_dir=_SYSTRACE_DIR)
suite = unittest.TestSuite()
for test_group in unfiltered_suite._tests:
for inner_group in test_group:
for test in inner_group:
method = getattr(
test, test._testMethodName) # pylint: disable=protected-access
if not decorators.ShouldSkip(method, options.device):
suite.addTest(test)
result = unittest.TextTestRunner(verbosity=2).run(suite)
if result.wasSuccessful():
sys.exit(0)
else:
sys.exit(1)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,16 @@
#!/usr/bin/env python
# Copyright 2016 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 os
import sys
_SYSTRACE_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.path.pardir))
sys.path.insert(0, _SYSTRACE_DIR)
from systrace import run_systrace
if __name__ == '__main__':
sys.exit(run_systrace.main())

View File

@@ -0,0 +1,13 @@
# 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 os
import sys
_CATAPULT_DIR = os.path.join(
os.path.dirname(os.path.abspath(__file__)), '..', '..')
sys.path.append(os.path.join(_CATAPULT_DIR, 'devil'))
sys.path.append(os.path.join(_CATAPULT_DIR, 'systrace'))
sys.path.append(os.path.join(_CATAPULT_DIR, 'common', 'py_utils'))

View File

@@ -0,0 +1,154 @@
# 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.
import logging
import optparse
import os
import re
import py_utils
from devil.android import flag_changer
from devil.android.constants import webapk
from devil.android.perf import cache_control
from devil.android.sdk import intent
from systrace import trace_result
from systrace import tracing_agents
class ChromeStartupTracingAgent(tracing_agents.TracingAgent):
def __init__(self, device, package_info, webapk_package, cold, url,
trace_time=None):
tracing_agents.TracingAgent.__init__(self)
self._device = device
self._package_info = package_info
self._webapk_package = webapk_package
self._cold = cold
self._logcat_monitor = self._device.GetLogcatMonitor()
self._url = url
self._trace_time = trace_time
self._trace_file = None
self._trace_finish_re = re.compile(r' Completed startup tracing to (.*)')
self._flag_changer = flag_changer.FlagChanger(
self._device, self._package_info.cmdline_file)
def __repr__(self):
return 'Browser Startup Trace'
def _SetupTracing(self):
# TODO(lizeb): Figure out how to clean up the command-line file when
# _TearDownTracing() is not executed in StopTracing().
flags = ['--trace-startup', '--enable-perfetto']
if self._trace_time is not None:
flags.append('--trace-startup-duration={}'.format(self._trace_time))
self._flag_changer.AddFlags(flags)
self._device.ForceStop(self._package_info.package)
if self._webapk_package:
self._device.ForceStop(self._webapk_package)
logging.warning('Forces to stop the WebAPK and the browser provided by '
'--browser: %s. Please make sure that this browser '
'matches the host browser of the WebAPK %s. ',
self._package_info.package,
self._webapk_package)
if self._cold:
self._device.EnableRoot()
cache_control.CacheControl(self._device).DropRamCaches()
launch_intent = None
if self._webapk_package:
launch_intent = intent.Intent(
package=self._webapk_package,
activity=webapk.WEBAPK_MAIN_ACTIVITY,
data=self._url)
elif self._url == '':
launch_intent = intent.Intent(
action='android.intent.action.MAIN',
package=self._package_info.package,
activity=self._package_info.activity)
else:
launch_intent = intent.Intent(
package=self._package_info.package,
activity=self._package_info.activity,
data=self._url,
extras={'create_new_tab': True})
self._logcat_monitor.Start()
self._device.StartActivity(launch_intent, blocking=True)
def _TearDownTracing(self):
self._flag_changer.Restore()
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
self._SetupTracing()
return True
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
try:
self._trace_file = self._logcat_monitor.WaitFor(
self._trace_finish_re).group(1)
finally:
self._TearDownTracing()
return True
@py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
def GetResults(self, timeout=None):
with open(self._PullTrace(), 'r') as f:
trace_data = f.read()
return trace_result.TraceResult('traceEvents', trace_data)
def _PullTrace(self):
trace_file = self._trace_file.replace('/storage/emulated/0/', '/sdcard/')
host_file = os.path.join(os.path.curdir, os.path.basename(trace_file))
self._device.PullFile(trace_file, host_file)
return host_file
def SupportsExplicitClockSync(self):
return False
def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
# pylint: disable=unused-argument
assert self.SupportsExplicitClockSync(), ('Clock sync marker cannot be '
'recorded since explicit clock sync is not supported.')
class ChromeStartupConfig(tracing_agents.TracingConfig):
def __init__(self, device, package_info, webapk_package, cold, url,
chrome_categories, trace_time):
tracing_agents.TracingConfig.__init__(self)
self.device = device
self.package_info = package_info
self.webapk_package = webapk_package
self.cold = cold
self.url = url
self.chrome_categories = chrome_categories
self.trace_time = trace_time
def try_create_agent(config):
return ChromeStartupTracingAgent(config.device, config.package_info,
config.webapk_package,
config.cold, config.url, config.trace_time)
def add_options(parser):
options = optparse.OptionGroup(parser, 'Chrome startup tracing')
options.add_option('--url', help='URL to visit on startup. Default: '
'https://www.google.com. An empty URL launches Chrome '
'with a MAIN action instead of VIEW.',
default='https://www.google.com', metavar='URL')
options.add_option('--cold', help='Flush the OS page cache before starting '
'the browser. Note that this require a device with root '
'access.', default=False, action='store_true')
options.add_option('--webapk-package', help='Specify the package name '
'of the WebAPK to launch the given URL. An empty URL '
'laucnhes the host browser of the WebAPK with an new '
'tab.', default=None)
return options
def get_config(options):
return ChromeStartupConfig(options.device, options.package_info,
options.webapk_package, options.cold,
options.url, options.chrome_categories,
options.trace_time)

View File

@@ -0,0 +1,32 @@
# 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.
import json
from profile_chrome import chrome_startup_tracing_agent
from systrace import decorators
from systrace.tracing_agents import agents_unittest
class ChromeAgentTest(agents_unittest.BaseAgentTest):
# TODO(washingtonp): This test seems to fail on the version of Android
# currently on the Trybot servers (KTU84P), although it works on Android M.
# Either upgrade the version of Android on the Trybot servers or determine
# if there is a way to run this agent on Android KTU84P.
@decorators.Disabled
def testTracing(self):
agent = chrome_startup_tracing_agent.ChromeStartupTracingAgent(
self.device, self.package_info,
'', # webapk_package
False, # cold
'https://www.google.com' # url
)
try:
agent.StartAgentTracing(None)
finally:
agent.StopAgentTracing()
result = agent.GetResults()
json.loads(result.raw_data)

View File

@@ -0,0 +1,217 @@
# 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 json
import optparse
import os
import re
import py_utils
from devil.android import device_errors
from devil.android.sdk import intent
from systrace import trace_result
from systrace import tracing_agents
DEFAULT_CHROME_CATEGORIES = '_DEFAULT_CHROME_CATEGORIES'
_HEAP_PROFILE_MMAP_PROPERTY = 'heapprof.mmap'
class ChromeTracingAgent(tracing_agents.TracingAgent):
def __init__(self, device, package_info, ring_buffer, trace_memory=False):
tracing_agents.TracingAgent.__init__(self)
self._device = device
self._package_info = package_info
self._ring_buffer = ring_buffer
self._logcat_monitor = self._device.GetLogcatMonitor()
self._trace_file = None
self._trace_memory = trace_memory
self._is_tracing = False
self._trace_start_re = \
re.compile(r'Logging performance trace to file')
self._trace_finish_re = \
re.compile(r'Profiler finished[.] Results are in (.*)[.]')
self._categories = None
def __repr__(self):
return 'chrome trace'
@staticmethod
def GetCategories(device, package_info):
with device.GetLogcatMonitor() as logmon:
device.BroadcastIntent(intent.Intent(
action='%s.GPU_PROFILER_LIST_CATEGORIES' % package_info.package))
try:
json_category_list = logmon.WaitFor(
re.compile(r'{"traceCategoriesList(.*)'), timeout=5).group(0)
except device_errors.CommandTimeoutError:
raise RuntimeError('Performance trace category list marker not found. '
'Is the correct version of the browser running?')
record_categories = set()
disabled_by_default_categories = set()
json_data = json.loads(json_category_list)['traceCategoriesList']
for item in json_data:
for category in item.split(','):
if category.startswith('disabled-by-default'):
disabled_by_default_categories.add(category)
else:
record_categories.add(category)
return list(record_categories), list(disabled_by_default_categories)
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
self._categories = _ComputeChromeCategories(config)
self._logcat_monitor.Start()
start_extras = {'categories': ','.join(self._categories)}
if self._ring_buffer:
start_extras['continuous'] = None
self._device.BroadcastIntent(intent.Intent(
action='%s.GPU_PROFILER_START' % self._package_info.package,
extras=start_extras))
if self._trace_memory:
self._device.EnableRoot()
self._device.SetProp(_HEAP_PROFILE_MMAP_PROPERTY, 1)
# Chrome logs two different messages related to tracing:
#
# 1. "Logging performance trace to file"
# 2. "Profiler finished. Results are in [...]"
#
# The first one is printed when tracing starts and the second one indicates
# that the trace file is ready to be pulled.
try:
self._logcat_monitor.WaitFor(self._trace_start_re, timeout=5)
self._is_tracing = True
except device_errors.CommandTimeoutError:
raise RuntimeError(
'Trace start marker not found. Possible causes: 1) Is the correct '
'version of the browser running? 2) Is the browser already launched?')
return True
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
if self._is_tracing:
self._device.BroadcastIntent(intent.Intent(
action='%s.GPU_PROFILER_STOP' % self._package_info.package))
self._trace_file = self._logcat_monitor.WaitFor(
self._trace_finish_re, timeout=120).group(1)
self._is_tracing = False
if self._trace_memory:
self._device.SetProp(_HEAP_PROFILE_MMAP_PROPERTY, 0)
return True
@py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
def GetResults(self, timeout=None):
with open(self._PullTrace(), 'r') as f:
trace_data = f.read()
return trace_result.TraceResult('traceEvents', trace_data)
def _PullTrace(self):
trace_file = self._trace_file.replace('/storage/emulated/0/', '/sdcard/')
host_file = os.path.join(os.path.curdir, os.path.basename(trace_file))
try:
self._device.PullFile(trace_file, host_file)
except device_errors.AdbCommandFailedError:
raise RuntimeError(
'Cannot pull the trace file. Have you granted Storage permission to '
'the browser? (Android Settings -> Apps -> [the browser app] -> '
'Permissions -> Storage)')
return host_file
def SupportsExplicitClockSync(self):
return False
def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
# pylint: disable=unused-argument
assert self.SupportsExplicitClockSync(), ('Clock sync marker cannot be '
'recorded since explicit clock sync is not supported.')
class ChromeConfig(tracing_agents.TracingConfig):
def __init__(self, chrome_categories, trace_cc, trace_frame_viewer,
trace_ubercompositor, trace_gpu, trace_flow, trace_memory,
trace_scheduler, ring_buffer, device, package_info):
tracing_agents.TracingConfig.__init__(self)
self.chrome_categories = chrome_categories
self.trace_cc = trace_cc
self.trace_frame_viewer = trace_frame_viewer
self.trace_ubercompositor = trace_ubercompositor
self.trace_gpu = trace_gpu
self.trace_flow = trace_flow
self.trace_memory = trace_memory
self.trace_scheduler = trace_scheduler
self.ring_buffer = ring_buffer
self.device = device
self.package_info = package_info
def try_create_agent(config):
if config.chrome_categories:
return ChromeTracingAgent(config.device, config.package_info,
config.ring_buffer, config.trace_memory)
return None
def add_options(parser):
chrome_opts = optparse.OptionGroup(parser, 'Chrome tracing options')
chrome_opts.add_option('-c', '--categories', help='Select Chrome tracing '
'categories with comma-delimited wildcards, '
'e.g., "*", "cat1*,-cat1a". Omit this option to trace '
'Chrome\'s default categories. Chrome tracing can be '
'disabled with "--categories=\'\'". Use "list" to '
'see the available categories.',
metavar='CHROME_CATEGORIES', dest='chrome_categories')
chrome_opts.add_option('--trace-cc',
help='Deprecated, use --trace-frame-viewer.',
action='store_true')
chrome_opts.add_option('--trace-frame-viewer',
help='Enable enough trace categories for '
'compositor frame viewing.', action='store_true')
chrome_opts.add_option('--trace-ubercompositor',
help='Enable enough trace categories for '
'ubercompositor frame data.', action='store_true')
chrome_opts.add_option('--trace-gpu', help='Enable extra trace categories '
'for GPU data.', action='store_true')
chrome_opts.add_option('--trace-flow', help='Enable extra trace categories '
'for IPC message flows.', action='store_true')
chrome_opts.add_option('--trace-memory', help='Enable extra trace categories '
'for memory profile. (tcmalloc required)',
action='store_true')
chrome_opts.add_option('--trace-scheduler', help='Enable extra trace '
'categories for scheduler state',
action='store_true')
return chrome_opts
def get_config(options):
return ChromeConfig(options.chrome_categories, options.trace_cc,
options.trace_frame_viewer, options.trace_ubercompositor,
options.trace_gpu, options.trace_flow,
options.trace_memory, options.trace_scheduler,
options.ring_buffer, options.device,
options.package_info)
def _ComputeChromeCategories(config):
categories = []
if config.trace_frame_viewer:
categories.append('disabled-by-default-cc.debug')
if config.trace_ubercompositor:
categories.append('disabled-by-default-cc.debug*')
if config.trace_gpu:
categories.append('disabled-by-default-gpu.debug*')
if config.trace_flow:
categories.append('disabled-by-default-toplevel.flow')
if config.trace_memory:
categories.append('disabled-by-default-memory')
if config.trace_scheduler:
categories.append('disabled-by-default-blink.scheduler')
categories.append('disabled-by-default-cc.debug.scheduler')
categories.append('disabled-by-default-renderer.scheduler')
categories.append('disabled-by-default-sequence_manager')
categories.append('sequence_manager')
if config.chrome_categories:
categories += config.chrome_categories.split(',')
return categories

View File

@@ -0,0 +1,51 @@
# 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 json
from profile_chrome import chrome_tracing_agent
from systrace import decorators
from systrace.tracing_agents import agents_unittest
class ChromeAgentTest(agents_unittest.BaseAgentTest):
# TODO(washingtonp): This test seems to fail on the version of Android
# currently on the Trybot servers (KTU84P), although it works on Android M.
# Either upgrade the version of Android on the Trybot servers or determine
# if there is a way to run this agent on Android KTU84P.
@decorators.Disabled
def testGetCategories(self):
curr_browser = self.GetChromeProcessID()
if curr_browser is None:
self.StartBrowser()
categories = \
chrome_tracing_agent.ChromeTracingAgent.GetCategories(
self.device, self.package_info)
self.assertEquals(len(categories), 2)
self.assertTrue(categories[0])
self.assertTrue(categories[1])
# TODO(washingtonp): This test is pretty flaky on the version of Android
# currently on the Trybot servers (KTU84P), although it works on Android M.
# Either upgrade the version of Android on the Trybot servers or determine
# if there is a way to run this agent on Android KTU84P.
@decorators.Disabled
def testTracing(self):
curr_browser = self.GetChromeProcessID()
if curr_browser is None:
self.StartBrowser()
categories = '*'
ring_buffer = False
agent = chrome_tracing_agent.ChromeTracingAgent(self.device,
self.package_info,
ring_buffer)
agent.StartAgentTracing(chrome_tracing_agent.ChromeConfig(categories, None,
None, None, None, None, None, None, ring_buffer, self.device,
self.package_info))
agent.StopAgentTracing()
result = agent.GetResults()
json.loads(result.raw_data)

View File

@@ -0,0 +1,98 @@
# 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.
import optparse
import os
import re
import py_utils
from profile_chrome import util
from systrace import trace_result
from systrace import tracing_agents
_DDMS_SAMPLING_FREQUENCY_US = 100
class DdmsAgent(tracing_agents.TracingAgent):
def __init__(self, device, package_info):
tracing_agents.TracingAgent.__init__(self)
self._device = device
self._package = package_info.package
self._output_file = None
self._supports_sampling = self._SupportsSampling()
def __repr__(self):
return 'ddms profile'
def _SupportsSampling(self):
for line in self._device.RunShellCommand(
['am', '--help'], check_return=True):
if re.match(r'.*am profile start.*--sampling', line):
return True
return False
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
self._output_file = (
'/data/local/tmp/ddms-profile-%s' % util.GetTraceTimestamp())
cmd = ['am', 'profile', 'start']
if self._supports_sampling:
cmd.extend(['--sampling', str(_DDMS_SAMPLING_FREQUENCY_US)])
cmd.extend([self._package, self._output_file])
self._device.RunShellCommand(cmd, check_return=True)
return True
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
self._device.RunShellCommand(
['am', 'profile', 'stop', self._package], check_return=True)
return True
@py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
def GetResults(self, timeout=None):
with open(self._PullTrace(), 'r') as f:
trace_data = f.read()
return trace_result.TraceResult('ddms', trace_data)
def _PullTrace(self):
if not self._output_file:
return None
host_file = os.path.join(
os.path.curdir, os.path.basename(self._output_file))
self._device.PullFile(self._output_file, host_file)
return host_file
def SupportsExplicitClockSync(self):
return False
def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
# pylint: disable=unused-argument
assert self.SupportsExplicitClockSync(), ('Clock sync marker cannot be '
'recorded since explicit clock sync is not supported.')
class DdmsConfig(tracing_agents.TracingConfig):
def __init__(self, device, package_info, ddms):
tracing_agents.TracingConfig.__init__(self)
self.device = device
self.package_info = package_info
self.ddms = ddms
def try_create_agent(config):
if config.ddms:
return DdmsAgent(config.device, config.package_info)
return None
def add_options(parser):
options = optparse.OptionGroup(parser, 'Java tracing')
options.add_option('--ddms', help='Trace Java execution using DDMS '
'sampling.', action='store_true')
return options
def get_config(options):
return DdmsConfig(options.device, options.package_info, options.ddms)

View File

@@ -0,0 +1,24 @@
# 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.
from profile_chrome import ddms_tracing_agent
from systrace import decorators
from systrace.tracing_agents import agents_unittest
class DdmsAgentTest(agents_unittest.BaseAgentTest):
# TODO(washingtonp): The DDMS test is flaky on the Tryserver, but it
# consistently passes on Android M. Need to figure out why the result data
# does not start with '*version' and why the test is flaky.
@decorators.Disabled
def testTracing(self):
agent = ddms_tracing_agent.DdmsAgent(self.device, self.package_info)
try:
agent.StartAgentTracing(None)
finally:
agent.StopAgentTracing()
result = agent.GetResults()
self.assertTrue(result.raw_data.startswith('*version'))

View File

@@ -0,0 +1,69 @@
# Copyright 2016 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 optparse
import tempfile
from systrace import trace_result
from systrace import tracing_agents
class FakeAgent(object):
def __init__(self, contents='fake-contents'):
self.contents = contents
self.stopped = False
self.filename = None
self.config = None
self.timeout = None
def StartAgentTracing(self, config, timeout=None):
self.config = config
self.timeout = timeout
return True
# pylint: disable=unused-argument
def StopAgentTracing(self, timeout=None):
self.stopped = True
return True
# pylint: disable=unused-argument
def GetResults(self, timeout=None):
trace_data = open(self._PullTrace()).read()
return trace_result.TraceResult('fakeData', trace_data)
def _PullTrace(self):
with tempfile.NamedTemporaryFile(delete=False) as f:
self.filename = f.name
f.write(self.contents)
return f.name
# pylint: disable=no-self-use
def SupportsExplicitClockSync(self):
return False
# pylint: disable=unused-argument, no-self-use
def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
print ('Clock sync marker cannot be recorded since explicit clock sync '
'is not supported.')
def __repr__(self):
return 'faketrace'
class FakeConfig(tracing_agents.TracingConfig):
def __init__(self):
tracing_agents.TracingConfig.__init__(self)
# pylint: disable=unused-argument
def try_create_agent(config):
return FakeAgent()
def add_options(parser):
options = optparse.OptionGroup(parser, 'Fake options.')
return options
# pylint: disable=unused-argument
def get_config(options):
return FakeConfig()

View File

@@ -0,0 +1,68 @@
# Copyright 2016 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 optparse
import tempfile
from systrace import trace_result
from systrace import tracing_agents
class FakeAgent2(object):
def __init__(self, contents='fake-contents'):
self.contents = contents
self.stopped = False
self.config = None
self.filename = None
# pylint: disable=unused-argument
def StartAgentTracing(self, config, timeout=None):
self.config = config
return True
# pylint: disable=unused-argument
def StopAgentTracing(self, timeout=None):
self.stopped = True
return True
# pylint: disable=unused-argument
def GetResults(self, timeout=None):
trace_data = open(self._PullTrace()).read()
return trace_result.TraceResult('fakeDataTwo', trace_data)
def _PullTrace(self):
with tempfile.NamedTemporaryFile(delete=False) as f:
self.filename = f.name
f.write(self.contents)
return f.name
# pylint: disable=no-self-use
def SupportsExplicitClockSync(self):
return False
# pylint: disable=unused-argument, no-self-use
def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
print ('Clock sync marker cannot be recorded since explicit clock sync '
'is not supported.')
def __repr__(self):
return 'faketracetwo'
class FakeConfig(tracing_agents.TracingConfig):
def __init__(self):
tracing_agents.TracingConfig.__init__(self)
# pylint: disable=unused-argument
def try_create_agent(config):
return FakeAgent2()
def add_options(parser):
options = optparse.OptionGroup(parser, 'Fake options.')
return options
# pylint: disable=unused-argument
def get_config(options):
return FakeConfig()

View File

@@ -0,0 +1,16 @@
# 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.
import optparse
def OutputOptions(parser):
output_options = optparse.OptionGroup(parser, 'Output options')
output_options.add_option('-o', '--output', dest='output_file',
help='Save trace output to file.')
output_options.add_option('--json', help='Save trace as raw JSON instead of '
'HTML.', dest='write_json')
output_options.add_option('--view', help='Open resulting trace file in a '
'browser.', action='store_true')
return output_options

View File

@@ -0,0 +1,160 @@
#!/usr/bin/env python
#
# 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 logging
import optparse
import os
import sys
import webbrowser
from profile_chrome import chrome_tracing_agent
from profile_chrome import ddms_tracing_agent
from profile_chrome import flags
from profile_chrome import perf_tracing_agent
from profile_chrome import profiler
from profile_chrome import ui
from systrace import util
from systrace.tracing_agents import atrace_agent
from devil.android import device_utils
from devil.android.sdk import adb_wrapper
_PROFILE_CHROME_AGENT_MODULES = [chrome_tracing_agent, ddms_tracing_agent,
perf_tracing_agent, atrace_agent]
def _CreateOptionParser():
parser = optparse.OptionParser(description='Record about://tracing profiles '
'from Android browsers. See http://dev.'
'chromium.org/developers/how-tos/trace-event-'
'profiling-tool for detailed instructions for '
'profiling.', conflict_handler='resolve')
parser = util.get_main_options(parser)
timed_options = optparse.OptionGroup(parser, 'Timed tracing')
timed_options.add_option('-t', '--time', help='Profile for N seconds and '
'download the resulting trace.', metavar='N',
type='float', dest='trace_time')
parser.add_option_group(timed_options)
cont_options = optparse.OptionGroup(parser, 'Continuous tracing')
cont_options.add_option('--continuous', help='Profile continuously until '
'stopped.', action='store_true')
cont_options.add_option('--ring-buffer', help='Use the trace buffer as a '
'ring buffer and save its contents when stopping '
'instead of appending events into one long trace.',
action='store_true')
parser.add_option_group(cont_options)
parser.add_option_group(flags.OutputOptions(parser))
browsers = sorted(util.get_supported_browsers().keys())
parser.add_option('-b', '--browser', help='Select among installed browsers. '
'One of ' + ', '.join(browsers) + ', "stable" is used by '
'default.', type='choice', choices=browsers,
default='stable')
parser.add_option('-v', '--verbose', help='Verbose logging.',
action='store_true')
parser.add_option('-z', '--compress', help='Compress the resulting trace '
'with gzip. ', action='store_true')
# Add options from profile_chrome agents.
for module in _PROFILE_CHROME_AGENT_MODULES:
parser.add_option_group(module.add_options(parser))
return parser
def main():
parser = _CreateOptionParser()
options, _args = parser.parse_args() # pylint: disable=unused-variable
if options.trace_cc:
parser.error("""--trace-cc is deprecated.
For basic jank busting uses, use --trace-frame-viewer
For detailed study of ubercompositor, pass --trace-ubercompositor.
When in doubt, just try out --trace-frame-viewer.
""")
logging.basicConfig()
if options.verbose:
logging.getLogger().setLevel(logging.DEBUG)
if not options.device_serial_number:
devices = [a.GetDeviceSerial() for a in adb_wrapper.AdbWrapper.Devices()]
if len(devices) == 0:
raise RuntimeError('No ADB devices connected.')
elif len(devices) >= 2:
raise RuntimeError('Multiple devices connected, serial number required')
options.device_serial_number = devices[0]
device = device_utils.DeviceUtils.HealthyDevices(device_arg=
options.device_serial_number)[0]
package_info = util.get_supported_browsers()[options.browser]
options.device = device
options.package_info = package_info
# Include Chrome categories by default in profile_chrome.
if not options.chrome_categories:
options.chrome_categories = chrome_tracing_agent.DEFAULT_CHROME_CATEGORIES
if options.chrome_categories in ['list', 'help']:
ui.PrintMessage('Collecting record categories list...', eol='')
record_categories = []
disabled_by_default_categories = []
record_categories, disabled_by_default_categories = \
chrome_tracing_agent.ChromeTracingAgent.GetCategories(
device, package_info)
ui.PrintMessage('done')
ui.PrintMessage('Record Categories:')
ui.PrintMessage('\n'.join('\t%s' % item \
for item in sorted(record_categories)))
ui.PrintMessage('\nDisabled by Default Categories:')
ui.PrintMessage('\n'.join('\t%s' % item \
for item in sorted(disabled_by_default_categories)))
return 0
if options.atrace_categories in ['list', 'help']:
atrace_agent.list_categories(atrace_agent.get_config(options))
print '\n'
return 0
if (perf_tracing_agent.PerfProfilerAgent.IsSupported() and
options.perf_categories in ['list', 'help']):
ui.PrintMessage('\n'.join(
perf_tracing_agent.PerfProfilerAgent.GetCategories(device)))
return 0
if not options.trace_time and not options.continuous:
ui.PrintMessage('Time interval or continuous tracing should be specified.')
return 1
if (options.chrome_categories and options.atrace_categories and
'webview' in options.atrace_categories):
logging.warning('Using the "webview" category in atrace together with '
'Chrome tracing results in duplicate trace events.')
if options.output_file:
options.output_file = os.path.expanduser(options.output_file)
result = profiler.CaptureProfile(
options,
options.trace_time if not options.continuous else 0,
_PROFILE_CHROME_AGENT_MODULES,
output=options.output_file,
compress=options.compress,
write_json=options.write_json)
if options.view:
if sys.platform == 'darwin':
os.system('/usr/bin/open %s' % os.path.abspath(result))
else:
webbrowser.open(result)

View File

@@ -0,0 +1,254 @@
# 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 logging
import optparse
import os
import signal
import subprocess
import sys
import tempfile
import py_utils
from devil.android import device_temp_file
from devil.android.perf import perf_control
from profile_chrome import ui
from systrace import trace_result
from systrace import tracing_agents
_CATAPULT_DIR = os.path.join(
os.path.dirname(os.path.abspath(__file__)), '..', '..')
sys.path.append(os.path.join(_CATAPULT_DIR, 'telemetry'))
try:
# pylint: disable=F0401,no-name-in-module,wrong-import-position
from telemetry.internal.platform.profiler import android_profiling_helper
from telemetry.internal.util import binary_manager
except ImportError:
android_profiling_helper = None
binary_manager = None
_PERF_OPTIONS = [
# Sample across all processes and CPUs to so that the current CPU gets
# recorded to each sample.
'--all-cpus',
# In perf 3.13 --call-graph requires an argument, so use the -g short-hand
# which does not.
'-g',
# Increase priority to avoid dropping samples. Requires root.
'--realtime', '80',
# Record raw samples to get CPU information.
'--raw-samples',
# Increase sampling frequency for better coverage.
'--freq', '2000',
]
class _PerfProfiler(object):
def __init__(self, device, perf_binary, categories):
self._device = device
self._output_file = device_temp_file.DeviceTempFile(
self._device.adb, prefix='perf_output')
self._log_file = tempfile.TemporaryFile()
# TODO(jbudorick) Look at providing a way to unhandroll this once the
# adb rewrite has fully landed.
device_param = (['-s', str(self._device)] if str(self._device) else [])
cmd = ['adb'] + device_param + \
['shell', perf_binary, 'record',
'--output', self._output_file.name] + _PERF_OPTIONS
if categories:
cmd += ['--event', ','.join(categories)]
self._perf_control = perf_control.PerfControl(self._device)
self._perf_control.SetPerfProfilingMode()
self._perf_process = subprocess.Popen(cmd,
stdout=self._log_file,
stderr=subprocess.STDOUT)
def SignalAndWait(self):
self._device.KillAll('perf', signum=signal.SIGINT)
self._perf_process.wait()
self._perf_control.SetDefaultPerfMode()
def _FailWithLog(self, msg):
self._log_file.seek(0)
log = self._log_file.read()
raise RuntimeError('%s. Log output:\n%s' % (msg, log))
def PullResult(self, output_path):
if not self._device.FileExists(self._output_file.name):
self._FailWithLog('Perf recorded no data')
perf_profile = os.path.join(output_path,
os.path.basename(self._output_file.name))
self._device.PullFile(self._output_file.name, perf_profile)
if not os.stat(perf_profile).st_size:
os.remove(perf_profile)
self._FailWithLog('Perf recorded a zero-sized file')
self._log_file.close()
self._output_file.close()
return perf_profile
class PerfProfilerAgent(tracing_agents.TracingAgent):
def __init__(self, device):
tracing_agents.TracingAgent.__init__(self)
self._device = device
self._perf_binary = self._PrepareDevice(device)
self._perf_instance = None
self._categories = None
def __repr__(self):
return 'perf profile'
@staticmethod
def IsSupported():
return bool(android_profiling_helper)
@staticmethod
def _PrepareDevice(device):
if not 'BUILDTYPE' in os.environ:
os.environ['BUILDTYPE'] = 'Release'
if binary_manager.NeedsInit():
binary_manager.InitDependencyManager(None)
return android_profiling_helper.PrepareDeviceForPerf(device)
@classmethod
def GetCategories(cls, device):
perf_binary = cls._PrepareDevice(device)
# Perf binary returns non-zero exit status on "list" command.
return device.RunShellCommand([perf_binary, 'list'], check_return=False)
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
self._categories = _ComputePerfCategories(config)
self._perf_instance = _PerfProfiler(self._device,
self._perf_binary,
self._categories)
return True
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
if not self._perf_instance:
return
self._perf_instance.SignalAndWait()
return True
@py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
def GetResults(self, timeout=None):
with open(self._PullTrace(), 'r') as f:
trace_data = f.read()
return trace_result.TraceResult('perf', trace_data)
@staticmethod
def _GetInteractivePerfCommand(perfhost_path, perf_profile, symfs_dir,
required_libs, kallsyms):
cmd = '%s report -n -i %s --symfs %s --kallsyms %s' % (
os.path.relpath(perfhost_path, '.'), perf_profile, symfs_dir, kallsyms)
for lib in required_libs:
lib = os.path.join(symfs_dir, lib[1:])
if not os.path.exists(lib):
continue
objdump_path = android_profiling_helper.GetToolchainBinaryPath(
lib, 'objdump')
if objdump_path:
cmd += ' --objdump %s' % os.path.relpath(objdump_path, '.')
break
return cmd
def _PullTrace(self):
symfs_dir = os.path.join(tempfile.gettempdir(),
os.path.expandvars('$USER-perf-symfs'))
if not os.path.exists(symfs_dir):
os.makedirs(symfs_dir)
required_libs = set()
# Download the recorded perf profile.
perf_profile = self._perf_instance.PullResult(symfs_dir)
required_libs = \
android_profiling_helper.GetRequiredLibrariesForPerfProfile(
perf_profile)
if not required_libs:
logging.warning('No libraries required by perf trace. Most likely there '
'are no samples in the trace.')
# Build a symfs with all the necessary libraries.
kallsyms = android_profiling_helper.CreateSymFs(self._device,
symfs_dir,
required_libs,
use_symlinks=False)
perfhost_path = binary_manager.FetchPath(
android_profiling_helper.GetPerfhostName(), 'x86_64', 'linux')
ui.PrintMessage('\nNote: to view the profile in perf, run:')
ui.PrintMessage(' ' + self._GetInteractivePerfCommand(perfhost_path,
perf_profile, symfs_dir, required_libs, kallsyms))
# Convert the perf profile into JSON.
perf_script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
'third_party', 'perf_to_tracing.py')
json_file_name = os.path.basename(perf_profile)
with open(os.devnull, 'w') as dev_null, \
open(json_file_name, 'w') as json_file:
cmd = [perfhost_path, 'script', '-s', perf_script_path, '-i',
perf_profile, '--symfs', symfs_dir, '--kallsyms', kallsyms]
if subprocess.call(cmd, stdout=json_file, stderr=dev_null):
logging.warning('Perf data to JSON conversion failed. The result will '
'not contain any perf samples. You can still view the '
'perf data manually as shown above.')
return None
return json_file_name
def SupportsExplicitClockSync(self):
return False
def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
# pylint: disable=unused-argument
assert self.SupportsExplicitClockSync(), ('Clock sync marker cannot be '
'recorded since explicit clock sync is not supported.')
def _OptionalValueCallback(default_value):
def callback(option, _, __, parser): # pylint: disable=unused-argument
value = default_value
if parser.rargs and not parser.rargs[0].startswith('-'):
value = parser.rargs.pop(0)
setattr(parser.values, option.dest, value)
return callback
class PerfConfig(tracing_agents.TracingConfig):
def __init__(self, perf_categories, device):
tracing_agents.TracingConfig.__init__(self)
self.perf_categories = perf_categories
self.device = device
def try_create_agent(config):
if config.perf_categories:
return PerfProfilerAgent(config.device)
return None
def add_options(parser):
options = optparse.OptionGroup(parser, 'Perf profiling options')
options.add_option('-p', '--perf', help='Capture a perf profile with '
'the chosen comma-delimited event categories. '
'Samples CPU cycles by default. Use "list" to see '
'the available sample types.', action='callback',
default='', callback=_OptionalValueCallback('cycles'),
metavar='PERF_CATEGORIES', dest='perf_categories')
return options
def get_config(options):
return PerfConfig(options.perf_categories, options.device)
def _ComputePerfCategories(config):
if not PerfProfilerAgent.IsSupported():
return []
if not config.perf_categories:
return []
return config.perf_categories.split(',')

View File

@@ -0,0 +1,39 @@
# 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 json
from profile_chrome import perf_tracing_agent
from profile_chrome import ui
from systrace import decorators
from systrace.tracing_agents import agents_unittest
class PerfProfilerAgentTest(agents_unittest.BaseAgentTest):
@decorators.ClientOnlyTest
def testGetCategories(self):
if not perf_tracing_agent.PerfProfilerAgent.IsSupported():
return
categories = \
perf_tracing_agent.PerfProfilerAgent.GetCategories(self.device)
assert 'cycles' in ' '.join(categories)
# TODO(washingtonp): Try enabling this test for the SimpleperfProfilerAgent,
# which will be added later.
@decorators.Disabled
def testTracing(self):
if not perf_tracing_agent.PerfProfilerAgent.IsSupported():
return
ui.EnableTestMode()
categories = 'cycles'
agent = perf_tracing_agent.PerfProfilerAgent(self.device)
try:
agent.StartAgentTracing(perf_tracing_agent.PerfConfig(categories,
self.device))
finally:
agent.StopAgentTracing()
result = agent.GetResults()
json.loads(result.raw_data)

View File

@@ -0,0 +1,108 @@
# 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 time
from profile_chrome import chrome_startup_tracing_agent
from profile_chrome import chrome_tracing_agent
from profile_chrome import ui
from profile_chrome import util
from systrace import output_generator
from systrace import tracing_controller
def _GetResults(trace_results, controller, output, compress, write_json,
interval):
ui.PrintMessage('Downloading...')
# Wait for the trace file to get written.
time.sleep(1)
for agent in controller.get_child_agents:
if isinstance(agent, chrome_tracing_agent.ChromeTracingAgent):
time.sleep(interval / 4)
# Ignore the systraceController because it will not contain any results,
# instead being in charge of collecting results.
trace_results = [x for x in controller.all_results if not (x.source_name ==
'systraceController')]
if not trace_results:
ui.PrintMessage('No results')
return ''
result = None
trace_results = output_generator.MergeTraceResultsIfNeeded(trace_results)
if not write_json:
ui.PrintMessage('Writing trace HTML...')
html_file = output or trace_results[0].source_name + '.html'
result = output_generator.GenerateHTMLOutput(trace_results, html_file)
ui.PrintMessage('\nWrote file://%s' % result)
elif compress and len(trace_results) == 1:
result = output or trace_results[0].source_name + '.gz'
util.WriteDataToCompressedFile(trace_results[0].raw_data, result)
elif len(trace_results) > 1:
result = (output or 'chrome-combined-trace-%s.zip' %
util.GetTraceTimestamp())
util.ArchiveData(trace_results, result)
elif output:
result = output
with open(result, 'wb') as f:
f.write(trace_results[0].raw_data)
else:
result = trace_results[0].source_name
with open(result, 'wb') as f:
f.write(trace_results[0].raw_data)
return result
def CaptureProfile(options, interval, modules, output=None,
compress=False, write_json=False):
"""Records a profiling trace saves the result to a file.
Args:
options: Command line options.
interval: Time interval to capture in seconds. An interval of None (or 0)
continues tracing until stopped by the user.
modules: The list of modules to initialize the tracing controller with.
output: Output file name or None to use an automatically generated name.
compress: If True, the result will be compressed either with gzip or zip
depending on the number of captured subtraces.
write_json: If True, prefer JSON output over HTML.
Returns:
Path to saved profile.
"""
agents_with_config = tracing_controller.CreateAgentsWithConfig(options,
modules)
if chrome_startup_tracing_agent in modules:
controller_config = tracing_controller.GetChromeStartupControllerConfig(
options)
else:
controller_config = tracing_controller.GetControllerConfig(options)
controller = tracing_controller.TracingController(agents_with_config,
controller_config)
try:
result = controller.StartTracing()
trace_type = controller.GetTraceType()
if not result:
ui.PrintMessage('Trace starting failed.')
if interval:
ui.PrintMessage(('Capturing %d-second %s. Press Enter to stop early...' %
(interval, trace_type)), eol='')
ui.WaitForEnter(interval)
else:
ui.PrintMessage('Capturing %s. Press Enter to stop...' % trace_type,
eol='')
raw_input()
ui.PrintMessage('Stopping...')
all_results = controller.StopTracing()
finally:
if interval:
ui.PrintMessage('done')
return _GetResults(all_results, controller, output, compress, write_json,
interval)

View File

@@ -0,0 +1,58 @@
# 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 os
import unittest
import zipfile
from profile_chrome import profiler
from profile_chrome import ui
from profile_chrome import fake_agent_1
from profile_chrome import fake_agent_2
from systrace import decorators
from systrace import tracing_controller
class ProfilerTest(unittest.TestCase):
def setUp(self):
ui.EnableTestMode()
self._tracing_options = tracing_controller.TracingControllerConfig(None,
None, None, None, None, None, None, None, None, None)
@decorators.ClientOnlyTest
def testCaptureBasicProfile(self):
result = profiler.CaptureProfile(self._tracing_options, 1, [fake_agent_1])
try:
self.assertTrue(os.path.exists(result))
self.assertTrue(result.endswith('.html'))
finally:
if os.path.exists(result):
os.remove(result)
@decorators.ClientOnlyTest
def testCaptureJsonProfile(self):
result = profiler.CaptureProfile(self._tracing_options, 1,
[fake_agent_2], write_json=True)
try:
self.assertFalse(result.endswith('.html'))
with open(result) as f:
self.assertEquals(f.read(), 'fake-contents')
finally:
if os.path.exists(result):
os.remove(result)
@decorators.ClientOnlyTest
def testCaptureMultipleProfiles(self):
result = profiler.CaptureProfile(self._tracing_options, 1,
[fake_agent_1, fake_agent_2],
write_json=True)
try:
self.assertTrue(result.endswith('.zip'))
self.assertTrue(zipfile.is_zipfile(result))
finally:
if os.path.exists(result):
os.remove(result)

View File

@@ -0,0 +1,3 @@
#!/bin/sh
cd $(dirname $0)/../
exec python -m unittest discover profile_chrome '*_unittest.py' $@

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,15 @@
Name: Perf to JSON conversion script
Short Name: perf_to_json
URL: http://www.chromium.org
Version: 0
Date: 21.7.2014
Revision: 0
License: GPL
License File: NOT_SHIPPED
Security Critical: No
Description:
Script for converting perf script events into tracing JSON.
Local Modifications:
None.

View File

@@ -0,0 +1,248 @@
# Script for converting perf script events into tracing JSON.
#
# Generated by perf script -g python
# Licensed under the terms of the GNU GPL License version 2
import json
import os
import sys
from collections import deque
# Categorize DSOs by component.
dso_to_comp = {
'libdvm.so': 'Java',
'libart.so': 'Java',
'libjavacore.so': 'Java',
'libandroid_runtime.so': 'Android',
'libgui.so': 'Android',
'libui.so': 'Android',
'libbinder.so': 'Android',
'libmemalloc.so': 'Android',
'libcrypto.so': 'Android',
'libcutils.so':'Android',
'libutils.so': 'Android',
'[kernel.kallsyms]': 'Kernel',
'libc.so': 'Standard Lib',
'libstdc++.so': 'Standard Lib',
'libm.so':'Standard Lib',
'libGLESv2_adreno.so': 'GPU Driver',
'libGLESv2_adreno200.so': 'GPU Driver',
'libq3dtools_adreno200.so': 'GPU Driver',
'libEGL_adreno.so': 'GPU Driver',
'libEGL_adreno200.so': 'GPU Driver',
'libEGL.so': 'GPU Driver',
'libgsl.so': 'GPU Driver',
'libGLESv2.so': 'GPU Driver',
'libsc-a3xx.so': 'GPU Driver',
'libadreno_utils.so': 'GPU Driver',
'eglsubAndroid.so': 'GPU Driver',
'gralloc.msm8960.so': 'GPU Driver',
'libadreno_utils': 'GPU Driver',
'libGLES_mali.so': 'GPU Driver',
'libchromeview.so': 'Chrome',
'[unknown]': '<unknown>',
'[UNKNOWN]': '<unknown>',
}
def FilterSymbolModule(module):
m = dso_to_comp.get(module, None)
if m:
return m
if module.find('libchrome.') == 0:
return 'Chrome'
if module.find('dalvik') >= 0 or module.find('@') >= 0:
return 'Java'
return module
def FilterSymbolName(module, orign_module, name):
if module == 'Java':
return name
elif module == 'GPU Driver':
return name
if name == '':
return orign_module + ':unknown'
if name[0].isdigit() or name == '(nil)':
return orign_module + ':unknown'
return name
class StackFrameNode:
def __init__(self, stack_id, name, category):
self.stack_id = stack_id
self.parent_id = 0
self.children = {}
self.category = category
self.name = name
self.samples = []
self.total_weight = 0.0
self.have_total_weight = False
self.parent = None
def ToDict(self, out_dict):
if self.stack_id:
node_dict = {}
node_dict['name'] = self.name
node_dict['category'] = self.category
if self.parent_id:
node_dict['parent'] = self.parent_id
out_dict[self.stack_id] = node_dict
for child in self.children.values():
child.ToDict(out_dict)
return out_dict
def GetTotalWeight(self):
if self.have_total_weight:
return self.total_weight
else:
# Sum up self samples weight, and children's total weights.
for s in self.samples:
self.total_weight += s.weight
for c in self.children.values():
self.total_weight += c.GetTotalWeight()
self.have_total_weight = True
return self.total_weight
class PerfSample:
def __init__(self, stack_id, ts, cpu, tid, weight, samp_type, comm):
self.stack_id = stack_id
self.ts = ts
self.cpu = cpu
self.tid = tid
self.weight = weight
self.type = samp_type
self.comm = comm
def ToDict(self):
ret = {}
ret['ts'] = self.ts / 1000.0 # Timestamp in microseconds
ret['tid'] = self.tid # Thread id
ret['cpu'] = self.cpu # Sampled CPU
ret['weight'] = self.weight # Sample weight
ret['name'] = self.type # Sample type
ret['comm'] = self.comm # Sample type
assert self.stack_id != 0
if self.stack_id:
ret['sf'] = self.stack_id # Stack frame id
return ret
samples = []
root_chain = StackFrameNode(0, 'root', '[unknown]')
next_stack_id = 1
tot_period = 0
saved_period = 0
def process_event(param_dict):
global next_stack_id
global saved_period
global tot_period
samp_comm = param_dict['comm']
samp_tid = param_dict['tid']
samp_cpu = param_dict['cpu']
samp_ts = param_dict['time']
samp_period = param_dict['period']
samp_type = param_dict['ev_name']
tot_period += samp_period
# Parse call chain.
seen_syms = set()
chain = deque()
for cs in param_dict['cs']:
cs_name = cs[0]
cs_dso = os.path.basename(cs[1])
cs_category = FilterSymbolModule(cs_dso)
cs_name = FilterSymbolName(cs_category, cs_dso, cs_name)
if cs_category != '<unknown>' or len(chain) == 0:
sym = (cs_name, cs_category)
if sym in seen_syms:
while chain[0] != sym:
seen_syms.remove(chain[0])
chain.popleft()
else:
seen_syms.add(sym)
chain.appendleft(sym)
# Discard garbage stacktrace before __pthread_start()
if cs_name == '__pthread_start(void*)':
break
# Done reading call chain. Add to stack frame tree.
stack_frame = root_chain
for call in chain:
if call in stack_frame.children:
stack_frame = stack_frame.children[call]
else:
new_node = StackFrameNode(next_stack_id, call[0], call[1])
next_stack_id += 1
new_node.parent_id = stack_frame.stack_id
stack_frame.children[call] = new_node
stack_frame = new_node
# Save sample.
sample = PerfSample(stack_frame.stack_id,
samp_ts,
samp_cpu,
samp_tid,
samp_period,
samp_type,
samp_comm)
samples.append(sample)
stack_frame.samples.append(sample)
saved_period += samp_period
def trace_begin():
pass
def trace_end():
# Return siblings of a call tree node.
def GetNodeSiblings(node):
if not node:
return []
if not node.parent:
return []
return node.parent.children.values()
# Try to reduce misplaced stack leaves by moving them up into sibling nodes.
def FixCallTree(node, parent):
# Get siblings of node's parent.
node.parent = parent
parent_siblings = GetNodeSiblings(parent)
# If parent's sibling has same node name, has no children and small weight,
# transplant sibling's samples into the current node.
for sibling in parent_siblings:
if sibling.name == node.name and \
len(sibling.children) == 0 and \
sibling.GetTotalWeight() <= node.GetTotalWeight() * 0.15:
# Transplant samples from sibling to current node.
for samp in sibling.samples:
samp.stack_id = node.stack_id
node.samples.append(samp)
sibling.samples = []
break
# Recurse child nodes.
for c in node.children.values():
FixCallTree(c, node)
FixCallTree(root_chain, None)
trace_dict = {}
trace_dict['samples'] = [s.ToDict() for s in samples]
trace_dict['stackFrames'] = root_chain.ToDict({})
trace_dict['traceEvents'] = []
json.dump(trace_dict, sys.stdout, indent=1)

View File

@@ -0,0 +1,27 @@
# 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 logging
import select
import sys
def PrintMessage(heading, eol='\n'):
sys.stdout.write('%s%s' % (heading, eol))
sys.stdout.flush()
def WaitForEnter(timeout):
select.select([sys.stdin], [], [], timeout)
def EnableTestMode():
def NoOp(*_, **__): # pylint: disable=unused-argument
pass
# pylint: disable=W0601
global PrintMessage
global WaitForEnter
PrintMessage = NoOp
WaitForEnter = NoOp
logging.getLogger().disabled = True

View File

@@ -0,0 +1,35 @@
# 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 gzip
import os
import time
import zipfile
def ArchiveFiles(host_files, output):
with zipfile.ZipFile(output, 'w', zipfile.ZIP_DEFLATED) as z:
for host_file in host_files:
z.write(host_file)
os.unlink(host_file)
def CompressFile(host_file, output):
with gzip.open(output, 'wb') as out, open(host_file, 'rb') as input_file:
out.write(input_file.read())
os.unlink(host_file)
def ArchiveData(trace_results, output):
with zipfile.ZipFile(output, 'w', zipfile.ZIP_DEFLATED) as z:
for result in trace_results:
trace_file = result.source_name + GetTraceTimestamp()
WriteDataToCompressedFile(result.raw_data, trace_file)
z.write(trace_file)
os.unlink(trace_file)
def WriteDataToCompressedFile(data, output):
with gzip.open(output, 'wb') as out:
out.write(data)
def GetTraceTimestamp():
return time.strftime('%Y-%m-%d-%H%M%S', time.localtime())

View File

@@ -0,0 +1,67 @@
[MESSAGES CONTROL]
# Disable the message, report, category or checker with the given id(s).
# TODO: Shrink this list to as small as possible.
disable=
design,
similarities,
abstract-class-not-used,
bad-builtin,
bad-continuation,
eval-used,
fixme,
invalid-name,
locally-disabled,
missing-docstring,
protected-access,
star-args,
[REPORTS]
# Don't write out full reports, just messages.
reports=no
[BASIC]
# Regular expression which should only match correct function names.
function-rgx=^(?:(?P<exempt>setUp|tearDown|setUpModule|tearDownModule)|(?P<camel_case>_?[A-Z][a-zA-Z0-9]*))$
# Regular expression which should only match correct method names.
method-rgx=^(?:(?P<exempt>_[a-z0-9_]+__|get|post|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass)|(?P<camel_case>(_{0,2}|test|assert)[A-Z][a-zA-Z0-9_]*))$
# Regular expression which should only match correct argument names.
argument-rgx=^[a-z][a-z0-9_]*$
# Regular expression which should only match correct variable names.
variable-rgx=^[a-z][a-z0-9_]*$
# Good variable names which should always be accepted, separated by a comma.
good-names=main,_
# List of builtins function names that should not be used, separated by a comma.
bad-functions=apply,input,reduce
[VARIABLES]
# Tells wether we should check for unused import in __init__ files.
init-import=no
# A regular expression matching names used for dummy variables (i.e. not used).
dummy-variables-rgx=^\*{0,2}(_$|unused_)
[TYPECHECK]
# Tells wether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
[FORMAT]
# We use two spaces for indents, instead of the usual four spaces or tab.
indent-string=' '

View File

@@ -0,0 +1,12 @@
# Names should be added to this file with this pattern:
#
# For individuals:
# Name <email address>
#
# For organizations:
# Organization <fnmatch pattern>
#
# See python fnmatch module documentation for more information.
The Chromium Authors <*@chromium.org>
Google Inc. <*@google.com>

View File

@@ -0,0 +1,27 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,16 @@
<!-- 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.
-->
Systrace
========
Systrace relies on
[Trace-Viewer](https://github.com/catapult-project/catapult/blob/master/tracing/README.md)
to visualize the traces. The development of Trace-Viewer and Systrace is
decoupled by the systrace_trace_viewer.html file.
* The update_systrace_trace_viewer.py script generates
systrace_trace_viewer.html based on the Trace-Viewer code.
* Systrace visualizes the trace result based on systrace_trace_viewer.html.
* Systrace will auto update systrace_trace_viewer.html if
update_systrace_trace_viewer.py exists.

View File

@@ -0,0 +1,27 @@
# Copyright 2016 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 os
import sys
def _JoinPath(*path_parts):
return os.path.abspath(os.path.join(*path_parts))
def _AddDirToPythonPath(*path_parts):
path = _JoinPath(*path_parts)
if os.path.isdir(path) and path not in sys.path:
# Some call sites that use Telemetry assume that sys.path[0] is the
# directory containing the script, so we add these extra paths to right
# after sys.path[0].
sys.path.insert(1, path)
_CATAPULT_DIR = os.path.join(
os.path.dirname(os.path.abspath(__file__)), os.path.pardir, os.path.pardir)
_AddDirToPythonPath(_CATAPULT_DIR, 'common', 'py_utils')
_AddDirToPythonPath(_CATAPULT_DIR, 'common', 'py_trace_event')
_AddDirToPythonPath(_CATAPULT_DIR, 'common', 'py_trace_event', 'py_trace_event')
_AddDirToPythonPath(_CATAPULT_DIR, 'devil')
_AddDirToPythonPath(_CATAPULT_DIR, 'systrace')
_AddDirToPythonPath(_CATAPULT_DIR, 'tracing')

View File

@@ -0,0 +1,41 @@
# Copyright 2016 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.
def HostOnlyTest(func):
"""Decorator for running unit tests only on the host device.
This will disable unit tests from running on Android devices.
"""
return _SkipTestDecoratorHelper(func, ['android'])
def ClientOnlyTest(func):
"""Decorator for running unit tests only on client devices (Android).
"""
return _SkipTestDecoratorHelper(func, ['win', 'linux', 'mac'])
def Disabled(func):
"""Decorator for not running a unit test on any Trybot platform.
"""
return _SkipTestDecoratorHelper(func, ['win', 'linux', 'mac', 'android'])
def LinuxMacTest(func):
return _SkipTestDecoratorHelper(func, ['win', 'android'])
def _SkipTestDecoratorHelper(func, disabled_strings):
if not hasattr(func, '_disabled_strings'):
setattr(func, '_disabled_strings', set(disabled_strings))
return func
def ShouldSkip(test, device):
"""Returns whether the test should be skipped and the reason for it."""
if hasattr(test, '_disabled_strings'):
disabled_devices = getattr(test, '_disabled_strings')
return device in disabled_devices
return False

View File

@@ -0,0 +1,52 @@
# Copyright 2016 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 os
import unittest
from systrace import decorators
from systrace import update_systrace_trace_viewer
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
STABLE_VIEWER_PATH = os.path.join(SCRIPT_DIR, 'systrace_trace_viewer.html')
# Tests presence and content of static HTML files used not only for Python
# systrace capture, but also Java-based capture in the android SDK tools.
#
# NOTE: changes to this file should typically be accompanied by changes to the
# Android SDK's method of systrace capture.
class MonitorTest(unittest.TestCase):
@decorators.HostOnlyTest
def test_systrace_trace_viewer(self):
self.assertEqual(STABLE_VIEWER_PATH,
update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE)
update_systrace_trace_viewer.update(force_update=True)
with open(STABLE_VIEWER_PATH) as f:
content = f.read().strip()
# expect big html file
self.assertGreater(5 * 1024 * 1024, len(content))
self.assertEqual('<', content[0])
os.remove(f.name)
@decorators.HostOnlyTest
def test_prefix(self):
with open(os.path.join(SCRIPT_DIR, 'prefix.html')) as f:
content = f.read().strip()
self.assertTrue("<html>" in content)
self.assertTrue("<title>Android System Trace</title>" in content)
self.assertTrue("{{SYSTRACE_TRACE_VIEWER_HTML}}" in content)
@decorators.HostOnlyTest
def test_suffix(self):
with open(os.path.join(SCRIPT_DIR, 'suffix.html')) as f:
content = f.read().strip()
self.assertTrue("</html>" in content)

View File

@@ -0,0 +1,190 @@
#!/usr/bin/env python
# Copyright 2016 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 base64
import gzip
import json
import os
import StringIO
from systrace import tracing_controller
from systrace import trace_result
from tracing.trace_data import trace_data
# TODO(alexandermont): Current version of trace viewer does not support
# the controller tracing agent output. Thus we use this variable to
# suppress this tracing agent's output. This should be removed once
# trace viewer is working again.
OUTPUT_CONTROLLER_TRACE_ = False
CONTROLLER_TRACE_DATA_KEY = 'controllerTraceDataKey'
_SYSTRACE_TO_TRACE_DATA_NAME_MAPPING = {
'androidProcessDump': trace_data.ANDROID_PROCESS_DATA_PART,
'atraceProcessDump': trace_data.ATRACE_PROCESS_DUMP_PART,
'systemTraceEvents': trace_data.ATRACE_PART,
'systraceController': trace_data.TELEMETRY_PART,
'traceEvents': trace_data.CHROME_TRACE_PART,
'waltTrace': trace_data.WALT_TRACE_PART,
}
_SYSTRACE_HEADER = 'Systrace'
def NewGenerateHTMLOutput(trace_results, output_file_name):
with trace_data.TraceDataBuilder() as builder:
for trace in trace_results:
trace_data_part = _SYSTRACE_TO_TRACE_DATA_NAME_MAPPING.get(
trace.source_name)
builder.AddTraceFor(
trace_data_part, trace.raw_data, allow_unstructured=True)
builder.Serialize(output_file_name, _SYSTRACE_HEADER)
def GenerateHTMLOutput(trace_results, output_file_name):
"""Write the results of systrace to an HTML file.
Args:
trace_results: A list of TraceResults.
output_file_name: The name of the HTML file that the trace viewer
results should be written to.
"""
def _ReadAsset(src_dir, filename):
return open(os.path.join(src_dir, filename)).read()
# TODO(rnephew): The tracing output formatter is able to handle a single
# systrace trace just as well as it handles multiple traces. The obvious thing
# to do here would be to use it all for all systrace output: however, we want
# to continue using the legacy way of formatting systrace output when a single
# systrace and the tracing controller trace are present in order to match the
# Java verison of systrace. Java systrace is expected to be deleted at a later
# date. We should consolidate this logic when that happens.
if len(trace_results) > 3:
NewGenerateHTMLOutput(trace_results, output_file_name)
return os.path.abspath(output_file_name)
systrace_dir = os.path.abspath(os.path.dirname(__file__))
try:
from systrace import update_systrace_trace_viewer
except ImportError:
pass
else:
update_systrace_trace_viewer.update()
trace_viewer_html = _ReadAsset(systrace_dir, 'systrace_trace_viewer.html')
# Open the file in binary mode to prevent python from changing the
# line endings, then write the prefix.
systrace_dir = os.path.abspath(os.path.dirname(__file__))
html_prefix = _ReadAsset(systrace_dir, 'prefix.html')
html_suffix = _ReadAsset(systrace_dir, 'suffix.html')
trace_viewer_html = _ReadAsset(systrace_dir,
'systrace_trace_viewer.html')
# Open the file in binary mode to prevent python from changing the
# line endings, then write the prefix.
html_file = open(output_file_name, 'wb')
html_file.write(html_prefix.replace('{{SYSTRACE_TRACE_VIEWER_HTML}}',
trace_viewer_html))
# Write the trace data itself. There is a separate section of the form
# <script class="trace-data" type="application/text"> ... </script>
# for each tracing agent (including the controller tracing agent).
html_file.write('<!-- BEGIN TRACE -->\n')
for result in trace_results:
html_file.write(' <script class="trace-data" type="application/text">\n')
html_file.write(_ConvertToHtmlString(result.raw_data))
html_file.write(' </script>\n')
html_file.write('<!-- END TRACE -->\n')
# Write the suffix and finish.
html_file.write(html_suffix)
html_file.close()
final_path = os.path.abspath(output_file_name)
return final_path
def _ConvertToHtmlString(result):
"""Convert a trace result to the format to be output into HTML.
If the trace result is a dictionary or list, JSON-encode it.
If the trace result is a string, leave it unchanged.
"""
if isinstance(result, dict) or isinstance(result, list):
return json.dumps(result)
elif isinstance(result, str):
return result
else:
raise ValueError('Invalid trace result format for HTML output')
def GenerateJSONOutput(trace_results, output_file_name):
"""Write the results of systrace to a JSON file.
Args:
trace_results: A list of TraceResults.
output_file_name: The name of the JSON file that the trace viewer
results should be written to.
"""
results = _ConvertTraceListToDictionary(trace_results)
results[CONTROLLER_TRACE_DATA_KEY] = (
tracing_controller.TRACE_DATA_CONTROLLER_NAME)
with open(output_file_name, 'w') as json_file:
json.dump(results, json_file)
final_path = os.path.abspath(output_file_name)
return final_path
def MergeTraceResultsIfNeeded(trace_results):
"""Merge a list of trace data, if possible. This function can take any list
of trace data, but it will only merge the JSON data (since that's all
we can merge).
Args:
trace_results: A list of TraceResults containing trace data.
"""
if len(trace_results) <= 1:
return trace_results
merge_candidates = []
for result in trace_results:
# Try to detect a JSON file cheaply since that's all we can merge.
if result.raw_data[0] != '{':
continue
try:
json_data = json.loads(result.raw_data)
except ValueError:
continue
merge_candidates.append(trace_result.TraceResult(result.source_name,
json_data))
if len(merge_candidates) <= 1:
return trace_results
other_results = [r for r in trace_results
if not r.source_name in
[c.source_name for c in merge_candidates]]
merged_data = merge_candidates[0].raw_data
for candidate in merge_candidates[1:]:
json_data = candidate.raw_data
for key, value in json_data.items():
if not str(key) in merged_data or not merged_data[str(key)]:
merged_data[str(key)] = value
return ([trace_result.TraceResult('merged-data', json.dumps(merged_data))]
+ other_results)
def _EncodeTraceData(trace_string):
compressed_trace = StringIO.StringIO()
with gzip.GzipFile(fileobj=compressed_trace, mode='w') as f:
f.write(trace_string)
b64_content = base64.b64encode(compressed_trace.getvalue())
return b64_content
def _ConvertTraceListToDictionary(trace_list):
trace_dict = {}
for trace in trace_list:
trace_dict[trace.source_name] = trace.raw_data
return trace_dict

View File

@@ -0,0 +1,111 @@
#!/usr/bin/env python
# Copyright 2016 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 hashlib
import json
import os
import unittest
from py_utils import tempfile_ext
from systrace import decorators
from systrace import output_generator
from systrace import trace_result
from systrace import update_systrace_trace_viewer
from tracing.trace_data import trace_data as trace_data_module
TEST_DIR = os.path.join(os.path.dirname(__file__), 'test_data')
ATRACE_DATA = os.path.join(TEST_DIR, 'atrace_data')
ATRACE_PROCESS_DUMP_DATA = os.path.join(TEST_DIR, 'atrace_procfs_dump')
COMBINED_PROFILE_CHROME_DATA = os.path.join(
TEST_DIR, 'profile-chrome_systrace_perf_chrome_data')
class OutputGeneratorTest(unittest.TestCase):
@decorators.HostOnlyTest
def testJsonTraceMerging(self):
update_systrace_trace_viewer.update(force_update=True)
self.assertTrue(os.path.exists(
update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE))
t1 = "{'traceEvents': [{'ts': 123, 'ph': 'b'}]}"
t2 = "{'traceEvents': [], 'stackFrames': ['blah']}"
results = [trace_result.TraceResult('a', t1),
trace_result.TraceResult('b', t2)]
merged_results = output_generator.MergeTraceResultsIfNeeded(results)
for r in merged_results:
if r.source_name == 'a':
self.assertEquals(r.raw_data, t1)
elif r.source_name == 'b':
self.assertEquals(r.raw_data, t2)
self.assertEquals(len(merged_results), len(results))
os.remove(update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE)
@decorators.HostOnlyTest
def testHtmlOutputGenerationFormatsSingleTrace(self):
update_systrace_trace_viewer.update(force_update=True)
self.assertTrue(os.path.exists(
update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE))
with open(ATRACE_DATA) as f:
atrace_data = f.read().replace(" ", "").strip()
trace_results = [trace_result.TraceResult('systemTraceEvents', atrace_data)]
with tempfile_ext.TemporaryFileName() as output_file_name:
output_generator.GenerateHTMLOutput(trace_results, output_file_name)
with open(output_file_name, 'r') as f:
html_output = f.read()
trace_data = (html_output.split(
'<script class="trace-data" type="application/text">')[1].split(
'</script>'))[0].replace(" ", "").strip()
# Ensure the trace data written in HTML is located within the
# correct place in the HTML document and that the data is not
# malformed.
self.assertEquals(trace_data, atrace_data)
os.remove(update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE)
@decorators.HostOnlyTest
def testHtmlOutputGenerationFormatsMultipleTraces(self):
trace_results = []
with trace_data_module.TraceDataBuilder() as trace_data_builder:
with open(ATRACE_DATA) as fp:
atrace_data = fp.read()
trace_results.append(
trace_result.TraceResult('systemTraceEvents', atrace_data))
trace_data_builder.AddTraceFor(trace_data_module.ATRACE_PART, atrace_data,
allow_unstructured=True)
with open(ATRACE_PROCESS_DUMP_DATA) as fp:
atrace_process_dump_data = fp.read()
trace_results.append(trace_result.TraceResult(
'atraceProcessDump', atrace_process_dump_data))
trace_data_builder.AddTraceFor(trace_data_module.ATRACE_PROCESS_DUMP_PART,
atrace_process_dump_data,
allow_unstructured=True)
with open(COMBINED_PROFILE_CHROME_DATA) as fp:
chrome_data = json.load(fp)
trace_results.append(
trace_result.TraceResult('traceEvents', chrome_data))
trace_data_builder.AddTraceFor(
trace_data_module.CHROME_TRACE_PART, chrome_data)
trace_results.append(
trace_result.TraceResult('systraceController', str({})))
trace_data_builder.AddTraceFor(trace_data_module.TELEMETRY_PART, {})
with tempfile_ext.NamedTemporaryDirectory() as temp_dir:
data_builder_out = os.path.join(temp_dir, 'data_builder.html')
output_generator_out = os.path.join(temp_dir, 'output_generator.html')
output_generator.GenerateHTMLOutput(trace_results, output_generator_out)
trace_data_builder.Serialize(data_builder_out, 'Systrace')
output_generator_md5sum = hashlib.md5(
open(output_generator_out, 'rb').read()).hexdigest()
data_builder_md5sum = hashlib.md5(
open(data_builder_out, 'rb').read()).hexdigest()
self.assertEqual(output_generator_md5sum, data_builder_md5sum)

View File

@@ -0,0 +1,70 @@
<!DOCTYPE html>
<html>
<head i18n-values="dir:textdirection;">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta charset="utf-8"/>
<title>Android System Trace</title>
<style>
html,
body {
height: 100%;
}
body {
-webkit-flex-direction: column;
display: -webkit-flex;
margin: 0;
padding: 0;
}
body > tr-ui-timeline-view {
-webkit-flex: 1 1 auto;
min-height: 0;
}
body > tr-ui-timeline-view:focus {
outline: none;
}
</style>
{{SYSTRACE_TRACE_VIEWER_HTML}}
</head>
<body>
<tr-ui-timeline-view>
<track-view-container id='track_view_container'></track-view-container>
</tr-ui-timeline-view>
<script>
'use strict';
var timelineViewEl;
function onLoad() {
timelineViewEl = document.querySelector('tr-ui-timeline-view');
timelineViewEl.globalMode = true;
var traceDataEls = document.body.querySelectorAll('.trace-data');
var traces = [];
for (var i = 0; i < traceDataEls.length; i++) {
var traceText = traceDataEls[i].textContent;
// Remove the leading newline.
traceText = traceText.substring(1);
traces.push(traceText);
}
var m = new tr.Model();
var i = new tr.importer.Import(m);
var p = i.importTracesWithProgressDialog(traces);
p.then(
function() {
timelineViewEl.model = m;
timelineViewEl.updateDocumentFavicon();
timelineViewEl.globalMode = true;
timelineViewEl.viewTitle = 'Android System Trace';
},
function(err) {
var overlay = new tr.ui.b.Overlay();
overlay.textContent = tr.b.normalizeException(err).message;
overlay.title = 'Import error';
overlay.visible = true;
});
}
window.addEventListener('load', onLoad);
</script>

View File

@@ -0,0 +1,207 @@
#!/usr/bin/env python
# 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.
"""Android system-wide tracing utility.
This is a tool for capturing a trace that includes data from both userland and
the kernel. It creates an HTML file for visualizing the trace.
"""
# Make sure we're using a new enough version of Python.
# The flags= parameter of re.sub() is new in Python 2.7. And Systrace does not
# support Python 3 yet.
# pylint: disable=wrong-import-position
import sys
version = sys.version_info[:2]
if version != (2, 7):
sys.stderr.write('This script does not support Python %d.%d. '
'Please use Python 2.7.\n' % version)
sys.exit(1)
import optparse
import os
import time
_SYSTRACE_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.path.pardir))
_CATAPULT_DIR = os.path.join(
os.path.dirname(os.path.abspath(__file__)), os.path.pardir, os.path.pardir)
_DEVIL_DIR = os.path.join(_CATAPULT_DIR, 'devil')
if _DEVIL_DIR not in sys.path:
sys.path.insert(0, _DEVIL_DIR)
if _SYSTRACE_DIR not in sys.path:
sys.path.insert(0, _SYSTRACE_DIR)
from devil import devil_env
from devil.android.sdk import adb_wrapper
from systrace import systrace_runner
from systrace import util
from systrace.tracing_agents import atrace_agent
from systrace.tracing_agents import atrace_from_file_agent
from systrace.tracing_agents import atrace_process_dump
from systrace.tracing_agents import ftrace_agent
from systrace.tracing_agents import walt_agent
ALL_MODULES = [atrace_agent, atrace_from_file_agent, atrace_process_dump,
ftrace_agent, walt_agent]
def parse_options(argv):
"""Parses and checks the command-line options.
Returns:
A tuple containing the options structure and a list of categories to
be traced.
"""
usage = 'Usage: %prog [options] [category1 [category2 ...]]'
desc = 'Example: %prog -b 32768 -t 15 gfx input view sched freq'
parser = optparse.OptionParser(usage=usage, description=desc,
conflict_handler='resolve')
parser = util.get_main_options(parser)
parser.add_option('-l', '--list-categories', dest='list_categories',
default=False, action='store_true',
help='list the available categories and exit')
# Add the other agent parsing options to the parser. For Systrace on the
# command line, all agents are added. For Android, only the compatible agents
# will be added.
for module in ALL_MODULES:
option_group = module.add_options(parser)
if option_group:
parser.add_option_group(option_group)
options, categories = parser.parse_args(argv[1:])
if options.output_file is None:
base = 'trace'
if options.from_file is not None:
base = os.path.splitext(options.from_file)[0]
suffix = '.json' if options.write_json else '.html'
options.output_file = base + suffix
if options.link_assets or options.asset_dir != 'trace-viewer':
parser.error('--link-assets and --asset-dir are deprecated.')
if options.trace_time and options.trace_time < 0:
parser.error('the trace time must be a non-negative number')
if (options.trace_buf_size is not None) and (options.trace_buf_size <= 0):
parser.error('the trace buffer size must be a positive number')
return (options, categories)
def find_adb():
"""Finds adb on the path.
This method is provided to avoid the issue of diskutils.spawn's
find_executable which first searches the current directory before
searching $PATH. That behavior results in issues where systrace.py
uses a different adb than the one in the path.
"""
paths = os.environ['PATH'].split(os.pathsep)
executable = 'adb'
if sys.platform == 'win32':
executable = executable + '.exe'
for p in paths:
f = os.path.join(p, executable)
if os.path.isfile(f):
return f
return None
def initialize_devil():
"""Initialize devil to use adb from $PATH"""
adb_path = find_adb()
if adb_path is None:
print >> sys.stderr, "Unable to find adb, is it in your path?"
sys.exit(1)
devil_dynamic_config = {
'config_type': 'BaseConfig',
'dependencies': {
'adb': {
'file_info': {
devil_env.GetPlatform(): {
'local_paths': [os.path.abspath(adb_path)]
}
}
}
}
}
devil_env.config.Initialize(configs=[devil_dynamic_config])
def main_impl(arguments):
# Parse the command line options.
options, categories = parse_options(arguments)
# Override --atrace-categories and --ftrace-categories flags if command-line
# categories are provided.
if categories:
if options.target == 'android':
options.atrace_categories = categories
elif options.target == 'linux':
options.ftrace_categories = categories
else:
raise RuntimeError('Categories are only valid for atrace/ftrace. Target '
'platform must be either Android or Linux.')
# Include atrace categories by default in Systrace.
if options.target == 'android' and not options.atrace_categories:
options.atrace_categories = atrace_agent.DEFAULT_CATEGORIES
if options.target == 'android' and not options.from_file:
initialize_devil()
devices = [a.GetDeviceSerial() for a in adb_wrapper.AdbWrapper.Devices()]
if not options.device_serial_number:
if len(devices) == 0:
raise RuntimeError('No ADB devices connected.')
elif len(devices) >= 2:
raise RuntimeError('Multiple devices connected, serial number required')
options.device_serial_number = devices[0]
elif options.device_serial_number not in devices:
raise RuntimeError('Device with the serial number "%s" is not connected.'
% options.device_serial_number)
# If list_categories is selected, just print the list of categories.
# In this case, use of the tracing controller is not necessary.
if options.list_categories:
if options.target == 'android':
atrace_agent.list_categories(options)
elif options.target == 'linux':
ftrace_agent.list_categories(options)
return
# Set up the systrace runner and start tracing.
controller = systrace_runner.SystraceRunner(
os.path.dirname(os.path.abspath(__file__)), options)
controller.StartTracing()
# Wait for the given number of seconds or until the user presses enter.
# pylint: disable=superfluous-parens
# (need the parens so no syntax error if trying to load with Python 3)
if options.from_file is not None:
print('Reading results from file.')
elif options.trace_time:
print('Starting tracing (%d seconds)' % options.trace_time)
time.sleep(options.trace_time)
else:
raw_input('Starting tracing (stop with enter)')
# Stop tracing and collect the output.
print('Tracing completed. Collecting output...')
controller.StopTracing()
print('Outputting Systrace results...')
controller.OutputSystraceResults(write_json=options.write_json)
def main():
main_impl(sys.argv)
if __name__ == '__main__' and __package__ is None:
main()

View File

@@ -0,0 +1,2 @@
</body>
</html>

View File

@@ -0,0 +1,70 @@
#!/usr/bin/env python
# Copyright 2016 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.
'''Implementation of tracing controller for systrace. This class creates the
necessary tracing agents for systrace, runs them, and outputs the results
as an HTML or JSON file.'''
from systrace import output_generator
from systrace import tracing_controller
from systrace.tracing_agents import android_process_data_agent
from systrace.tracing_agents import atrace_agent
from systrace.tracing_agents import atrace_from_file_agent
from systrace.tracing_agents import atrace_process_dump
from systrace.tracing_agents import ftrace_agent
from systrace.tracing_agents import walt_agent
AGENT_MODULES = [android_process_data_agent, atrace_agent,
atrace_from_file_agent, atrace_process_dump,
ftrace_agent, walt_agent]
class SystraceRunner(object):
def __init__(self, script_dir, options):
"""Constructor.
Args:
script_dir: Directory containing the trace viewer script
(systrace_trace_viewer.html)
options: Object containing command line options.
"""
# Parse command line arguments and create agents.
self._script_dir = script_dir
self._out_filename = options.output_file
agents_with_config = tracing_controller.CreateAgentsWithConfig(
options, AGENT_MODULES)
controller_config = tracing_controller.GetControllerConfig(options)
# Set up tracing controller.
self._tracing_controller = tracing_controller.TracingController(
agents_with_config, controller_config)
def StartTracing(self):
self._tracing_controller.StartTracing()
def StopTracing(self):
self._tracing_controller.StopTracing()
def OutputSystraceResults(self, write_json=False):
"""Output the results of systrace to a file.
If output is necessary, then write the results of systrace to either (a)
a standalone HTML file, or (b) a json file which can be read by the
trace viewer.
Args:
write_json: Whether to output to a json file (if false, use HTML file)
"""
print 'Tracing complete, writing results'
if write_json:
result = output_generator.GenerateJSONOutput(
self._tracing_controller.all_results,
self._out_filename)
else:
result = output_generator.GenerateHTMLOutput(
self._tracing_controller.all_results,
self._out_filename)
print '\nWrote trace %s file: file://%s\n' % (('JSON' if write_json
else 'HTML'), result)

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,127 @@
# tracer: nop
#
# entries-in-buffer/entries-written: 116/116 #P:1
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
atrace-14446 [000] ...2 1212.465062: sched_switch: prev_comm=atrace prev_pid=14446 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.465074: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.465082: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.465092: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.465102: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.465126: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.465132: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.465139: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.465145: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.465227: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h5 1212.465297: sched_wakeup: comm=adbd pid=212 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.465306: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=adbd next_pid=212 next_prio=120
dsx_exp_workque-212 [000] d..4 1212.465329: sched_wakeup: comm=adbd pid=209 prio=120 success=1 target_cpu=000
dsx_exp_workque-212 [000] ...2 1212.465348: sched_switch: prev_comm=adbd prev_pid=212 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=209 next_prio=120
uether-209 [000] d..4 1212.465395: sched_wakeup: comm=adbd pid=211 prio=120 success=1 target_cpu=000
uether-209 [000] ...2 1212.465441: sched_switch: prev_comm=adbd prev_pid=209 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=211 next_prio=120
dsx_rebuild_wor-211 [000] ...2 1212.465448: sched_switch: prev_comm=adbd prev_pid=211 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h5 1212.574554: sched_wakeup: comm=sensors.qcom pid=292 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.574566: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=sensors.qcom next_pid=292 next_prio=120
irq/363-ARM64 s-292 [000] ...2 1212.574665: sched_switch: prev_comm=sensors.qcom prev_pid=292 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 [000] d..4 1212.574797: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
sensors.qcom-14447 [000] ...2 1212.574802: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
sensors.qcom-1593 [000] ...2 1212.574819: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=D ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 [000] d..3 1212.574823: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
sensors.qcom-14447 [000] ...2 1212.574827: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
sensors.qcom-1593 [000] d..4 1212.574865: sched_wakeup: comm=sensors.qcom pid=760 prio=120 success=1 target_cpu=000
sensors.qcom-1593 [000] ...2 1212.574876: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=760 next_prio=120
sensors.qcom-760 [000] d..4 1212.574905: sched_wakeup: comm=system_server pid=782 prio=118 success=1 target_cpu=000
sensors.qcom-760 [000] ...2 1212.574917: sched_switch: prev_comm=sensors.qcom prev_pid=760 prev_prio=120 prev_state=S ==> next_comm=system_server next_pid=782 next_prio=118
system_server-782 [000] d..4 1212.574981: sched_wakeup: comm=system_server pid=785 prio=118 success=1 target_cpu=000
system_server-782 [000] ...2 1212.575009: sched_switch: prev_comm=system_server prev_pid=782 prev_prio=118 prev_state=S ==> next_comm=system_server next_pid=785 next_prio=118
system_server-785 [000] ...2 1212.575045: sched_switch: prev_comm=system_server prev_pid=785 prev_prio=118 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 [000] ...3 1212.575143: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=x ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.575153: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.575159: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.575167: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.575175: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.575181: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.575188: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.575195: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.575201: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.575211: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1212.649601: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.649614: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 [000] ...2 1212.649630: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h6 1212.729539: sched_wakeup: comm=kworker/u:1 pid=21 prio=120 success=1 target_cpu=000
<idle>-0 [000] dNs6 1212.729550: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.729563: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:1 next_pid=21 next_prio=120
kworker/u:1-21 [000] d..5 1212.729571: sched_wakeup: comm=mpdecision pid=2046 prio=113 success=1 target_cpu=000
kworker/u:1-21 [000] ...2 1212.729578: sched_switch: prev_comm=kworker/u:1 prev_pid=21 prev_prio=120 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
thermal-engine-557 [000] d..4 1212.729597: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
thermal-engine-557 [000] ...2 1212.729600: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=D ==> next_comm=mpdecision next_pid=2046 next_prio=113
mpdecision-2046 [000] ...2 1212.729801: sched_switch: prev_comm=mpdecision prev_pid=2046 prev_prio=113 prev_state=S ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 [000] ...2 1212.730104: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.730134: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.730154: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.730176: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.730201: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.730220: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.730241: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.730262: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.730280: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.730303: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h6 1212.730638: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.730669: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
migration/0-7 [000] d..6 1212.730707: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
migration/0-7 [000] ...2 1212.730728: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 [000] ...2 1212.730916: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h6 1212.731632: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.731661: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
migration/0-7 [000] d..6 1212.731702: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
migration/0-7 [000] ...2 1212.731722: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 [000] ...2 1212.731832: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h6 1212.732685: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.732714: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
migration/0-7 [000] d..6 1212.732747: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
migration/0-7 [000] ...2 1212.732767: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 [000] d..4 1212.732810: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
kworker/0:1H-17 [000] ...2 1212.732829: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
thermal-engine-557 [000] ...2 1212.732854: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1212.876266: sched_wakeup: comm=RILSender0 pid=1365 prio=120 success=1 target_cpu=000
<idle>-0 [000] dNh4 1212.876284: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.876316: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=RILSender0 next_pid=1365 next_prio=120
RILSender0-1365 [000] ...2 1212.876415: sched_switch: prev_comm=RILSender0 prev_pid=1365 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 [000] ...2 1212.876454: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1213.089569: sched_wakeup: comm=Thread-625 pid=5750 prio=120 success=1 target_cpu=000
<idle>-0 [000] dNh4 1213.089587: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.089622: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=Thread-625 next_pid=5750 next_prio=120
AsyncTask #1-5750 [000] ...2 1213.089842: sched_switch: prev_comm=Thread-625 prev_pid=5750 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 [000] ...2 1213.089879: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1213.327439: sched_wakeup: comm=pandora.android pid=5395 prio=120 success=1 target_cpu=000
<idle>-0 [000] dNh4 1213.327455: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.327487: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 [000] ...2 1213.327518: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 [000] d..4 1213.327718: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
pandora.android-5395 [000] ...2 1213.327739: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 [000] ...2 1213.327763: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=D ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 [000] d..3 1213.327781: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
pandora.android-5395 [000] ...2 1213.327795: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 [000] d..4 1213.328056: sched_wakeup: comm=Binder_1 pid=878 prio=120 success=1 target_cpu=000
Binder_1-780 [000] ...2 1213.328095: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=878 next_prio=120
Binder_1-878 [000] d..4 1213.328263: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
Binder_1-878 [000] ...2 1213.328345: sched_switch: prev_comm=Binder_1 prev_pid=878 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 [000] ...2 1213.328558: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 [000] ...2 1213.328743: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1213.328773: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.328793: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1213.328821: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1213.328846: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.328866: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1213.328891: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1213.328913: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.328931: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1213.328964: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1213.465138: sched_wakeup: comm=atrace pid=14446 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.465171: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=atrace next_pid=14446 next_prio=120

View File

@@ -0,0 +1,128 @@
# tracer: nop
#
# entries-in-buffer/entries-written: 116/116 #P:1
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
atrace-14446 [000] ...2 1212.465062: sched_switch: prev_comm=atrace prev_pid=14446 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.465074: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.465082: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.465092: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.465102: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.465126: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.465132: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.465139: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.465145: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.465227: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h5 1212.465297: sched_wakeup: comm=adbd pid=212 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.465306: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=adbd next_pid=212 next_prio=120
adbd-212 [000] d..4 1212.465329: sched_wakeup: comm=adbd pid=209 prio=120 success=1 target_cpu=000
adbd-212 [000] ...2 1212.465348: sched_switch: prev_comm=adbd prev_pid=212 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=209 next_prio=120
adbd-209 [000] d..4 1212.465395: sched_wakeup: comm=adbd pid=211 prio=120 success=1 target_cpu=000
adbd-209 [000] ...2 1212.465441: sched_switch: prev_comm=adbd prev_pid=209 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=211 next_prio=120
adbd-211 [000] ...2 1212.465448: sched_switch: prev_comm=adbd prev_pid=211 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h5 1212.574554: sched_wakeup: comm=sensors.qcom pid=292 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.574566: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=sensors.qcom next_pid=292 next_prio=120
sensors.qcom-292 [000] ...2 1212.574665: sched_switch: prev_comm=sensors.qcom prev_pid=292 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 [000] d..4 1212.574797: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
sensors.qcom-14447 [000] ...2 1212.574802: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
sensors.qcom-1593 [000] ...2 1212.574819: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=D ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 [000] d..3 1212.574823: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
sensors.qcom-14447 [000] ...2 1212.574827: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
sensors.qcom-1593 [000] d..4 1212.574865: sched_wakeup: comm=sensors.qcom pid=760 prio=120 success=1 target_cpu=000
sensors.qcom-1593 [000] ...2 1212.574876: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=760 next_prio=120
sensors.qcom-760 [000] d..4 1212.574905: sched_wakeup: comm=system_server pid=782 prio=118 success=1 target_cpu=000
sensors.qcom-760 [000] ...2 1212.574917: sched_switch: prev_comm=sensors.qcom prev_pid=760 prev_prio=120 prev_state=S ==> next_comm=system_server next_pid=782 next_prio=118
system_server-782 [000] d..4 1212.574981: sched_wakeup: comm=system_server pid=785 prio=118 success=1 target_cpu=000
system_server-782 [000] ...2 1212.575009: sched_switch: prev_comm=system_server prev_pid=782 prev_prio=118 prev_state=S ==> next_comm=system_server next_pid=785 next_prio=118
system_server-785 [000] ...2 1212.575045: sched_switch: prev_comm=system_server prev_pid=785 prev_prio=118 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 [000] ...3 1212.575143: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=x ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.575153: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.575159: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.575167: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.575175: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.575181: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.575188: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.575195: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.575201: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.575211: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1212.649601: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.649614: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 [000] ...2 1212.649630: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h6 1212.729539: sched_wakeup: comm=kworker/u:1 pid=21 prio=120 success=1 target_cpu=000
<idle>-0 [000] dNs6 1212.729550: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.729563: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:1 next_pid=21 next_prio=120
kworker/u:1-21 [000] d..5 1212.729571: sched_wakeup: comm=mpdecision pid=2046 prio=113 success=1 target_cpu=000
kworker/u:1-21 [000] ...2 1212.729578: sched_switch: prev_comm=kworker/u:1 prev_pid=21 prev_prio=120 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
kworker/0:2H-557 [000] d..4 1212.729597: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/0:2H-557 [000] ...2 1212.729600: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=D ==> next_comm=mpdecision next_pid=2046 next_prio=113
mpdecision-2046 [000] ...2 1212.729801: sched_switch: prev_comm=mpdecision prev_pid=2046 prev_prio=113 prev_state=S ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 [000] ...2 1212.730104: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.730134: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.730154: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.730176: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.730201: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.730220: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.730241: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.730262: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.730280: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.730303: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h6 1212.730638: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.730669: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
kworker/u:0H-7 [000] d..6 1212.730707: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/u:0H-7 [000] ...2 1212.730728: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 [000] ...2 1212.730916: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h6 1212.731632: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.731661: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
kworker/u:0H-7 [000] d..6 1212.731702: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/u:0H-7 [000] ...2 1212.731722: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 [000] ...2 1212.731832: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h6 1212.732685: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.732714: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
kworker/u:0H-7 [000] d..6 1212.732747: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/u:0H-7 [000] ...2 1212.732767: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 [000] d..4 1212.732810: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
kworker/0:1H-17 [000] ...2 1212.732829: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
kworker/0:2H-557 [000] ...2 1212.732854: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1212.876266: sched_wakeup: comm=RILSender0 pid=1365 prio=120 success=1 target_cpu=000
<idle>-0 [000] dNh4 1212.876284: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.876316: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=RILSender0 next_pid=1365 next_prio=120
RILSender0-1365 [000] ...2 1212.876415: sched_switch: prev_comm=RILSender0 prev_pid=1365 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 [000] ...2 1212.876454: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1213.089569: sched_wakeup: comm=Thread-625 pid=5750 prio=120 success=1 target_cpu=000
<idle>-0 [000] dNh4 1213.089587: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.089622: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=Thread-625 next_pid=5750 next_prio=120
Thread-625-5750 [000] ...2 1213.089842: sched_switch: prev_comm=Thread-625 prev_pid=5750 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 [000] ...2 1213.089879: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1213.327439: sched_wakeup: comm=pandora.android pid=5395 prio=120 success=1 target_cpu=000
<idle>-0 [000] dNh4 1213.327455: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.327487: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 [000] ...2 1213.327518: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 [000] d..4 1213.327718: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
pandora.android-5395 [000] ...2 1213.327739: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 [000] ...2 1213.327763: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=D ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 [000] d..3 1213.327781: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
pandora.android-5395 [000] ...2 1213.327795: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 [000] d..4 1213.328056: sched_wakeup: comm=Binder_1 pid=878 prio=120 success=1 target_cpu=000
Binder_1-780 [000] ...2 1213.328095: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=878 next_prio=120
Binder_1-878 [000] d..4 1213.328263: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
Binder_1-878 [000] ...2 1213.328345: sched_switch: prev_comm=Binder_1 prev_pid=878 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 [000] ...2 1213.328558: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 [000] ...2 1213.328743: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1213.328773: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.328793: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1213.328821: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1213.328846: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.328866: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1213.328891: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1213.328913: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.328931: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1213.328964: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1213.465138: sched_wakeup: comm=atrace pid=14446 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.465171: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=atrace next_pid=14446 next_prio=120

View File

@@ -0,0 +1,127 @@
# tracer: nop
#
# entries-in-buffer/entries-written: 116/116 #P:1
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
atrace-14446 [000] ...2 1212.465062: sched_switch: prev_comm=atrace prev_pid=14446 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.465074: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.465082: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.465092: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.465102: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.465126: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.465132: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.465139: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.465145: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.465227: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h5 1212.465297: sched_wakeup: comm=adbd pid=212 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.465306: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=adbd next_pid=212 next_prio=120
adbd-212 [000] d..4 1212.465329: sched_wakeup: comm=adbd pid=209 prio=120 success=1 target_cpu=000
adbd-212 [000] ...2 1212.465348: sched_switch: prev_comm=adbd prev_pid=212 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=209 next_prio=120
adbd-209 [000] d..4 1212.465395: sched_wakeup: comm=adbd pid=211 prio=120 success=1 target_cpu=000
adbd-209 [000] ...2 1212.465441: sched_switch: prev_comm=adbd prev_pid=209 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=211 next_prio=120
adbd-211 [000] ...2 1212.465448: sched_switch: prev_comm=adbd prev_pid=211 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h5 1212.574554: sched_wakeup: comm=sensors.qcom pid=292 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.574566: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=sensors.qcom next_pid=292 next_prio=120
sensors.qcom-292 [000] ...2 1212.574665: sched_switch: prev_comm=sensors.qcom prev_pid=292 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 [000] d..4 1212.574797: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
sensors.qcom-14447 [000] ...2 1212.574802: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
sensors.qcom-1593 [000] ...2 1212.574819: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=D ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 [000] d..3 1212.574823: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
sensors.qcom-14447 [000] ...2 1212.574827: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
sensors.qcom-1593 [000] d..4 1212.574865: sched_wakeup: comm=sensors.qcom pid=760 prio=120 success=1 target_cpu=000
sensors.qcom-1593 [000] ...2 1212.574876: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=760 next_prio=120
sensors.qcom-760 [000] d..4 1212.574905: sched_wakeup: comm=system_server pid=782 prio=118 success=1 target_cpu=000
sensors.qcom-760 [000] ...2 1212.574917: sched_switch: prev_comm=sensors.qcom prev_pid=760 prev_prio=120 prev_state=S ==> next_comm=system_server next_pid=782 next_prio=118
system_server-782 [000] d..4 1212.574981: sched_wakeup: comm=system_server pid=785 prio=118 success=1 target_cpu=000
system_server-782 [000] ...2 1212.575009: sched_switch: prev_comm=system_server prev_pid=782 prev_prio=118 prev_state=S ==> next_comm=system_server next_pid=785 next_prio=118
system_server-785 [000] ...2 1212.575045: sched_switch: prev_comm=system_server prev_pid=785 prev_prio=118 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 [000] ...3 1212.575143: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=x ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.575153: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.575159: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.575167: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.575175: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.575181: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.575188: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.575195: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.575201: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.575211: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1212.649601: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.649614: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 [000] ...2 1212.649630: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h6 1212.729539: sched_wakeup: comm=kworker/u:1 pid=21 prio=120 success=1 target_cpu=000
<idle>-0 [000] dNs6 1212.729550: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.729563: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:1 next_pid=21 next_prio=120
kworker/u:1-21 [000] d..5 1212.729571: sched_wakeup: comm=mpdecision pid=2046 prio=113 success=1 target_cpu=000
kworker/u:1-21 [000] ...2 1212.729578: sched_switch: prev_comm=kworker/u:1 prev_pid=21 prev_prio=120 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
kworker/0:2H-557 [000] d..4 1212.729597: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/0:2H-557 [000] ...2 1212.729600: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=D ==> next_comm=mpdecision next_pid=2046 next_prio=113
mpdecision-2046 [000] ...2 1212.729801: sched_switch: prev_comm=mpdecision prev_pid=2046 prev_prio=113 prev_state=S ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 [000] ...2 1212.730104: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.730134: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.730154: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.730176: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.730201: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.730220: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.730241: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1212.730262: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.730280: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1212.730303: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h6 1212.730638: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.730669: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
kworker/u:0H-7 [000] d..6 1212.730707: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/u:0H-7 [000] ...2 1212.730728: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 [000] ...2 1212.730916: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h6 1212.731632: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.731661: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
kworker/u:0H-7 [000] d..6 1212.731702: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/u:0H-7 [000] ...2 1212.731722: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 [000] ...2 1212.731832: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h6 1212.732685: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.732714: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
kworker/u:0H-7 [000] d..6 1212.732747: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/u:0H-7 [000] ...2 1212.732767: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 [000] d..4 1212.732810: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
kworker/0:1H-17 [000] ...2 1212.732829: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
kworker/0:2H-557 [000] ...2 1212.732854: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1212.876266: sched_wakeup: comm=RILSender0 pid=1365 prio=120 success=1 target_cpu=000
<idle>-0 [000] dNh4 1212.876284: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1212.876316: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=RILSender0 next_pid=1365 next_prio=120
RILSender0-1365 [000] ...2 1212.876415: sched_switch: prev_comm=RILSender0 prev_pid=1365 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 [000] ...2 1212.876454: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1213.089569: sched_wakeup: comm=Thread-625 pid=5750 prio=120 success=1 target_cpu=000
<idle>-0 [000] dNh4 1213.089587: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.089622: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=Thread-625 next_pid=5750 next_prio=120
Thread-625-5750 [000] ...2 1213.089842: sched_switch: prev_comm=Thread-625 prev_pid=5750 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 [000] ...2 1213.089879: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1213.327439: sched_wakeup: comm=pandora.android pid=5395 prio=120 success=1 target_cpu=000
<idle>-0 [000] dNh4 1213.327455: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.327487: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 [000] ...2 1213.327518: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 [000] d..4 1213.327718: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
pandora.android-5395 [000] ...2 1213.327739: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 [000] ...2 1213.327763: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=D ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 [000] d..3 1213.327781: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
pandora.android-5395 [000] ...2 1213.327795: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 [000] d..4 1213.328056: sched_wakeup: comm=Binder_1 pid=878 prio=120 success=1 target_cpu=000
Binder_1-780 [000] ...2 1213.328095: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=878 next_prio=120
Binder_1-878 [000] d..4 1213.328263: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
Binder_1-878 [000] ...2 1213.328345: sched_switch: prev_comm=Binder_1 prev_pid=878 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 [000] ...2 1213.328558: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 [000] ...2 1213.328743: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1213.328773: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.328793: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1213.328821: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1213.328846: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.328866: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1213.328891: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d..4 1213.328913: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.328931: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 [000] ...2 1213.328964: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 [000] d.h4 1213.465138: sched_wakeup: comm=atrace pid=14446 prio=120 success=1 target_cpu=000
<idle>-0 [000] ...2 1213.465171: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=atrace next_pid=14446 next_prio=120

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{1: '/init', 2: 'kthreadd', 3: 'ksoftirqd/0', 7: 'kworker/u:0H', 8: 'migration/0', 13: 'khelper', 14: 'netns'}

View File

@@ -0,0 +1,127 @@
# tracer: nop
#
# entries-in-buffer/entries-written: 116/116 #P:1
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
atrace-14446 (-----) [000] ...2 1212.465062: sched_switch: prev_comm=atrace prev_pid=14446 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.465074: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.465082: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 ( 3) [000] ...2 1212.465092: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.465102: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.465126: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 ( 3) [000] ...2 1212.465132: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.465139: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.465145: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 ( 3) [000] ...2 1212.465227: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h5 1212.465297: sched_wakeup: comm=adbd pid=212 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.465306: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=adbd next_pid=212 next_prio=120
adbd-212 ( 212) [000] d..4 1212.465329: sched_wakeup: comm=adbd pid=209 prio=120 success=1 target_cpu=000
adbd-212 ( 212) [000] ...2 1212.465348: sched_switch: prev_comm=adbd prev_pid=212 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=209 next_prio=120
adbd-209 ( 209) [000] d..4 1212.465395: sched_wakeup: comm=adbd pid=211 prio=120 success=1 target_cpu=000
adbd-209 ( 209) [000] ...2 1212.465441: sched_switch: prev_comm=adbd prev_pid=209 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=211 next_prio=120
adbd-211 ( 211) [000] ...2 1212.465448: sched_switch: prev_comm=adbd prev_pid=211 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h5 1212.574554: sched_wakeup: comm=sensors.qcom pid=292 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.574566: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=sensors.qcom next_pid=292 next_prio=120
sensors.qcom-292 (-----) [000] ...2 1212.574665: sched_switch: prev_comm=sensors.qcom prev_pid=292 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 (-----) [000] d..4 1212.574797: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
sensors.qcom-14447 (-----) [000] ...2 1212.574802: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
sensors.qcom-1593 (-----) [000] ...2 1212.574819: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=D ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 (-----) [000] d..3 1212.574823: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
sensors.qcom-14447 (-----) [000] ...2 1212.574827: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
sensors.qcom-1593 (-----) [000] d..4 1212.574865: sched_wakeup: comm=sensors.qcom pid=760 prio=120 success=1 target_cpu=000
sensors.qcom-1593 (-----) [000] ...2 1212.574876: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=760 next_prio=120
sensors.qcom-760 (-----) [000] d..4 1212.574905: sched_wakeup: comm=system_server pid=782 prio=118 success=1 target_cpu=000
sensors.qcom-760 (-----) [000] ...2 1212.574917: sched_switch: prev_comm=sensors.qcom prev_pid=760 prev_prio=120 prev_state=S ==> next_comm=system_server next_pid=782 next_prio=118
system_server-782 (-----) [000] d..4 1212.574981: sched_wakeup: comm=system_server pid=785 prio=118 success=1 target_cpu=000
system_server-782 (-----) [000] ...2 1212.575009: sched_switch: prev_comm=system_server prev_pid=782 prev_prio=118 prev_state=S ==> next_comm=system_server next_pid=785 next_prio=118
system_server-785 ( 785) [000] ...2 1212.575045: sched_switch: prev_comm=system_server prev_pid=785 prev_prio=118 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 (-----) [000] ...3 1212.575143: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=x ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.575153: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.575159: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 ( 3) [000] ...2 1212.575167: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.575175: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.575181: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 ( 3) [000] ...2 1212.575188: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.575195: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.575201: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 ( 3) [000] ...2 1212.575211: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h4 1212.649601: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.649614: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 (-----) [000] ...2 1212.649630: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h6 1212.729539: sched_wakeup: comm=kworker/u:1 pid=21 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] dNs6 1212.729550: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.729563: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:1 next_pid=21 next_prio=120
kworker/u:1-21 (-----) [000] d..5 1212.729571: sched_wakeup: comm=mpdecision pid=2046 prio=113 success=1 target_cpu=000
kworker/u:1-21 (-----) [000] ...2 1212.729578: sched_switch: prev_comm=kworker/u:1 prev_pid=21 prev_prio=120 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
kworker/0:2H-557 (-----) [000] d..4 1212.729597: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/0:2H-557 (-----) [000] ...2 1212.729600: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=D ==> next_comm=mpdecision next_pid=2046 next_prio=113
mpdecision-2046 (-----) [000] ...2 1212.729801: sched_switch: prev_comm=mpdecision prev_pid=2046 prev_prio=113 prev_state=S ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 (-----) [000] ...2 1212.730104: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.730134: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.730154: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 ( 3) [000] ...2 1212.730176: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.730201: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.730220: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 ( 3) [000] ...2 1212.730241: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.730262: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.730280: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 ( 3) [000] ...2 1212.730303: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h6 1212.730638: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.730669: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
kworker/u:0H-7 ( 7) [000] d..6 1212.730707: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/u:0H-7 ( 7) [000] ...2 1212.730728: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 (-----) [000] ...2 1212.730916: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h6 1212.731632: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.731661: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
kworker/u:0H-7 ( 7) [000] d..6 1212.731702: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/u:0H-7 ( 7) [000] ...2 1212.731722: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 (-----) [000] ...2 1212.731832: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h6 1212.732685: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.732714: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
kworker/u:0H-7 ( 7) [000] d..6 1212.732747: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/u:0H-7 ( 7) [000] ...2 1212.732767: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 (-----) [000] d..4 1212.732810: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
kworker/0:1H-17 (-----) [000] ...2 1212.732829: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
kworker/0:2H-557 (-----) [000] ...2 1212.732854: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h4 1212.876266: sched_wakeup: comm=RILSender0 pid=1365 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] dNh4 1212.876284: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.876316: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=RILSender0 next_pid=1365 next_prio=120
RILSender0-1365 ( 1345) [000] ...2 1212.876415: sched_switch: prev_comm=RILSender0 prev_pid=1365 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 (-----) [000] ...2 1212.876454: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h4 1213.089569: sched_wakeup: comm=Thread-625 pid=5750 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] dNh4 1213.089587: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1213.089622: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=Thread-625 next_pid=5750 next_prio=120
Thread-625-5750 (-----) [000] ...2 1213.089842: sched_switch: prev_comm=Thread-625 prev_pid=5750 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 (-----) [000] ...2 1213.089879: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h4 1213.327439: sched_wakeup: comm=pandora.android pid=5395 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] dNh4 1213.327455: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1213.327487: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 (-----) [000] ...2 1213.327518: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 (-----) [000] d..4 1213.327718: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
pandora.android-5395 (-----) [000] ...2 1213.327739: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 (-----) [000] ...2 1213.327763: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=D ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 (-----) [000] d..3 1213.327781: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
pandora.android-5395 (-----) [000] ...2 1213.327795: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 (-----) [000] d..4 1213.328056: sched_wakeup: comm=Binder_1 pid=878 prio=120 success=1 target_cpu=000
Binder_1-780 (-----) [000] ...2 1213.328095: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=878 next_prio=120
Binder_1-878 ( 877) [000] d..4 1213.328263: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
Binder_1-878 ( 877) [000] ...2 1213.328345: sched_switch: prev_comm=Binder_1 prev_pid=878 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 (-----) [000] ...2 1213.328558: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 (-----) [000] ...2 1213.328743: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1213.328773: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1213.328793: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 ( 3) [000] ...2 1213.328821: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1213.328846: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1213.328866: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 ( 3) [000] ...2 1213.328891: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1213.328913: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1213.328931: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 ( 3) [000] ...2 1213.328964: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h4 1213.465138: sched_wakeup: comm=atrace pid=14446 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1213.465171: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=atrace next_pid=14446 next_prio=120

View File

@@ -0,0 +1,127 @@
# tracer: nop
#
# entries-in-buffer/entries-written: 116/116 #P:1
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
atrace-14446 (-----) [000] ...2 1212.465062: sched_switch: prev_comm=atrace prev_pid=14446 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.465074: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.465082: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 (-----) [000] ...2 1212.465092: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.465102: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.465126: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 (-----) [000] ...2 1212.465132: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.465139: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.465145: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 (-----) [000] ...2 1212.465227: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h5 1212.465297: sched_wakeup: comm=adbd pid=212 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.465306: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=adbd next_pid=212 next_prio=120
adbd-212 (-----) [000] d..4 1212.465329: sched_wakeup: comm=adbd pid=209 prio=120 success=1 target_cpu=000
adbd-212 (-----) [000] ...2 1212.465348: sched_switch: prev_comm=adbd prev_pid=212 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=209 next_prio=120
adbd-209 (-----) [000] d..4 1212.465395: sched_wakeup: comm=adbd pid=211 prio=120 success=1 target_cpu=000
adbd-209 (-----) [000] ...2 1212.465441: sched_switch: prev_comm=adbd prev_pid=209 prev_prio=120 prev_state=S ==> next_comm=adbd next_pid=211 next_prio=120
adbd-211 (-----) [000] ...2 1212.465448: sched_switch: prev_comm=adbd prev_pid=211 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h5 1212.574554: sched_wakeup: comm=sensors.qcom pid=292 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.574566: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=sensors.qcom next_pid=292 next_prio=120
sensors.qcom-292 (-----) [000] ...2 1212.574665: sched_switch: prev_comm=sensors.qcom prev_pid=292 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 (-----) [000] d..4 1212.574797: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
sensors.qcom-14447 (-----) [000] ...2 1212.574802: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
sensors.qcom-1593 (-----) [000] ...2 1212.574819: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=D ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 (-----) [000] d..3 1212.574823: sched_wakeup: comm=sensors.qcom pid=1593 prio=120 success=1 target_cpu=000
sensors.qcom-14447 (-----) [000] ...2 1212.574827: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=R+ ==> next_comm=sensors.qcom next_pid=1593 next_prio=120
sensors.qcom-1593 (-----) [000] d..4 1212.574865: sched_wakeup: comm=sensors.qcom pid=760 prio=120 success=1 target_cpu=000
sensors.qcom-1593 (-----) [000] ...2 1212.574876: sched_switch: prev_comm=sensors.qcom prev_pid=1593 prev_prio=120 prev_state=S ==> next_comm=sensors.qcom next_pid=760 next_prio=120
sensors.qcom-760 (-----) [000] d..4 1212.574905: sched_wakeup: comm=system_server pid=782 prio=118 success=1 target_cpu=000
sensors.qcom-760 (-----) [000] ...2 1212.574917: sched_switch: prev_comm=sensors.qcom prev_pid=760 prev_prio=120 prev_state=S ==> next_comm=system_server next_pid=782 next_prio=118
system_server-782 (-----) [000] d..4 1212.574981: sched_wakeup: comm=system_server pid=785 prio=118 success=1 target_cpu=000
system_server-782 (-----) [000] ...2 1212.575009: sched_switch: prev_comm=system_server prev_pid=782 prev_prio=118 prev_state=S ==> next_comm=system_server next_pid=785 next_prio=118
system_server-785 (-----) [000] ...2 1212.575045: sched_switch: prev_comm=system_server prev_pid=785 prev_prio=118 prev_state=S ==> next_comm=sensors.qcom next_pid=14447 next_prio=120
sensors.qcom-14447 (-----) [000] ...3 1212.575143: sched_switch: prev_comm=sensors.qcom prev_pid=14447 prev_prio=120 prev_state=x ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.575153: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.575159: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 (-----) [000] ...2 1212.575167: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.575175: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.575181: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 (-----) [000] ...2 1212.575188: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.575195: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.575201: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 (-----) [000] ...2 1212.575211: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h4 1212.649601: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.649614: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 (-----) [000] ...2 1212.649630: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h6 1212.729539: sched_wakeup: comm=kworker/u:1 pid=21 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] dNs6 1212.729550: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.729563: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:1 next_pid=21 next_prio=120
kworker/u:1-21 (-----) [000] d..5 1212.729571: sched_wakeup: comm=mpdecision pid=2046 prio=113 success=1 target_cpu=000
kworker/u:1-21 (-----) [000] ...2 1212.729578: sched_switch: prev_comm=kworker/u:1 prev_pid=21 prev_prio=120 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
kworker/0:2H-557 (-----) [000] d..4 1212.729597: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/0:2H-557 (-----) [000] ...2 1212.729600: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=D ==> next_comm=mpdecision next_pid=2046 next_prio=113
mpdecision-2046 (-----) [000] ...2 1212.729801: sched_switch: prev_comm=mpdecision prev_pid=2046 prev_prio=113 prev_state=S ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 (-----) [000] ...2 1212.730104: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.730134: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.730154: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 (-----) [000] ...2 1212.730176: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.730201: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.730220: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 (-----) [000] ...2 1212.730241: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1212.730262: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.730280: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 (-----) [000] ...2 1212.730303: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h6 1212.730638: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.730669: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
kworker/u:0H-7 (-----) [000] d..6 1212.730707: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/u:0H-7 (-----) [000] ...2 1212.730728: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 (-----) [000] ...2 1212.730916: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h6 1212.731632: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.731661: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
kworker/u:0H-7 (-----) [000] d..6 1212.731702: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/u:0H-7 (-----) [000] ...2 1212.731722: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 (-----) [000] ...2 1212.731832: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=D ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h6 1212.732685: sched_wakeup: comm=kworker/u:0H pid=7 prio=100 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.732714: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=kworker/u:0H next_pid=7 next_prio=100
kworker/u:0H-7 (-----) [000] d..6 1212.732747: sched_wakeup: comm=kworker/0:1H pid=17 prio=100 success=1 target_cpu=000
kworker/u:0H-7 (-----) [000] ...2 1212.732767: sched_switch: prev_comm=kworker/u:0H prev_pid=7 prev_prio=100 prev_state=D ==> next_comm=kworker/0:1H next_pid=17 next_prio=100
kworker/0:1H-17 (-----) [000] d..4 1212.732810: sched_wakeup: comm=kworker/0:2H pid=557 prio=100 success=1 target_cpu=000
kworker/0:1H-17 (-----) [000] ...2 1212.732829: sched_switch: prev_comm=kworker/0:1H prev_pid=17 prev_prio=100 prev_state=S ==> next_comm=kworker/0:2H next_pid=557 next_prio=100
kworker/0:2H-557 (-----) [000] ...2 1212.732854: sched_switch: prev_comm=kworker/0:2H prev_pid=557 prev_prio=100 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h4 1212.876266: sched_wakeup: comm=RILSender0 pid=1365 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] dNh4 1212.876284: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1212.876316: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=RILSender0 next_pid=1365 next_prio=120
RILSender0-1365 (-----) [000] ...2 1212.876415: sched_switch: prev_comm=RILSender0 prev_pid=1365 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 (-----) [000] ...2 1212.876454: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h4 1213.089569: sched_wakeup: comm=Thread-625 pid=5750 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] dNh4 1213.089587: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1213.089622: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=Thread-625 next_pid=5750 next_prio=120
Thread-625-5750 (-----) [000] ...2 1213.089842: sched_switch: prev_comm=Thread-625 prev_pid=5750 prev_prio=120 prev_state=S ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 (-----) [000] ...2 1213.089879: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h4 1213.327439: sched_wakeup: comm=pandora.android pid=5395 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] dNh4 1213.327455: sched_wakeup: comm=MMHandlerThread pid=7231 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1213.327487: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=MMHandlerThread next_pid=7231 next_prio=120
MMHandlerThread-7231 (-----) [000] ...2 1213.327518: sched_switch: prev_comm=MMHandlerThread prev_pid=7231 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 (-----) [000] d..4 1213.327718: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
pandora.android-5395 (-----) [000] ...2 1213.327739: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 (-----) [000] ...2 1213.327763: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=D ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 (-----) [000] d..3 1213.327781: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
pandora.android-5395 (-----) [000] ...2 1213.327795: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 (-----) [000] d..4 1213.328056: sched_wakeup: comm=Binder_1 pid=878 prio=120 success=1 target_cpu=000
Binder_1-780 (-----) [000] ...2 1213.328095: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=878 next_prio=120
Binder_1-878 (-----) [000] d..4 1213.328263: sched_wakeup: comm=Binder_1 pid=780 prio=120 success=1 target_cpu=000
Binder_1-878 (-----) [000] ...2 1213.328345: sched_switch: prev_comm=Binder_1 prev_pid=878 prev_prio=120 prev_state=S ==> next_comm=Binder_1 next_pid=780 next_prio=120
Binder_1-780 (-----) [000] ...2 1213.328558: sched_switch: prev_comm=Binder_1 prev_pid=780 prev_prio=120 prev_state=S ==> next_comm=pandora.android next_pid=5395 next_prio=120
pandora.android-5395 (-----) [000] ...2 1213.328743: sched_switch: prev_comm=pandora.android prev_pid=5395 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1213.328773: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1213.328793: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 (-----) [000] ...2 1213.328821: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1213.328846: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1213.328866: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 (-----) [000] ...2 1213.328891: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d..4 1213.328913: sched_wakeup: comm=ksoftirqd/0 pid=3 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1213.328931: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=ksoftirqd/0 next_pid=3 next_prio=120
ksoftirqd/0-3 (-----) [000] ...2 1213.328964: sched_switch: prev_comm=ksoftirqd/0 prev_pid=3 prev_prio=120 prev_state=S ==> next_comm=swapper/0 next_pid=0 next_prio=120
<idle>-0 (-----) [000] d.h4 1213.465138: sched_wakeup: comm=atrace pid=14446 prio=120 success=1 target_cpu=000
<idle>-0 (-----) [000] ...2 1213.465171: sched_switch: prev_comm=swapper/0 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=atrace next_pid=14446 next_prio=120

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
TRACE:
x<EFBFBD>½]ΫnG}χW4 ΟƒμΚ[U±3€―³ΖzlνΚ<CEBD>}X,„6Ωυ<>dsΊ¶µΰΗo$-Κ&+£OEd5€dhΔs²ς<C2B2>qβςluά―Ο6ϋOVW»λ<0F>}πlµΉ:ξ·›ΓσνΥσo^Ώήμ?Ύ<>_φΫγqsυΙΚuΡ\~[­VΟ^|<7C>ίύά¬_―<5F>—_ώΛj»<6A>Χαωξυλ™?ψρo?I?xµΩ<C2B5>?ίogo6ησ~ψφέOΣΏYοΟ‰ωγΓξυώ<E28098>ωσο<CF83><CEBF>m<EFBFBD>"9t<39><74>„FϋΖ‘ιφΝβ „#>ΌΜZRPβΐk‰1•Κ΅@ΉTf<54>CµqhkI5<16>@r¶σ@`-%uσ<CF83><13><>z·ΠΡ¨xΪvL <4C>-Υ%ψ|<><E28098>ήt‘θu/θ‰ρΏ“εQNfµ+πω#‡©Χϊό¦q„CΛύσ<1B>γψωM >Α£ΪβώΧ»Η―θ.D[@-΄” „8Ϋ<16>ΤΫ
OoΊ‡Θ€'rfΔβ<CE94>·β΅ ΄% AΑ­@R]U± 50<35>εVθ_6<5F>C<EFBFBD>΅±ΛΖΏ]τE} 2Ι|Ρ"!Η°:
Τ<CEA0>\®!ΗΐƒΓΧ>· <>c0V±ώ49δ”A¬ήyD•<44>η<EFBFBD> 'O•sP<06>[2w<32>χΚ(ΰάv<>ηgOΣ ΰΏ‰„fΉ<€<>ΤT?¶9x―Πj¦θ4΄ΪQ)ΩΙ†σµ5
9ζ[·Σ

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
#!/usr/bin/env python
# Copyright 2016 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.
'''Tracing agent result wrapper for systrace.
This class represents the captured trace results from a particular
tool (e.g. atrace, ftrace.)
'''
class TraceResult(object):
def __init__(self, source_name, raw_data):
self.source_name = source_name
self.raw_data = raw_data

View File

@@ -0,0 +1,91 @@
#!/usr/bin/env python
# Copyright 2016 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.
'''Tracing agent interface for systrace.
This class represents an agent that captures traces from a particular
tool (e.g. atrace, ftrace.)
'''
# Timeout interval constants.
START_STOP_TIMEOUT = 10.0
GET_RESULTS_TIMEOUT = 30.0
class TracingConfig(object):
'''Store the tracing configuration options for all Systrace agents. If there
are ever any options that are to be shared between all of the agents, those
options should go here.
'''
def __init__(self):
pass
class TracingAgent(object):
def __init__(self):
pass
def StartAgentTracing(self, config, timeout=None):
'''Starts running the trace for this agent. Stops with timeout if
not completed within timeout interval.
Args:
config: TracingConfig subclass containing agent-specific options
and categories.
timeout: Timeout interval in seconds.
Returns:
Boolean value indicating whether or not the trace started successfully.
'''
pass
def StopAgentTracing(self, timeout=None):
'''Stops running the trace for this agent and returns immediately.
Stops with timeout if not completed within timeout interval.
Args:
timeout: Timeout interval in seconds.
Returns:
Boolean value indicating whether or not the trace started successfully.
'''
pass
def SupportsExplicitClockSync(self):
'''Find out if this agent supports recording of clock sync markers.
Returns:
Boolean value indicating whether this agent supports recording
of clock sync markers.
'''
raise NotImplementedError
def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
'''Record a clock sync marker for this agent.
Args:
sync_id: Clock sync ID string.
did_record_sync_marker_callback: Callback function to call
(with arguments: timestamp and sync_id) after the
clock sync marker is recorded.
'''
raise NotImplementedError
def GetResults(self, timeout=None):
'''Get the completed trace for this agent, stopping with timeout
Get the completed trace for this agent. Call only after
StopAgentTracing is done. This function blocks until the result
is collected (note; this may take several seconds). Stops with timeout
if not completed within self._options.collection_timeout seconds.
Args:
timeout: Timeout interval in seconds.
Returns:
Completed trace for this agent.
'''
pass

View File

@@ -0,0 +1,47 @@
# 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
from systrace import util
from devil.android import device_utils
from devil.android.sdk import intent
from devil.android.sdk import keyevent
class BaseAgentTest(unittest.TestCase):
def setUp(self):
devices = device_utils.DeviceUtils.HealthyDevices()
self.browser = 'stable'
self.package_info = util.get_supported_browsers()[self.browser]
self.device = devices[0]
curr_browser = self.GetChromeProcessID()
if curr_browser is None:
self.StartBrowser()
def tearDown(self):
# Stop the browser after each test to ensure that it doesn't interfere
# with subsequent tests, e.g. by holding the devtools socket open.
self.device.ForceStop(self.package_info.package)
def StartBrowser(self):
# Turn on the device screen.
self.device.SetScreen(True)
# Unlock device.
self.device.SendKeyEvent(keyevent.KEYCODE_MENU)
# Start browser.
self.device.StartActivity(
intent.Intent(activity=self.package_info.activity,
package=self.package_info.package,
data='about:blank',
extras={'create_new_tab': True}),
blocking=True, force_stop=True)
def GetChromeProcessID(self):
return self.device.GetApplicationPids(
self.package_info.package, at_most_one=True)

View File

@@ -0,0 +1,95 @@
# 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.
# Tracing agent that captures friendly process and thread data - names, pids and
# tids and names, etc to enrich display in the trace viewer. Captures snapshots
# of the output of 'ps' on the device at intervals.
import logging
import py_utils
from devil.android import device_utils
from devil.android.device_errors import AdbShellCommandFailedError
from systrace import tracing_agents
from systrace import trace_result
# Leftmost output columns match those used on legacy devices.
# Get thread names separately as there may be spaces that breaks col
# splitting.
# TODO(benm): Refactor device_utils.GetPids to get threads and use that here.
PS_COMMAND_PROC = "ps -A -o USER,PID,PPID,VSIZE,RSS,WCHAN,ADDR=PC,S,NAME,COMM" \
"&& ps -AT -o USER,PID,TID,CMD"
# Fallback for old devices.
PS_COMMAND_PROC_LEGACY = "ps && ps -t"
# identify this as trace of thread / process state
TRACE_HEADER = 'PROCESS DUMP\n'
def try_create_agent(config):
if config.target != 'android':
return None
if config.from_file is not None:
return None
if config.process_dump_enable:
# Since AtraceProcessDumpAgent was enabled it's unnecessary to collect ps
# data because each process memory dump updates information about processes
# and their threads. It's more complete data than two ps snapshots for an
# entire trace. However, that agent isn't enabled by default.
return None
return AndroidProcessDataAgent()
def get_config(options):
return options
class AndroidProcessDataAgent(tracing_agents.TracingAgent):
def __init__(self):
super(AndroidProcessDataAgent, self).__init__()
self._trace_data = ""
self._device = None
def __repr__(self):
return 'android_process_data'
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
self._device = device_utils.DeviceUtils(config.device_serial_number)
self._trace_data += self._get_process_snapshot()
return True
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
self._trace_data += self._get_process_snapshot()
return True
@py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
def GetResults(self, timeout=None):
result = TRACE_HEADER + self._trace_data
return trace_result.TraceResult('androidProcessDump', result)
def SupportsExplicitClockSync(self):
return False
def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
pass
def _get_process_snapshot(self):
use_legacy = False
try:
dump = self._device.RunShellCommand( \
PS_COMMAND_PROC, check_return=True, as_root=True, shell=True)
except AdbShellCommandFailedError:
use_legacy = True
# Check length of 2 as we execute two commands, which in case of failure
# on old devices output 1 line each.
if use_legacy or len(dump) == 2:
logging.debug('Couldn\'t parse ps dump, trying legacy method ...')
dump = self._device.RunShellCommand( \
PS_COMMAND_PROC_LEGACY, check_return=True, as_root=True, shell=True)
if len(dump) == 2:
logging.error('Unable to extract process data!')
return ""
return '\n'.join(dump) + '\n'

View File

@@ -0,0 +1,472 @@
# 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.
import optparse
import platform
import re
import sys
import threading
import zlib
import py_utils
from devil.android import device_utils
from devil.android.sdk import version_codes
from py_trace_event import trace_time as trace_time_module
from systrace import trace_result
from systrace import tracing_agents
from systrace import util
# Text that ADB sends, but does not need to be displayed to the user.
ADB_IGNORE_REGEXP = r'^capturing trace\.\.\. done|^capturing trace\.\.\.'
# The number of seconds to wait on output from ADB.
ADB_STDOUT_READ_TIMEOUT = 0.2
# The number of seconds to wait for large output from ADB.
ADB_LARGE_OUTPUT_TIMEOUT = 600
# The adb shell command to initiate a trace.
ATRACE_BASE_ARGS = ['atrace']
# If a custom list of categories is not specified, traces will include
# these categories (if available on the device).
DEFAULT_CATEGORIES = 'sched,freq,gfx,view,dalvik,webview,'\
'input,disk,am,wm,rs,binder_driver'
# The command to list trace categories.
LIST_CATEGORIES_ARGS = ATRACE_BASE_ARGS + ['--list_categories']
# Minimum number of seconds between displaying status updates.
MIN_TIME_BETWEEN_STATUS_UPDATES = 0.2
# ADB sends this text to indicate the beginning of the trace data.
TRACE_START_REGEXP = r'TRACE\:'
# Plain-text trace data should always start with this string.
TRACE_TEXT_HEADER = '# tracer'
_FIX_MISSING_TGIDS = True
_FIX_CIRCULAR_TRACES = True
def list_categories(config):
"""List the possible trace event categories.
This function needs the tracing config since it needs to get the serial
number of the device to send a command to.
Args:
config: Tracing config.
"""
devutils = device_utils.DeviceUtils(config.device_serial_number)
categories = devutils.RunShellCommand(
LIST_CATEGORIES_ARGS, check_return=True)
device_sdk_version = util.get_device_sdk_version()
if device_sdk_version < version_codes.MARSHMALLOW:
# work around platform bug where rs tag would corrupt trace until M(Api23)
categories = [c for c in categories if not re.match(r'^\s*rs\s*-', c)]
print '\n'.join(categories)
if not devutils.HasRoot():
print '\nNOTE: more categories may be available with adb root\n'
def get_available_categories(config, device_sdk_version):
"""Gets the list of atrace categories available for tracing.
Args:
config: Tracing config.
device_sdk_version: Sdk version int of device to be queried.
"""
devutils = device_utils.DeviceUtils(config.device_serial_number)
categories_output = devutils.RunShellCommand(
LIST_CATEGORIES_ARGS, check_return=True)
categories = [c.split('-')[0].strip() for c in categories_output]
if device_sdk_version < version_codes.MARSHMALLOW:
# work around platform bug where rs tag would corrupt trace until M(Api23)
categories = [c for c in categories if c != 'rs']
return categories
def try_create_agent(config):
"""Create an Atrace agent.
Args:
config: Command line config.
"""
if config.target != 'android':
return None
if config.from_file is not None:
return None
if not config.atrace_categories:
return None
# Check device SDK version.
device_sdk_version = util.get_device_sdk_version()
if device_sdk_version < version_codes.JELLY_BEAN_MR2:
print ('Device SDK versions < 18 (Jellybean MR2) not supported.\n'
'Your device SDK version is %d.' % device_sdk_version)
return None
return AtraceAgent(device_sdk_version)
def _construct_extra_atrace_args(config, categories):
"""Construct extra arguments (-a, -k, categories) for atrace command.
Args:
config: Tracing config.
"""
extra_args = []
if config.app_name is not None:
extra_args.extend(['-a', config.app_name])
if config.kfuncs is not None:
extra_args.extend(['-k', config.kfuncs])
extra_args.extend(categories)
return extra_args
def _construct_atrace_args(config, categories):
"""Builds the command used to invoke a trace process.
Returns:
A tuple where the first element is an array of command arguments, and
the second element is a boolean which will be true if the command will
stream trace data.
"""
atrace_args = ATRACE_BASE_ARGS[:]
if config.compress_trace_data:
atrace_args.extend(['-z'])
if (config.trace_time is not None) and (config.trace_time > 0):
atrace_args.extend(['-t', str(config.trace_time)])
if (config.trace_buf_size is not None) and (config.trace_buf_size > 0):
atrace_args.extend(['-b', str(config.trace_buf_size)])
elif 'webview' in categories and 'sched' in categories:
# https://crbug.com/814330: webview_startup sometimes exceeds the buffer
# limit, so doubling this.
atrace_args.extend(['-b', '8192'])
elif 'sched' in categories:
# 'sched' is a high-volume tag, double the default buffer size
# to accommodate that
atrace_args.extend(['-b', '4096'])
extra_args = _construct_extra_atrace_args(config, categories)
atrace_args.extend(extra_args)
return atrace_args
class AtraceAgent(tracing_agents.TracingAgent):
def __init__(self, device_sdk_version):
super(AtraceAgent, self).__init__()
self._device_sdk_version = device_sdk_version
self._adb = None
self._trace_data = None
self._tracer_args = None
self._collection_thread = None
self._device_utils = None
self._device_serial_number = None
self._config = None
self._categories = None
def __repr__(self):
return 'atrace'
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
assert config.atrace_categories, 'Atrace categories are missing!'
self._config = config
self._categories = config.atrace_categories
if isinstance(self._categories, list):
self._categories = ','.join(self._categories)
avail_cats = get_available_categories(config, self._device_sdk_version)
unavailable = [x for x in self._categories.split(',') if
x not in avail_cats]
self._categories = [x for x in self._categories.split(',') if
x in avail_cats]
if unavailable:
print 'These categories are unavailable: ' + ' '.join(unavailable)
self._device_utils = device_utils.DeviceUtils(config.device_serial_number)
self._device_serial_number = config.device_serial_number
self._tracer_args = _construct_atrace_args(config,
self._categories)
self._device_utils.RunShellCommand(
self._tracer_args + ['--async_start'], check_return=True)
return True
def _collect_and_preprocess(self):
"""Collects and preprocesses trace data.
Stores results in self._trace_data.
"""
trace_data = self._collect_trace_data()
self._trace_data = self._preprocess_trace_data(trace_data)
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
"""Stops tracing and starts collecting results.
To synchronously retrieve the results after calling this function,
call GetResults().
"""
self._collection_thread = threading.Thread(
target=self._collect_and_preprocess)
self._collection_thread.start()
return True
@py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
def GetResults(self, timeout=None):
"""Waits for collection thread to finish and returns trace results."""
self._collection_thread.join()
self._collection_thread = None
return trace_result.TraceResult('systemTraceEvents', self._trace_data)
def SupportsExplicitClockSync(self):
return True
def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
"""Records a clock sync marker.
Args:
sync_id: ID string for clock sync marker.
"""
cmd = 'echo trace_event_clock_sync: name=%s >' \
' /sys/kernel/debug/tracing/trace_marker' % sync_id
with self._device_utils.adb.PersistentShell(
self._device_serial_number) as shell:
t1 = trace_time_module.Now()
shell.RunCommand(cmd, close=True)
did_record_sync_marker_callback(t1, sync_id)
def _stop_collect_trace(self):
"""Stops atrace.
Note that prior to Api 23, --async-stop isn't working correctly. It
doesn't stop tracing and clears trace buffer before dumping it rendering
results unusable."""
if self._device_sdk_version < version_codes.MARSHMALLOW:
is_trace_enabled_file = '/sys/kernel/debug/tracing/tracing_on'
# Stop tracing first so new data won't arrive while dump is performed (it
# may take a non-trivial time and tracing buffer may overflow).
self._device_utils.WriteFile(is_trace_enabled_file, '0')
result = self._device_utils.RunShellCommand(
self._tracer_args + ['--async_dump'], raw_output=True,
large_output=True, check_return=True,
timeout=ADB_LARGE_OUTPUT_TIMEOUT)
# Run synchronous tracing for 0 seconds to stop tracing, clear buffers
# and other state.
self._device_utils.RunShellCommand(
self._tracer_args + ['-t 0'], check_return=True)
else:
# On M+ --async_stop does everything necessary
result = self._device_utils.RunShellCommand(
self._tracer_args + ['--async_stop'], raw_output=True,
large_output=True, check_return=True,
timeout=ADB_LARGE_OUTPUT_TIMEOUT)
return result
def _collect_trace_data(self):
"""Reads the output from atrace and stops the trace."""
result = self._stop_collect_trace()
data_start = re.search(TRACE_START_REGEXP, result)
if data_start:
data_start = data_start.end(0)
else:
raise IOError('Unable to get atrace data. Did you forget adb root?')
output = re.sub(ADB_IGNORE_REGEXP, '', result[data_start:])
return output
def _preprocess_trace_data(self, trace_data):
"""Performs various processing on atrace data.
Args:
trace_data: The raw trace data.
Returns:
The processed trace data.
"""
if trace_data:
trace_data = strip_and_decompress_trace(trace_data)
if not trace_data:
print >> sys.stderr, ('No data was captured. Output file was not '
'written.')
sys.exit(1)
if _FIX_MISSING_TGIDS:
# Gather proc data from device and patch tgids
procfs_dump = self._device_utils.RunShellCommand(
'echo -n /proc/[0-9]*/task/[0-9]*',
shell=True, check_return=True)[0].split(' ')
pid2_tgid = extract_tgids(procfs_dump)
trace_data = fix_missing_tgids(trace_data, pid2_tgid)
if _FIX_CIRCULAR_TRACES:
trace_data = fix_circular_traces(trace_data)
return trace_data
def extract_tgids(trace_lines):
"""Removes the procfs dump from the given trace text
Args:
trace_lines: The text portion of the trace
Returns:
a map of pids to their tgid.
"""
tgid_2pid = {}
for line in trace_lines:
result = re.match('^/proc/([0-9]+)/task/([0-9]+)', line)
if result:
parent_pid, tgid = result.group(1, 2)
tgid_2pid[tgid] = parent_pid
return tgid_2pid
def strip_and_decompress_trace(trace_data):
"""Fixes new-lines and decompresses trace data.
Args:
trace_data: The trace data returned by atrace.
Returns:
The decompressed trace data.
"""
# Collapse CRLFs that are added by adb shell.
if trace_data.startswith('\r\n'):
trace_data = trace_data.replace('\r\n', '\n')
elif trace_data.startswith('\r\r\n'):
# On windows, adb adds an extra '\r' character for each line.
trace_data = trace_data.replace('\r\r\n', '\n')
# Skip the initial newline.
if trace_data[0] == '\n':
trace_data = trace_data[1:]
if not trace_data.startswith(TRACE_TEXT_HEADER):
# No header found, so assume the data is compressed.
trace_data = zlib.decompress(trace_data)
# Enforce Unix line-endings.
trace_data = trace_data.replace('\r', '')
# Skip any initial newlines.
while trace_data and trace_data[0] == '\n':
trace_data = trace_data[1:]
return trace_data
def fix_missing_tgids(trace_data, pid2_tgid):
"""Replaces missing TGIDs from the trace data with those found in procfs
Args:
trace_data: the atrace data
Returns:
The updated trace data with missing TGIDs replaced with the correct TGID
"""
def repl(m):
tid = m.group(2)
if (int(tid) > 0 and m.group(1) != '<idle>' and m.group(3) == '(-----)'
and tid in pid2_tgid):
# returns Proc_name-PID (TGID)
# Binder_2-381 (-----) becomes Binder_2-381 (128)
return m.group(1) + '-' + m.group(2) + ' ( ' + pid2_tgid[tid] + ')'
return m.group(0)
# matches something like:
# Binder_2-895 (-----)
trace_data = re.sub(r'^\s*(\S+)-(\d+)\s+(\(\S+\))', repl, trace_data,
flags=re.MULTILINE)
return trace_data
def fix_circular_traces(out):
"""Fix inconsistentcies in traces due to circular buffering.
The circular buffers are kept per CPU, so it is not guaranteed that the
beginning of a slice is overwritten before the end. To work around this, we
throw away the prefix of the trace where not all CPUs have events yet.
Args:
out: The data to fix.
Returns:
The updated trace data.
"""
# If any of the CPU's buffers have filled up and
# older events have been dropped, the kernel
# emits markers of the form '##### CPU 2 buffer started ####' on
# the line before the first event in the trace on that CPU.
#
# No such headers are emitted if there were no overflows or the trace
# was captured with non-circular buffers.
buffer_start_re = re.compile(r'^#+ CPU \d+ buffer started', re.MULTILINE)
start_of_full_trace = 0
while True:
result = buffer_start_re.search(out, start_of_full_trace + 1)
if result:
start_of_full_trace = result.start()
else:
break
if start_of_full_trace > 0:
# Need to keep the header intact to make the importer happy.
end_of_header = re.search(r'^[^#]', out, re.MULTILINE).start()
out = out[:end_of_header] + out[start_of_full_trace:]
return out
class AtraceConfig(tracing_agents.TracingConfig):
def __init__(self, atrace_categories, trace_buf_size, kfuncs,
app_name, compress_trace_data, from_file,
device_serial_number, trace_time, target):
tracing_agents.TracingConfig.__init__(self)
self.atrace_categories = atrace_categories
self.trace_buf_size = trace_buf_size
self.kfuncs = kfuncs
self.app_name = app_name
# Trace compression is broken on Windows.
# TODO: Fix https://crbug.com/739751.
self.compress_trace_data = \
compress_trace_data and platform.system() != 'Windows'
self.from_file = from_file
self.device_serial_number = device_serial_number
self.trace_time = trace_time
self.target = target
def add_options(parser):
options = optparse.OptionGroup(parser, 'Atrace options')
options.add_option('--atrace-categories', dest='atrace_categories',
help='Select atrace categories with a comma-delimited '
'list, e.g. --atrace-categories=cat1,cat2,cat3')
options.add_option('-k', '--ktrace', dest='kfuncs', action='store',
help='specify a comma-separated list of kernel functions '
'to trace')
options.add_option('--no-compress', dest='compress_trace_data',
default=True, action='store_false',
help='Tell the device not to send the trace data in '
'compressed form.')
options.add_option('-a', '--app', dest='app_name', default=None,
type='string', action='store',
help='enable application-level tracing for '
'comma-separated list of app cmdlines')
options.add_option('--from-file', dest='from_file',
action='store', help='read the trace from a '
'file (compressed) rather than running a '
'live trace')
return options
def get_config(options):
return AtraceConfig(options.atrace_categories,
options.trace_buf_size, options.kfuncs,
options.app_name, options.compress_trace_data,
options.from_file, options.device_serial_number,
options.trace_time, options.target)

View File

@@ -0,0 +1,126 @@
#!/usr/bin/env python
# Copyright (c) 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.
import contextlib
import logging
import os
import unittest
from systrace import decorators
from systrace import run_systrace
from systrace import util
from systrace.tracing_agents import atrace_agent
from devil.android import device_utils
from devil.android.sdk import intent
from py_utils import tempfile_ext
DEVICE_SERIAL = 'AG8404EC0444AGC'
ATRACE_ARGS = ['atrace', '-z', '-t', '10', '-b', '4096']
CATEGORIES = ['sched', 'gfx', 'view', 'wm']
ADB_SHELL = ['adb', '-s', DEVICE_SERIAL, 'shell']
SYSTRACE_CMD = ['./run_systrace.py', '--time', '10', '-o', 'out.html', '-e',
DEVICE_SERIAL] + CATEGORIES
TRACE_ARGS = (ATRACE_ARGS + CATEGORIES)
TEST_DIR = os.path.join(os.path.dirname(__file__), os.pardir, 'test_data')
ATRACE_DATA = os.path.join(TEST_DIR, 'atrace_data')
ATRACE_DATA_RAW = os.path.join(TEST_DIR, 'atrace_data_raw')
ATRACE_DATA_STRIPPED = os.path.join(TEST_DIR, 'atrace_data_stripped')
ATRACE_PROCFS_DUMP = os.path.join(TEST_DIR, 'atrace_procfs_dump')
ATRACE_EXTRACTED_TGIDS = os.path.join(TEST_DIR, 'atrace_extracted_tgids')
ATRACE_MISSING_TGIDS = os.path.join(TEST_DIR, 'atrace_missing_tgids')
ATRACE_FIXED_TGIDS = os.path.join(TEST_DIR, 'atrace_fixed_tgids')
class AtraceAgentTest(unittest.TestCase):
# TODO(washingtonp): These end-to-end tests do not work on the Trybot server
# because adb cannot be found on the Trybot servers. Figure out what the
# issue is and update this test.
@decorators.Disabled
def test_tracing(self):
TRACE_BUFFER_SIZE = '16384'
TRACE_TIME = '5'
devices = device_utils.DeviceUtils.HealthyDevices()
package_info = util.get_supported_browsers()['stable']
device = devices[0]
with tempfile_ext.TemporaryFileName() as output_file_name:
# Launch the browser before tracing.
device.StartActivity(
intent.Intent(activity=package_info.activity,
package=package_info.package,
data='about:blank',
extras={'create_new_tab': True}),
blocking=True, force_stop=True)
# Run atrace agent.
run_systrace.main_impl(['./run_systrace.py',
'-b',
TRACE_BUFFER_SIZE,
'-t',
TRACE_TIME,
'-o',
output_file_name,
'-e',
str(device),
'--atrace-categories=gfx,input,view'])
# Verify results.
with open(output_file_name, 'r') as f:
full_trace = f.read()
self.assertTrue('CPU#' in full_trace)
@decorators.HostOnlyTest
def test_construct_atrace_args(self):
options, categories = run_systrace.parse_options(SYSTRACE_CMD)
options.atrace_categories = categories
tracer_args = atrace_agent._construct_atrace_args(options, categories)
self.assertEqual(' '.join(TRACE_ARGS), ' '.join(tracer_args))
@decorators.HostOnlyTest
def test_strip_and_decompress_trace(self):
with contextlib.nested(open(ATRACE_DATA_RAW, 'r'),
open(ATRACE_DATA_STRIPPED, 'r')) as (f1, f2):
atrace_data_raw = f1.read()
atrace_data_stripped = f2.read()
trace_data = atrace_agent.strip_and_decompress_trace(atrace_data_raw)
self.assertEqual(atrace_data_stripped, trace_data)
@decorators.HostOnlyTest
def test_extract_tgids(self):
with contextlib.nested(open(ATRACE_PROCFS_DUMP, 'r'),
open(ATRACE_EXTRACTED_TGIDS, 'r')) as (f1, f2):
atrace_procfs_dump = f1.read()
atrace_procfs_extracted = f2.read()
tgids = eval(atrace_procfs_extracted)
result = atrace_agent.extract_tgids(atrace_procfs_dump.splitlines())
self.assertEqual(result, tgids)
@decorators.HostOnlyTest
def test_fix_missing_tgids(self):
with contextlib.nested(open(ATRACE_EXTRACTED_TGIDS, 'r'),
open(ATRACE_MISSING_TGIDS, 'r'),
open(ATRACE_FIXED_TGIDS, 'r')) as (f1, f2, f3):
atrace_data = f2.read()
tgid_map = eval(f1.read())
fixed = f3.read()
res = atrace_agent.fix_missing_tgids(atrace_data, tgid_map)
self.assertEqual(res, fixed)
if __name__ == "__main__":
logging.getLogger().setLevel(logging.DEBUG)
unittest.main(verbosity=2)

View File

@@ -0,0 +1,130 @@
# Copyright 2016 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 os
import re
import stat
import subprocess
import sys
import urllib2
import py_utils
from systrace import trace_result
from systrace import tracing_agents
from systrace.tracing_agents import atrace_agent
# ADB sends this text to indicate the beginning of the trace data.
TRACE_START_REGEXP = r'TRACE\:'
# Text that ADB sends, but does not need to be displayed to the user.
ADB_IGNORE_REGEXP = r'^capturing trace\.\.\. done|^capturing trace\.\.\.'
T2T_OUTPUT = 'trace.systrace'
def try_create_agent(options):
if options.from_file is not None:
with open(options.from_file, 'rb') as f_in:
if is_perfetto(f_in):
if convert_perfetto_trace(options.from_file):
options.from_file = T2T_OUTPUT
else:
print ('Perfetto trace file: ' + options.from_file +
' could not be converted.')
sys.exit(1)
return AtraceFromFileAgent(options)
else:
return False
def convert_perfetto_trace(in_file):
traceconv_path = os.path.abspath(os.path.join(os.path.dirname(__file__),
'../traceconv'))
try:
traceconv = urllib2.urlopen('https://get.perfetto.dev/traceconv')
with open(traceconv_path, 'w') as out:
out.write(traceconv.read())
except urllib2.URLError:
print 'Could not download traceconv to convert the Perfetto trace.'
sys.exit(1)
os.chmod(traceconv_path, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR)
return subprocess.call([traceconv_path, 'systrace', in_file, T2T_OUTPUT]) == 0
def is_perfetto(from_file):
# Starts with a preamble for field ID=1 (TracePacket)
if ord(from_file.read(1)) != 0x0a:
return False
for _ in range(10): # Check the first 10 packets are structured correctly
# Then a var int that specifies field size
field_size = 0
shift = 0
while True:
c = ord(from_file.read(1))
field_size |= (c & 0x7f) << shift
shift += 7
if not c & 0x80:
break
# The packet itself
from_file.seek(field_size, os.SEEK_CUR)
# The preamble for the next field ID=1 (TracePacket)
if ord(from_file.read(1)) != 0x0a:
return False
# Go back to the beginning of the file
from_file.seek(0)
return True
class AtraceFromFileConfig(tracing_agents.TracingConfig):
def __init__(self, from_file):
tracing_agents.TracingConfig.__init__(self)
self.fix_circular = True
self.from_file = from_file
def add_options(parser): # pylint: disable=unused-argument
# The atrace_from_file_agent is not currently used, so don't display
# any options.
return None
def get_config(options):
return AtraceFromFileConfig(options.from_file)
class AtraceFromFileAgent(tracing_agents.TracingAgent):
def __init__(self, options):
super(AtraceFromFileAgent, self).__init__()
self._filename = os.path.expanduser(options.from_file)
self._trace_data = False
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
# pylint: disable=unused-argument
return True
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
self._trace_data = self._read_trace_data()
return True
def SupportsExplicitClockSync(self):
return False
def RecordClockSyncMarker(self, sync_id, did_record_clock_sync_callback):
raise NotImplementedError
@py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
def GetResults(self, timeout=None):
return trace_result.TraceResult('trace-data', self._trace_data)
def _read_trace_data(self):
with open(self._filename, 'rb') as f:
result = f.read()
data_start = re.search(TRACE_START_REGEXP, result).end(0)
data = re.sub(ADB_IGNORE_REGEXP, '', result[data_start:])
return self._preprocess_data(data)
# pylint: disable=no-self-use
def _preprocess_data(self, data):
# TODO: add fix_threads and fix_tgids options back in here
# once we embed the dump data in the file (b/27504068)
data = atrace_agent.strip_and_decompress_trace(data)
data = atrace_agent.fix_circular_traces(data)
return data

View File

@@ -0,0 +1,82 @@
#!/usr/bin/env python
# Copyright (c) 2016 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 contextlib
import os
import unittest
from py_utils import tempfile_ext
from systrace import decorators
from systrace import run_systrace
from systrace import update_systrace_trace_viewer
TEST_DIR = os.path.join(os.path.dirname(__file__), '..', 'test_data')
COMPRESSED_ATRACE_DATA = os.path.join(TEST_DIR, 'compressed_atrace_data.txt')
DECOMPRESSED_ATRACE_DATA = os.path.join(TEST_DIR,
'decompressed_atrace_data.txt')
NON_EXISTENT_DATA = os.path.join(TEST_DIR, 'THIS_FILE_DOES_NOT_EXIST.txt')
class AtraceFromFileAgentTest(unittest.TestCase):
@decorators.HostOnlyTest
def test_from_file(self):
update_systrace_trace_viewer.update(force_update=True)
self.assertTrue(os.path.exists(
update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE))
try:
with tempfile_ext.TemporaryFileName() as output_file_name:
# use from-file to create a specific expected output
run_systrace.main_impl(['./run_systrace.py',
'--from-file',
COMPRESSED_ATRACE_DATA,
'-o',
output_file_name])
# and verify file contents
with contextlib.nested(open(output_file_name, 'r'),
open(DECOMPRESSED_ATRACE_DATA, 'r')) as (f1, f2):
full_trace = f1.read()
expected_contents = f2.read()
self.assertTrue(expected_contents in full_trace)
finally:
os.remove(update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE)
@decorators.HostOnlyTest
def test_default_output_filename(self):
update_systrace_trace_viewer.update(force_update=True)
self.assertTrue(os.path.exists(
update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE))
output_file_name = os.path.join(TEST_DIR, 'compressed_atrace_data.html')
try:
# use from-file to create a specific expected output
run_systrace.main_impl(['./run_systrace.py',
'--from-file',
COMPRESSED_ATRACE_DATA])
# and verify file contents
with contextlib.nested(open(output_file_name, 'r'),
open(DECOMPRESSED_ATRACE_DATA, 'r')) as (f1, f2):
full_trace = f1.read()
expected_contents = f2.read()
self.assertTrue(expected_contents in full_trace)
except:
raise
finally:
os.remove(update_systrace_trace_viewer.SYSTRACE_TRACE_VIEWER_HTML_FILE)
if os.path.exists(output_file_name):
os.remove(output_file_name)
@decorators.HostOnlyTest
def test_missing_file(self):
try:
run_systrace.main_impl(['./run_systrace.py',
'--from-file',
NON_EXISTENT_DATA])
self.fail('should not get here')
except IOError:
pass

View File

@@ -0,0 +1,128 @@
# 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.
# Tracing agent that captures periodic per-process memory dumps and other
# useful information from ProcFS like utime, stime, OOM stats, etc.
import json
import logging
import optparse
import py_utils
from devil.android import device_utils
from devil.android.device_errors import AdbShellCommandFailedError
from py_trace_event import trace_time as trace_time_module
from systrace import tracing_agents
from systrace import trace_result
TRACE_HEADER = 'ATRACE_PROCESS_DUMP'
TRACE_RESULT_NAME = 'atraceProcessDump'
HELPER_COMMAND = '/data/local/tmp/atrace_helper'
HELPER_STOP_COMMAND = 'kill -TERM `pidof atrace_helper`'
HELPER_DUMP_JSON = '/data/local/tmp/procdump.json'
class AtraceProcessDumpAgent(tracing_agents.TracingAgent):
def __init__(self):
super(AtraceProcessDumpAgent, self).__init__()
self._device = None
self._dump = None
self._clock_sync_markers = {}
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
self._device = device_utils.DeviceUtils(config.device_serial_number)
cmd = [HELPER_COMMAND, '-b', '-g',
'-t', str(config.dump_interval_ms),
'-o', HELPER_DUMP_JSON]
if config.full_dump_config:
cmd += ['-m', config.full_dump_config]
if config.enable_mmaps:
cmd += ['-s']
self._device.RunShellCommand(cmd, check_return=True, as_root=True)
return True
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
self._device.RunShellCommand(
HELPER_STOP_COMMAND,
shell=True, check_return=True, as_root=True)
try:
self._device.RunShellCommand(['test', '-f', HELPER_DUMP_JSON],
check_return=True, as_root=True)
self._dump = self._device.ReadFile(HELPER_DUMP_JSON, force_pull=True)
self._device.RunShellCommand(['rm', HELPER_DUMP_JSON],
check_return=True, as_root=True)
except AdbShellCommandFailedError:
logging.error('AtraceProcessDumpAgent failed to pull data. Check device storage.')
return False
return True
@py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
def GetResults(self, timeout=None):
result = TRACE_HEADER + '\n' + self._dump
cs = json.dumps(self._clock_sync_markers)
result = TRACE_HEADER + \
'\n{\"clock_sync_markers\":' + cs + ',\n\"dump\":' + self._dump + '}'
return trace_result.TraceResult(TRACE_RESULT_NAME, result)
def SupportsExplicitClockSync(self):
return True
def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
with self._device.adb.PersistentShell(self._device.serial) as shell:
ts_in_controller_domain = trace_time_module.Now()
output = shell.RunCommand(HELPER_COMMAND + ' --echo-ts', close=True)
ts_in_agent_domain = int(output[0][0])
self._clock_sync_markers[sync_id] = ts_in_agent_domain
did_record_sync_marker_callback(ts_in_controller_domain, sync_id)
class AtraceProcessDumpConfig(tracing_agents.TracingConfig):
def __init__(self, enabled, device_serial_number,
dump_interval_ms, full_dump_config, enable_mmaps):
tracing_agents.TracingConfig.__init__(self)
self.enabled = enabled
self.device_serial_number = device_serial_number
self.dump_interval_ms = dump_interval_ms
self.full_dump_config = full_dump_config
self.enable_mmaps = enable_mmaps
def add_options(parser):
options = optparse.OptionGroup(parser, 'Atrace process dump options')
options.add_option('--process-dump', dest='process_dump_enable',
default=False, action='store_true',
help='Capture periodic per-process memory dumps.')
options.add_option('--process-dump-interval', dest='process_dump_interval_ms',
default=5000,
help='Interval between memory dumps in milliseconds.')
options.add_option('--process-dump-full', dest='process_dump_full_config',
default=None,
help='Capture full memory dumps for some processes.\n' \
'Value: all, apps or comma-separated process names.')
options.add_option('--process-dump-mmaps', dest='process_dump_mmaps',
default=False, action='store_true',
help='Capture VM regions and memory-mapped files.\n' \
'It increases dump size dramatically, hence only ' \
'has effect if --process-dump-full is a whitelist.')
return options
def get_config(options):
can_enable = (options.target == 'android') and (not options.from_file)
return AtraceProcessDumpConfig(
enabled=(options.process_dump_enable and can_enable),
device_serial_number=options.device_serial_number,
dump_interval_ms=options.process_dump_interval_ms,
full_dump_config=options.process_dump_full_config,
enable_mmaps=options.process_dump_mmaps
)
def try_create_agent(config):
if config.enabled:
return AtraceProcessDumpAgent()
return None

View File

@@ -0,0 +1,258 @@
# 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.
import optparse
import os
import py_utils
from systrace import trace_result
from systrace import tracing_agents
class FtraceAgentIo(object):
@staticmethod
def writeFile(path, data):
if FtraceAgentIo.haveWritePermissions(path):
with open(path, 'w') as f:
f.write(data)
else:
raise IOError('Cannot write to %s; did you forget sudo/root?' % path)
@staticmethod
def readFile(path):
with open(path, 'r') as f:
return f.read()
@staticmethod
def haveWritePermissions(path):
return os.access(path, os.W_OK)
FT_DIR = "/sys/kernel/debug/tracing/"
FT_CLOCK = FT_DIR + "trace_clock"
FT_BUFFER_SIZE = FT_DIR + "buffer_size_kb"
FT_TRACER = FT_DIR + "current_tracer"
FT_PRINT_TGID = FT_DIR + "options/print-tgid"
FT_TRACE_ON = FT_DIR + "tracing_on"
FT_TRACE = FT_DIR + "trace"
FT_TRACE_MARKER = FT_DIR + "trace_marker"
FT_OVERWRITE = FT_DIR + "options/overwrite"
all_categories = {
"sched": {
"desc": "CPU Scheduling",
"req": ["sched/sched_switch/", "sched/sched_wakeup/"]
},
"freq": {
"desc": "CPU Frequency",
"req": ["power/cpu_frequency/"],
"opt": ["power/clock_set_rate/", "clk/clk_set_rate/"]
},
"irq": {
"desc": "CPU IRQS and IPIS",
"req": ["irq/"],
"opt": ["ipi/"]
},
"workq": {
"desc": "Kernel workqueues",
"req": ["workqueue/"]
},
"memreclaim": {
"desc": "Kernel Memory Reclaim",
"req": ["vmscan/mm_vmscan_direct_reclaim_begin/",
"vmscan/mm_vmscan_direct_reclaim_end/",
"vmscan/mm_vmscan_kswapd_wake/",
"vmscan/mm_vmscan_kswapd_sleep/"]
},
"idle": {
"desc": "CPU Idle",
"req": ["power/cpu_idle/"]
},
"regulators": {
"desc": "Voltage and Current Regulators",
"req": ["regulator/"]
},
"disk": {
"desc": "Disk I/O",
"req": ["block/block_rq_issue/",
"block/block_rq_complete/"],
"opt": ["f2fs/f2fs_sync_file_enter/",
"f2fs/f2fs_sync_file_exit/",
"f2fs/f2fs_write_begin/",
"f2fs/f2fs_write_end/",
"ext4/ext4_da_write_begin/",
"ext4/ext4_da_write_end/",
"ext4/ext4_sync_file_enter/",
"ext4/ext4_sync_file_exit/"]
}
}
def try_create_agent(config):
if config.target != 'linux':
return None
return FtraceAgent(FtraceAgentIo)
def list_categories(_):
agent = FtraceAgent(FtraceAgentIo)
agent._print_avail_categories()
class FtraceConfig(tracing_agents.TracingConfig):
def __init__(self, ftrace_categories, target, trace_buf_size):
tracing_agents.TracingConfig.__init__(self)
self.ftrace_categories = ftrace_categories
self.target = target
self.trace_buf_size = trace_buf_size
def add_options(parser):
options = optparse.OptionGroup(parser, 'Ftrace options')
options.add_option('--ftrace-categories', dest='ftrace_categories',
help='Select ftrace categories with a comma-delimited '
'list, e.g. --ftrace-categories=cat1,cat2,cat3')
return options
def get_config(options):
return FtraceConfig(options.ftrace_categories, options.target,
options.trace_buf_size)
class FtraceAgent(tracing_agents.TracingAgent):
def __init__(self, fio=FtraceAgentIo):
"""Initialize a systrace agent.
Args:
config: The command-line config.
categories: The trace categories to capture.
"""
super(FtraceAgent, self).__init__()
self._fio = fio
self._config = None
self._categories = None
def _get_trace_buffer_size(self):
buffer_size = 4096
if ((self._config.trace_buf_size is not None)
and (self._config.trace_buf_size > 0)):
buffer_size = self._config.trace_buf_size
return buffer_size
def _fix_categories(self, categories):
"""
Applies the default category (sched) if there are no categories
in the list and removes unavailable categories from the list.
Args:
categories: List of categories.
"""
if not categories:
categories = ["sched"]
return [x for x in categories
if self._is_category_available(x)]
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
"""Start tracing.
"""
self._config = config
categories = self._fix_categories(config.ftrace_categories)
self._fio.writeFile(FT_BUFFER_SIZE,
str(self._get_trace_buffer_size()))
self._fio.writeFile(FT_CLOCK, 'global')
self._fio.writeFile(FT_TRACER, 'nop')
self._fio.writeFile(FT_OVERWRITE, "0")
# TODO: riandrews to push necessary patches for TGID option to upstream
# linux kernel
# self._fio.writeFile(FT_PRINT_TGID, '1')
for category in categories:
self._category_enable(category)
self._categories = categories # need to store list of categories to disable
print 'starting tracing.'
self._fio.writeFile(FT_TRACE, '')
self._fio.writeFile(FT_TRACE_ON, '1')
return True
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
"""Collect the result of tracing.
This function will block while collecting the result. For sync mode, it
reads the data, e.g., from stdout, until it finishes. For async mode, it
blocks until the agent is stopped and the data is ready.
"""
self._fio.writeFile(FT_TRACE_ON, '0')
for category in self._categories:
self._category_disable(category)
return True
@py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
def GetResults(self, timeout=None):
# get the output
d = self._fio.readFile(FT_TRACE)
self._fio.writeFile(FT_BUFFER_SIZE, "1")
return trace_result.TraceResult('trace-data', d)
def SupportsExplicitClockSync(self):
return False
def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
# No implementation, but need to have this to support the API
# pylint: disable=unused-argument
return False
def _is_category_available(self, category):
if category not in all_categories:
return False
events_dir = FT_DIR + "events/"
req_events = all_categories[category]["req"]
for event in req_events:
event_full_path = events_dir + event + "enable"
if not self._fio.haveWritePermissions(event_full_path):
return False
return True
def _avail_categories(self):
ret = []
for event in all_categories:
if self._is_category_available(event):
ret.append(event)
return ret
def _print_avail_categories(self):
avail = self._avail_categories()
if len(avail):
print "tracing config:"
for category in self._avail_categories():
desc = all_categories[category]["desc"]
print "{0: <16}".format(category), ": ", desc
else:
print "No tracing categories available - perhaps you need root?"
def _category_enable_paths(self, category):
events_dir = FT_DIR + "events/"
req_events = all_categories[category]["req"]
for event in req_events:
event_full_path = events_dir + event + "enable"
yield event_full_path
if "opt" in all_categories[category]:
opt_events = all_categories[category]["opt"]
for event in opt_events:
event_full_path = events_dir + event + "enable"
if self._fio.haveWritePermissions(event_full_path):
yield event_full_path
def _category_enable(self, category):
for path in self._category_enable_paths(category):
self._fio.writeFile(path, "1")
def _category_disable(self, category):
for path in self._category_enable_paths(category):
self._fio.writeFile(path, "0")

View File

@@ -0,0 +1,143 @@
#!/usr/bin/env python
# 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.
import unittest
import logging
from systrace import decorators
from systrace import run_systrace
from systrace.tracing_agents import ftrace_agent
SYSTRACE_HOST_CMD_DEFAULT = ['./systrace.py', '--target=linux']
FT_DIR = "/sys/kernel/debug/tracing/"
FT_EVENT_DIR = FT_DIR + "events/"
FT_TRACE_ON = FT_DIR + "tracing_on"
FT_TRACE = FT_DIR + "trace"
FT_BUFFER_SIZE = FT_DIR + "buffer_size_kb"
def make_test_io_interface(permitted_files):
class TestIoImpl(object):
@staticmethod
def writeFile(path, data):
permitted_files[path] = data
@staticmethod
def readFile(path):
if path in permitted_files:
return permitted_files[path]
else:
return ""
@staticmethod
def haveWritePermissions(path):
return path in permitted_files
return TestIoImpl
class FtraceAgentTest(unittest.TestCase):
@decorators.HostOnlyTest
def test_avail_categories(self):
# sched only has required events
permitted_files = {
FT_EVENT_DIR + "sched/sched_switch/enable": "0",
FT_EVENT_DIR + "sched/sched_wakeup/enable": "0"
}
io_interface = make_test_io_interface(permitted_files)
agent = ftrace_agent.FtraceAgent(io_interface)
self.assertEqual(['sched'], agent._avail_categories())
# check for no available categories
permitted_files = {}
io_interface = make_test_io_interface(permitted_files)
agent = ftrace_agent.FtraceAgent(io_interface)
self.assertEqual([], agent._avail_categories())
# block has some required, some optional events
permitted_files = {
FT_EVENT_DIR + "block/block_rq_complete/enable": "0",
FT_EVENT_DIR + "block/block_rq_issue/enable": "0"
}
io_interface = make_test_io_interface(permitted_files)
agent = ftrace_agent.FtraceAgent(io_interface)
self.assertEqual(['disk'], agent._avail_categories())
@decorators.HostOnlyTest
def test_tracing_bootstrap(self):
workq_event_path = FT_EVENT_DIR + "workqueue/enable"
permitted_files = {
workq_event_path: "0",
FT_TRACE: "x"
}
io_interface = make_test_io_interface(permitted_files)
systrace_cmd = SYSTRACE_HOST_CMD_DEFAULT + ["workq"]
options, categories = run_systrace.parse_options(systrace_cmd)
agent = ftrace_agent.FtraceAgent(io_interface)
self.assertEqual(['workq'], agent._avail_categories())
# confirm tracing is enabled, buffer is cleared
agent.StartAgentTracing(options, categories)
self.assertEqual(permitted_files[FT_TRACE_ON], "1")
self.assertEqual(permitted_files[FT_TRACE], "")
# fill in file with dummy contents
dummy_trace = "trace_contents"
permitted_files[FT_TRACE] = dummy_trace
# confirm tracing is disabled
agent.StopAgentTracing()
agent.GetResults()
self.assertEqual(permitted_files[FT_TRACE_ON], "0")
# confirm trace is expected, and read from fs
self.assertEqual(agent.GetResults().raw_data, dummy_trace)
# confirm buffer size is reset to 1
self.assertEqual(permitted_files[FT_BUFFER_SIZE], "1")
@decorators.HostOnlyTest
def test_tracing_event_enable_disable(self):
# turn on irq tracing
ipi_event_path = FT_EVENT_DIR + "ipi/enable"
irq_event_path = FT_EVENT_DIR + "irq/enable"
permitted_files = {
ipi_event_path: "0",
irq_event_path: "0"
}
io_interface = make_test_io_interface(permitted_files)
systrace_cmd = SYSTRACE_HOST_CMD_DEFAULT + ["irq"]
options, categories = run_systrace.parse_options(systrace_cmd)
options.ftrace_categories = categories
agent = ftrace_agent.FtraceAgent(io_interface)
self.assertEqual(['irq'], agent._avail_categories())
# confirm all the event nodes are turned on during tracing
agent.StartAgentTracing(options)
self.assertEqual(permitted_files[irq_event_path], "1")
self.assertEqual(permitted_files[ipi_event_path], "1")
# and then turned off when completed.
agent.StopAgentTracing()
agent.GetResults()
self.assertEqual(permitted_files[irq_event_path], "0")
self.assertEqual(permitted_files[ipi_event_path], "0")
@decorators.HostOnlyTest
def test_buffer_size(self):
systrace_cmd = SYSTRACE_HOST_CMD_DEFAULT + ['-b', '16000']
options, categories = run_systrace.parse_options(systrace_cmd)
agent = ftrace_agent.FtraceAgent()
agent._config = options
agent._config.atrace_categories = categories
self.assertEqual(agent._get_trace_buffer_size(), 16000)
if __name__ == "__main__":
logging.getLogger().setLevel(logging.DEBUG)
unittest.main(verbosity=2)

View File

@@ -0,0 +1,121 @@
# 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.
import optparse
import threading
import py_utils
from devil.android import device_utils
from systrace import trace_result
from systrace import tracing_agents
from py_trace_event import trace_time as trace_time_module
TRACE_FILE_PATH = \
'/sdcard/Android/data/org.chromium.latency.walt/files/trace.txt'
CLOCK_DOMAIN_MARKER = '# clock_type=LINUX_CLOCK_MONOTONIC\n'
def try_create_agent(options):
if options.is_walt_enabled:
return WaltAgent()
return None
class WaltConfig(tracing_agents.TracingConfig):
def __init__(self, device_serial_number, is_walt_enabled):
tracing_agents.TracingConfig.__init__(self)
self.device_serial_number = device_serial_number
self.is_walt_enabled = is_walt_enabled
def add_options(parser):
options = optparse.OptionGroup(parser, 'WALT trace options')
options.add_option('--walt', dest='is_walt_enabled', default=False,
action='store_true', help='Use the WALT tracing agent. '
'WALT is a device for measuring latency of physical '
'sensors on phones and computers. '
'See https://github.com/google/walt')
return options
def get_config(options):
return WaltConfig(options.device_serial_number, options.is_walt_enabled)
class WaltAgent(tracing_agents.TracingAgent):
"""
This tracing agent requires the WALT app to be installed on the Android phone,
and requires the WALT device to be attached to the phone. WALT is a device
for measuring latency of physical sensors and outputs on phones and
computers. For more information, visit https://github.com/google/walt
"""
def __init__(self):
super(WaltAgent, self).__init__()
self._trace_contents = None
self._config = None
self._device_utils = None
self._clock_sync_marker = None
self._collection_thread = None
def __repr__(self):
return 'WaltAgent'
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
del timeout # unused
self._config = config
self._device_utils = device_utils.DeviceUtils(
self._config.device_serial_number)
if self._device_utils.PathExists(TRACE_FILE_PATH):
# clear old trace events so they are not included in the current trace
self._device_utils.WriteFile(TRACE_FILE_PATH, '')
return True
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
"""Stops tracing and starts collecting results.
To synchronously retrieve the results after calling this function,
call GetResults().
"""
del timeout # unused
self._collection_thread = threading.Thread(
target=self._collect_trace_data)
self._collection_thread.start()
return True
def _collect_trace_data(self):
self._trace_contents = self._device_utils.ReadFile(TRACE_FILE_PATH)
def SupportsExplicitClockSync(self):
return True
def RecordClockSyncMarker(self, sync_id, did_record_clock_sync_callback):
cmd = 'cat /proc/timer_list | grep now'
t1 = trace_time_module.Now()
command_result = self._device_utils.RunShellCommand(cmd, shell=True)
nsec = command_result[0].split()[2]
self._clock_sync_marker = format_clock_sync_marker(sync_id, nsec)
did_record_clock_sync_callback(t1, sync_id)
@py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
def GetResults(self, timeout=None):
del timeout # unused
self._collection_thread.join()
self._collection_thread = None
return trace_result.TraceResult('waltTrace', self._get_trace_result())
def _get_trace_result(self):
result = '# tracer: \n' + CLOCK_DOMAIN_MARKER + self._trace_contents
if self._clock_sync_marker is not None:
result += self._clock_sync_marker
return result
def format_clock_sync_marker(sync_id, nanosec_time):
return ('<0>-0 (-----) [001] ...1 ' + str(float(nanosec_time) / 1e9)
+ ': tracing_mark_write: trace_event_clock_sync: name='
+ sync_id + '\n')

View File

@@ -0,0 +1,51 @@
#!/usr/bin/env python
# Copyright (c) 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.
import logging
import unittest
from systrace import decorators
from systrace import run_systrace
from systrace.tracing_agents import walt_agent
class WaltAgentTest(unittest.TestCase):
"""
The WALT agent pulls the trace log from the Android phone, and does not
communicate with the WALT device directly. This makes the agent similar
to atrace. Since the host only connects to the Android phone, more exhaustive
testing would require mocking DeviceUtils.
"""
@decorators.HostOnlyTest
def test_construct_walt_args(self):
options, _ = run_systrace.parse_options(['./run_systrace.py',
'--walt'])
self.assertTrue(walt_agent.get_config(options).is_walt_enabled)
options, _ = run_systrace.parse_options(['./run_systrace.py'])
self.assertFalse(walt_agent.get_config(options).is_walt_enabled)
@decorators.HostOnlyTest
def test_format_clock_sync_marker(self):
actual_marker = walt_agent.format_clock_sync_marker(
'some_sync_id', 12345678901234)
expected_marker = ('<0>-0 (-----) [001] ...1 12345.6789012: ' +
'tracing_mark_write: trace_event_clock_sync: ' +
'name=some_sync_id\n')
self.assertEqual(actual_marker, expected_marker)
@decorators.HostOnlyTest
def test_get_results_string(self):
agent = walt_agent.WaltAgent()
agent._trace_contents = '<trace contents here>\n'
agent._clock_sync_marker = '<clock sync marker here>\n'
result = agent._get_trace_result()
self.assertEquals(result, '# tracer: \n# clock_type=LINUX_CLOCK_MONOTONIC\n'
'<trace contents here>\n<clock sync marker here>\n')
if __name__ == "__main__":
logging.getLogger().setLevel(logging.DEBUG)
unittest.main(verbosity=2)

View File

@@ -0,0 +1,309 @@
#!/usr/bin/env python
# Copyright 2016 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.
'''Tracing controller class. This class manages
multiple tracing agents and collects data from all of them. It also
manages the clock sync process.
'''
import ast
import json
import sys
import tempfile
import uuid
import py_utils
from systrace import trace_result
from systrace import tracing_agents
from py_trace_event import trace_event
TRACE_DATA_CONTROLLER_NAME = 'systraceController'
def ControllerAgentClockSync(issue_ts, name):
"""Record the clock sync marker for controller tracing agent.
Unlike with the other tracing agents, the tracing controller should not
call this directly. Rather, it is called via callback from the other
tracing agents when they write a trace.
"""
trace_event.clock_sync(name, issue_ts=issue_ts)
class TracingControllerAgent(tracing_agents.TracingAgent):
def __init__(self):
super(TracingControllerAgent, self).__init__()
self._log_path = None
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StartAgentTracing(self, config, timeout=None):
"""Start tracing for the controller tracing agent.
Start tracing for the controller tracing agent. Note that
the tracing controller records the "controller side"
of the clock sync records, and nothing else.
"""
del config
if not trace_event.trace_can_enable():
raise RuntimeError, ('Cannot enable trace_event;'
' ensure py_utils is in PYTHONPATH')
controller_log_file = tempfile.NamedTemporaryFile(delete=False)
self._log_path = controller_log_file.name
controller_log_file.close()
trace_event.trace_enable(self._log_path)
return True
@py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
def StopAgentTracing(self, timeout=None):
"""Stops tracing for the controller tracing agent.
"""
# pylint: disable=no-self-use
# This function doesn't use self, but making it a member function
# for consistency with the other TracingAgents
trace_event.trace_disable()
return True
@py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
def GetResults(self, timeout=None):
"""Gets the log output from the controller tracing agent.
This output only contains the "controller side" of the clock sync records.
"""
with open(self._log_path, 'r') as outfile:
data = ast.literal_eval(outfile.read() + ']')
# Explicitly set its own clock domain. This will stop the Systrace clock
# domain from incorrectly being collapsed into the on device clock domain.
formatted_data = {
'traceEvents': data,
'metadata': {
'clock-domain': 'SYSTRACE',
}
}
return trace_result.TraceResult(TRACE_DATA_CONTROLLER_NAME,
json.dumps(formatted_data))
def SupportsExplicitClockSync(self):
"""Returns whether this supports explicit clock sync.
Although the tracing controller conceptually supports explicit clock
sync, it is not an agent controlled by other controllers so it does not
define RecordClockSyncMarker (rather, the recording of the "controller
side" of the clock sync marker is done in _IssueClockSyncMarker). Thus,
SupportsExplicitClockSync must return false.
"""
return False
# pylint: disable=unused-argument
def RecordClockSyncMarker(self, sync_id, callback):
raise NotImplementedError
class TracingController(object):
def __init__(self, agents_with_config, controller_config):
"""Create tracing controller.
Create a tracing controller object. Note that the tracing
controller is also a tracing agent.
Args:
agents_with_config: List of tracing agents for this controller with the
corresponding tracing configuration objects.
controller_config: Configuration options for the tracing controller.
"""
self._child_agents = None
self._child_agents_with_config = agents_with_config
self._controller_agent = TracingControllerAgent()
self._controller_config = controller_config
self._trace_in_progress = False
self.all_results = None
@property
def get_child_agents(self):
return self._child_agents
def StartTracing(self):
"""Start tracing for all tracing agents.
This function starts tracing for both the controller tracing agent
and the child tracing agents.
Returns:
Boolean indicating whether or not the start tracing succeeded.
Start tracing is considered successful if at least the
controller tracing agent was started.
"""
assert not self._trace_in_progress, 'Trace already in progress.'
self._trace_in_progress = True
# Start the controller tracing agents. Controller tracing agent
# must be started successfully to proceed.
if not self._controller_agent.StartAgentTracing(
self._controller_config,
timeout=self._controller_config.timeout):
print 'Unable to start controller tracing agent.'
return False
# Start the child tracing agents.
succ_agents = []
for agent_and_config in self._child_agents_with_config:
agent = agent_and_config.agent
config = agent_and_config.config
if agent.StartAgentTracing(config,
timeout=self._controller_config.timeout):
succ_agents.append(agent)
else:
print 'Agent %s not started.' % str(agent)
# Print warning if all agents not started.
na = len(self._child_agents_with_config)
ns = len(succ_agents)
if ns < na:
print 'Warning: Only %d of %d tracing agents started.' % (ns, na)
self._child_agents = succ_agents
return True
def StopTracing(self):
"""Issue clock sync marker and stop tracing for all tracing agents.
This function stops both the controller tracing agent
and the child tracing agents. It issues a clock sync marker prior
to stopping tracing.
Returns:
Boolean indicating whether or not the stop tracing succeeded
for all agents.
"""
assert self._trace_in_progress, 'No trace in progress.'
self._trace_in_progress = False
# Issue the clock sync marker and stop the child tracing agents.
self._IssueClockSyncMarker()
succ_agents = []
for agent in self._child_agents:
if agent.StopAgentTracing(timeout=self._controller_config.timeout):
succ_agents.append(agent)
else:
print 'Agent %s not stopped.' % str(agent)
# Stop the controller tracing agent. Controller tracing agent
# must be stopped successfully to proceed.
if not self._controller_agent.StopAgentTracing(
timeout=self._controller_config.timeout):
print 'Unable to stop controller tracing agent.'
return False
# Print warning if all agents not stopped.
na = len(self._child_agents)
ns = len(succ_agents)
if ns < na:
print 'Warning: Only %d of %d tracing agents stopped.' % (ns, na)
self._child_agents = succ_agents
# Collect the results from all the stopped tracing agents.
all_results = []
for agent in self._child_agents + [self._controller_agent]:
try:
result = agent.GetResults(
timeout=self._controller_config.collection_timeout)
if not result:
print 'Warning: Timeout when getting results from %s.' % str(agent)
continue
if result.source_name in [r.source_name for r in all_results]:
print ('Warning: Duplicate tracing agents named %s.' %
result.source_name)
all_results.append(result)
# Check for exceptions. If any exceptions are seen, reraise and abort.
# Note that a timeout exception will be swalloed by the timeout
# mechanism and will not get to that point (it will return False instead
# of the trace result, which will be dealt with above)
except:
print 'Warning: Exception getting results from %s:' % str(agent)
print sys.exc_info()[0]
raise
self.all_results = all_results
return all_results
def GetTraceType(self):
"""Return a string representing the child agents that are being traced."""
sorted_agents = sorted(map(str, self._child_agents))
return ' + '.join(sorted_agents)
def _IssueClockSyncMarker(self):
"""Issue clock sync markers to all the child tracing agents."""
for agent in self._child_agents:
if agent.SupportsExplicitClockSync():
sync_id = GetUniqueSyncID()
agent.RecordClockSyncMarker(sync_id, ControllerAgentClockSync)
def GetUniqueSyncID():
"""Get a unique sync ID.
Gets a unique sync ID by generating a UUID and converting it to a string
(since UUIDs are not JSON serializable)
"""
return str(uuid.uuid4())
class AgentWithConfig(object):
def __init__(self, agent, config):
self.agent = agent
self.config = config
def CreateAgentsWithConfig(options, modules):
"""Create tracing agents.
This function will determine which tracing agents are valid given the
options and create those agents along with their corresponding configuration
object.
Args:
options: The command-line options.
modules: The modules for either Systrace or profile_chrome.
TODO(washingtonp): After all profile_chrome agents are in
Systrace, this parameter will no longer be valid.
Returns:
A list of AgentWithConfig options containing agents and their corresponding
configuration object.
"""
result = []
for module in modules:
config = module.get_config(options)
agent = module.try_create_agent(config)
if agent and config:
result.append(AgentWithConfig(agent, config))
return [x for x in result if x and x.agent]
class TracingControllerConfig(tracing_agents.TracingConfig):
def __init__(self, output_file, trace_time, write_json,
link_assets, asset_dir, timeout, collection_timeout,
device_serial_number, target, trace_buf_size):
tracing_agents.TracingConfig.__init__(self)
self.output_file = output_file
self.trace_time = trace_time
self.write_json = write_json
self.link_assets = link_assets
self.asset_dir = asset_dir
self.timeout = timeout
self.collection_timeout = collection_timeout
self.device_serial_number = device_serial_number
self.target = target
self.trace_buf_size = trace_buf_size
def GetControllerConfig(options):
return TracingControllerConfig(options.output_file, options.trace_time,
options.write_json,
options.link_assets, options.asset_dir,
options.timeout, options.collection_timeout,
options.device_serial_number, options.target,
options.trace_buf_size)
def GetChromeStartupControllerConfig(options):
return TracingControllerConfig(None, options.trace_time,
options.write_json, None, None, None, None,
None, None, options.trace_buf_size)

View File

@@ -0,0 +1,138 @@
#!/usr/bin/env python
# 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.
import codecs
import optparse
import os
import re
import subprocess
import sys
_CATAPULT_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir))
sys.path.append(os.path.join(_CATAPULT_PATH, 'tracing'))
# this import needs to be after the change to sys.path above
#pylint: disable=wrong-import-position
from tracing_build import vulcanize_trace_viewer
SYSTRACE_TRACE_VIEWER_HTML_FILE = os.path.join(
os.path.abspath(os.path.dirname(__file__)),
'systrace_trace_viewer.html')
CATAPULT_REV_ = 'CATAPULT_REV'
NO_AUTO_UPDATE_ = 'NO_AUTO_UPDATE'
UNKNOWN_REVISION_ = 'UNKNOWN'
def create_catapult_rev_str_(revision):
return '<!--' + CATAPULT_REV_ + '=' + str(revision) + '-->'
def get_catapult_rev_in_file_(html_file):
assert os.path.exists(html_file)
rev = ''
with open(html_file, 'r') as f:
lines = f.readlines()
for line in lines[::-1]:
if CATAPULT_REV_ in line:
tokens = line.split(CATAPULT_REV_)
rev = re.sub(r'[=\->]', '', tokens[1]).strip()
break
return rev
def get_catapult_rev_in_git_():
try:
catapult_rev = subprocess.check_output(
'git rev-parse HEAD',
shell=True, # Needed by Windows
cwd=os.path.dirname(os.path.abspath(__file__))).strip()
except (subprocess.CalledProcessError, OSError):
return None
if not catapult_rev:
return None
return catapult_rev
def update(no_auto_update=False, no_min=False, force_update=False):
"""Update the systrace trace viewer html file.
When the html file exists, do not update the file if
1. the revision is NO_AUTO_UPDATE_;
2. or the revision is not changed.
Args:
no_auto_update: If true, force updating the file with revision
NO_AUTO_UPDATE_. Future auto-updates will be skipped.
no_min: If true, skip minification when updating the file.
force_update: If true, update the systrace trace viewer file no matter
what.
"""
if no_auto_update:
new_rev = NO_AUTO_UPDATE_
else:
new_rev = get_catapult_rev_in_git_()
if not new_rev:
# Source tree could be missing git metadata.
print >> sys.stderr, 'Warning: Couldn\'t determine current git revision.'
new_rev = UNKNOWN_REVISION_
need_update = False
if force_update:
need_update = True
elif no_auto_update:
need_update = True
elif not os.path.exists(SYSTRACE_TRACE_VIEWER_HTML_FILE):
need_update = True
else:
old_rev = get_catapult_rev_in_file_(SYSTRACE_TRACE_VIEWER_HTML_FILE)
if not old_rev or old_rev == UNKNOWN_REVISION_:
need_update = True
# If old_rev was set to NO_AUTO_UPDATE_ it should be skipped, since forced
# update cases have been already handled above.
if old_rev != new_rev and old_rev != NO_AUTO_UPDATE_:
need_update = True
if not need_update:
print 'Update skipped.'
return
print 'Generating viewer file %s with revision %s.' % (
SYSTRACE_TRACE_VIEWER_HTML_FILE, new_rev)
# Generate the vulcanized result.
with codecs.open(SYSTRACE_TRACE_VIEWER_HTML_FILE,
encoding='utf-8', mode='w') as f:
vulcanize_trace_viewer.WriteTraceViewer(
f,
config_name='full',
minify=(not no_min),
output_html_head_and_body=False)
if not force_update:
f.write(create_catapult_rev_str_(new_rev))
def main():
parser = optparse.OptionParser()
parser.add_option('--force-update', dest='force_update',
default=False, action='store_true', help='force update the '
'systrace trace viewer html file')
parser.add_option('--no-auto-update', dest='no_auto_update',
default=False, action='store_true', help='force update the '
'systrace trace viewer html file and disable auto-updates, '
'delete \'systrace_trace_viewer.html\' to re-enable '
'auto-updates')
parser.add_option('--no-min', dest='no_min', default=False,
action='store_true', help='skip minification')
# pylint: disable=unused-variable
options, unused_args = parser.parse_args(sys.argv[1:])
update(no_auto_update=options.no_auto_update,
no_min=options.no_min,
force_update=options.force_update)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,149 @@
# 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.
import optparse
import os
import sys
from devil.android.constants import chrome
from devil.android import device_utils, device_errors
class OptionParserIgnoreErrors(optparse.OptionParser):
"""Wrapper for OptionParser that ignores errors and produces no output."""
def error(self, msg):
pass
def exit(self, status=0, msg=None):
pass
def print_usage(self, out_file=None):
pass
def print_help(self, out_file=None):
pass
def print_version(self, out_file=None):
pass
def run_adb_shell(shell_args, device_serial):
"""Runs "adb shell" with the given arguments.
Args:
shell_args: array of arguments to pass to adb shell.
device_serial: if not empty, will add the appropriate command-line
parameters so that adb targets the given device.
Returns:
A tuple containing the adb output (stdout & stderr) and the return code
from adb. Will exit if adb fails to start.
"""
adb_output = []
adb_return_code = 0
device = device_utils.DeviceUtils.HealthyDevices(device_arg=device_serial)[0]
try:
adb_output = device.RunShellCommand(shell_args, shell=False,
check_return=True, raw_output=True)
except device_errors.AdbShellCommandFailedError as error:
adb_return_code = error.status
adb_output = error.output
return (adb_output, adb_return_code)
def get_device_sdk_version():
"""Uses adb to attempt to determine the SDK version of a running device."""
getprop_args = ['getprop', 'ro.build.version.sdk']
# get_device_sdk_version() is called before we even parse our command-line
# args. Therefore, parse just the device serial number part of the
# command-line so we can send the adb command to the correct device.
parser = OptionParserIgnoreErrors()
parser.add_option('-e', '--serial', dest='device_serial', type='string')
options, unused_args = parser.parse_args() # pylint: disable=unused-variable
success = False
adb_output, adb_return_code = run_adb_shell(getprop_args,
options.device_serial)
if adb_return_code == 0:
# ADB may print output other than the version number (e.g. it chould
# print a message about starting the ADB server).
# Break the ADB output into white-space delimited segments.
parsed_output = str.split(adb_output)
if parsed_output:
# Assume that the version number is the last thing printed by ADB.
version_string = parsed_output[-1]
if version_string:
try:
# Try to convert the text into an integer.
version = int(version_string)
except ValueError:
version = -1
else:
success = True
if not success:
print >> sys.stderr, adb_output
raise Exception("Failed to get device sdk version")
return version
def get_supported_browsers():
"""Returns the package names of all supported browsers."""
# Add aliases for backwards compatibility.
supported_browsers = {
'stable': chrome.PACKAGE_INFO['chrome_stable'],
'beta': chrome.PACKAGE_INFO['chrome_beta'],
'dev': chrome.PACKAGE_INFO['chrome_dev'],
'build': chrome.PACKAGE_INFO['chrome'],
}
supported_browsers.update(chrome.PACKAGE_INFO)
return supported_browsers
def get_default_serial():
if 'ANDROID_SERIAL' in os.environ:
return os.environ['ANDROID_SERIAL']
return None
def get_main_options(parser):
parser.add_option('-o', dest='output_file', help='write trace output to FILE',
default=None, metavar='FILE')
parser.add_option('-t', '--time', dest='trace_time', type='int',
help='trace for N seconds', metavar='N')
parser.add_option('-j', '--json', dest='write_json',
default=False, action='store_true',
help='write a JSON file')
parser.add_option('--link-assets', dest='link_assets', default=False,
action='store_true',
help='(deprecated)')
parser.add_option('--from-file', dest='from_file', action='store',
help='read the trace from a file (compressed) rather than'
'running a live trace')
parser.add_option('--asset-dir', dest='asset_dir', default='trace-viewer',
type='string', help='(deprecated)')
parser.add_option('-e', '--serial', dest='device_serial_number',
default=get_default_serial(),
type='string', help='adb device serial number')
parser.add_option('--target', dest='target', default='android', type='string',
help='choose tracing target (android or linux)')
parser.add_option('--timeout', dest='timeout', type='int',
help='timeout for start and stop tracing (seconds)')
parser.add_option('--collection-timeout', dest='collection_timeout',
type='int', help='timeout for data collection (seconds)')
parser.add_option('-a', '--app', dest='app_name', default=None,
type='string', action='store',
help='enable application-level tracing for '
'comma-separated list of app cmdlines')
parser.add_option('-t', '--time', dest='trace_time', type='int',
help='trace for N seconds', metavar='N')
parser.add_option('-b', '--buf-size', dest='trace_buf_size',
type='int', help='use a trace buffer size '
' of N KB', metavar='N')
return parser