atrace.cpp revision 6eea6fb259a6d0b1c585d3267b8df7ca29a1206d
1fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/*
2fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Copyright (C) 2012 The Android Open Source Project
3fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *
4fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Licensed under the Apache License, Version 2.0 (the "License");
5fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * you may not use this file except in compliance with the License.
6fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * You may obtain a copy of the License at
7fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *
8fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *      http://www.apache.org/licenses/LICENSE-2.0
9fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis *
10fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * Unless required by applicable law or agreed to in writing, software
11fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * distributed under the License is distributed on an "AS IS" BASIS,
12fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * See the License for the specific language governing permissions and
14fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis * limitations under the License.
15fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis */
16fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
17fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <errno.h>
18fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <fcntl.h>
194edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling#include <getopt.h>
20fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <signal.h>
21fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdarg.h>
22fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdbool.h>
23fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdio.h>
24fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <stdlib.h>
25fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <sys/sendfile.h>
26fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis#include <time.h>
277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis#include <zlib.h>
28fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
296eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <binder/IBinder.h>
306eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <binder/IServiceManager.h>
316eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <binder/Parcel.h>
326eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
336eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <cutils/properties.h>
346eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
356eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <utils/String8.h>
366eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis#include <utils/Trace.h>
376eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
386eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisusing namespace android;
396eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
40ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
41ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
426eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisenum { MAX_SYS_FILES = 8 };
436eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
446eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisconst char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
456eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
466eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennistypedef enum { OPT, REQ } requiredness  ;
476eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
486eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstruct TracingCategory {
496eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // The name identifying the category.
506eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    const char* name;
516eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
526eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // A longer description of the category.
536eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    const char* longname;
546eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
556eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // The userland tracing tags that the category enables.
566eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    uint64_t tags;
576eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
586eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // The fname==NULL terminated list of /sys/ files that the category
596eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // enables.
606eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    struct {
616eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        // Whether the file must be writable in order to enable the tracing
626eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        // category.
636eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        requiredness required;
646eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
656eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        // The path to the enable file.
666eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const char* path;
676eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } sysfiles[MAX_SYS_FILES];
686eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis};
696eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
706eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis/* Tracing categories */
716eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic const TracingCategory k_categories[] = {
726eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "gfx",    "Graphics",         ATRACE_TAG_GRAPHICS, { } },
736eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "input",  "Input",            ATRACE_TAG_INPUT, { } },
746eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "view",   "View System",      ATRACE_TAG_VIEW, { } },
756eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "wm",     "Window Manager",   ATRACE_TAG_WINDOW_MANAGER, { } },
766eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "am",     "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
776eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "audio",  "Audio",            ATRACE_TAG_AUDIO, { } },
786eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "video",  "Video",            ATRACE_TAG_VIDEO, { } },
796eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "camera", "Camera",           ATRACE_TAG_CAMERA, { } },
806eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "sched",  "CPU Scheduling",   0, {
816eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { REQ,  "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
826eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { REQ,  "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
836eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
846eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "freq",   "CPU Frequency",    0, {
856eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { REQ,  "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
866eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { OPT, "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
876eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
886eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "membus", "Memory Bus Utilization", 0, {
896eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { REQ,  "/sys/kernel/debug/tracing/events/memory_bus/enable" },
906eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
916eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "idle",   "CPU Idle",         0, {
926eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { REQ,  "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
936eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
946eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "disk",   "Disk I/O",         0, {
956eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { REQ,  "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
966eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { REQ,  "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
976eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { REQ,  "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
986eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { REQ,  "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
996eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
1006eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "load",   "CPU Load",         0, {
1016eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { REQ,  "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
1026eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
1036eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "sync",   "Synchronization",  0, {
1046eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { REQ,  "/sys/kernel/debug/tracing/events/sync/enable" },
1056eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
1066eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    { "workq",  "Kernel Workqueues", 0, {
1076eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        { REQ,  "/sys/kernel/debug/tracing/events/workqueue/enable" },
1086eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    } },
1096eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis};
1106eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
111fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Command line options */
112fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic int g_traceDurationSeconds = 5;
113fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceOverwrite = false;
114cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic int g_traceBufferSizeKB = 2048;
1157b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennisstatic bool g_compress = false;
11631be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic bool g_nohup = false;
11731be80f02cddda55e75614884038fa4645b694cdGlenn Kastenstatic int g_initialSleepSecs = 0;
118fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
119fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Global state */
120fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool g_traceAborted = false;
1216eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool g_categoryEnables[NELEM(k_categories)] = {};
122fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
123fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis/* Sys file paths */
124fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_traceClockPath =
125fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace_clock";
126fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
127cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic const char* k_traceBufferSizePath =
128cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    "/sys/kernel/debug/tracing/buffer_size_kb";
129cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
130fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOverwriteEnablePath =
131fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/options/overwrite";
132fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
133fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracingOnPath =
134fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/tracing_on";
135fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
136fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic const char* k_tracePath =
137fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    "/sys/kernel/debug/tracing/trace";
138fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
139e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis// Check whether a file exists.
140e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennisstatic bool fileExists(const char* filename) {
141e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return access(filename, F_OK) != -1;
142e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis}
143e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis
1446eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Check whether a file is writable.
1456eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool fileIsWritable(const char* filename) {
1466eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return access(filename, W_OK) != -1;
1476eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
1486eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
149fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Write a string to a file, returning true if the write was successful.
1506eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool writeStr(const char* filename, const char* str)
151fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
152fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int fd = open(filename, O_WRONLY);
153fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (fd == -1) {
154fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", filename,
155fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
156fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
157fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
158fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
159fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
160fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ssize_t len = strlen(str);
161fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (write(fd, str, len) != len) {
162fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
163fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
164fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = false;
165fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
166fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
167fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(fd);
168fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
169fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
170fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
171fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
1726eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Enable or disable a kernel option by writing a "1" or a "0" into a /sys
1736eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// file.
174fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setKernelOptionEnable(const char* filename, bool enable)
175fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
176fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(filename, enable ? "1" : "0");
177fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
178fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
1796eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Check whether the category is supported on the device with the current
1806eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// rootness.  A category is supported only if all its required /sys/ files are
1816eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// writable and if enabling the category will enable one or more tracing tags
1826eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// or /sys/ files.
1836eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool isCategorySupported(const TracingCategory& category)
1843169533f1d11c4a7aa0cd6fa2aa04fc810db0de6Jamie Gennis{
1856eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    bool ok = category.tags != 0;
1866eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < MAX_SYS_FILES; i++) {
1876eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const char* path = category.sysfiles[i].path;
1886eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        bool req = category.sysfiles[i].required == REQ;
1896eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (path != NULL) {
1906eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (req) {
1916eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (!fileIsWritable(path)) {
1926eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    return false;
1936eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                } else {
1946eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    ok = true;
1956eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
1966eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            } else {
1976eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                ok |= fileIsWritable(path);
1986eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
1996eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
200e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    }
201e8744fd4dce2881c83d69c084b6937d0397ace05Jamie Gennis    return ok;
202cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
203cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
2046eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Check whether the category would be supported on the device if the user
2056eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// were root.  This function assumes that root is able to write to any file
2066eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// that exists.  It performs the same logic as isCategorySupported, but it
2076eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// uses file existance rather than writability in the /sys/ file checks.
2086eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool isCategorySupportedForRoot(const TracingCategory& category)
2099ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling{
2106eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    bool ok = category.tags != 0;
2116eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < MAX_SYS_FILES; i++) {
2126eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const char* path = category.sysfiles[i].path;
2136eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        bool req = category.sysfiles[i].required == REQ;
2146eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (path != NULL) {
2156eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (req) {
2166eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (!fileExists(path)) {
2176eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    return false;
2186eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                } else {
2196eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    ok = true;
2206eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
2216eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            } else {
2226eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                ok |= fileExists(path);
2236eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
2246eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
2259ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    }
2269ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling    return ok;
2279ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling}
2289ba4baf178bb9dad3912403bfd9aee07c14da33aErik Gilling
2296eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Enable or disable overwriting of the kernel trace buffers.  Disabling this
2306eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// will cause tracing to stop once the trace buffers have filled up.
2316eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool setTraceOverwriteEnable(bool enable)
232ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown{
2336eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return setKernelOptionEnable(k_tracingOverwriteEnablePath, enable);
234ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown}
235ac9453d82e9077a8b02afa4e26ef9ff1f47b4ee9Jeff Brown
236fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable kernel tracing.
237fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setTracingEnabled(bool enable)
238fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
239fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return setKernelOptionEnable(k_tracingOnPath, enable);
240fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
241fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
242fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Clear the contents of the kernel trace.
243fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool clearTrace()
244fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
245fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = creat(k_tracePath, 0);
246fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
247fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
248fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
249fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return false;
250fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
251fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
252fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
253fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
254fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return true;
255fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
256fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
257cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis// Set the size of the kernel's trace buffer in kilobytes.
258cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennisstatic bool setTraceBufferSizeKB(int size)
259cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis{
260cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    char str[32] = "1";
261cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    int len;
262cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    if (size < 1) {
263cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis        size = 1;
264cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    }
265cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    snprintf(str, 32, "%d", size);
266cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    return writeStr(k_traceBufferSizePath, str);
267cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis}
268cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
269fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable or disable the kernel's use of the global clock.  Disabling the global
270fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// clock will result in the kernel using a per-CPU local clock.
271fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic bool setGlobalClockEnable(bool enable)
272fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
273fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return writeStr(k_traceClockPath, enable ? "global" : "local");
274fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
275fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
2766eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Poke all the binder-enabled processes in the system to get them to re-read
2776eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// their system properties.
2786eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool pokeBinderServices()
2796eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
2806eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    sp<IServiceManager> sm = defaultServiceManager();
2816eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    Vector<String16> services = sm->listServices();
2826eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (size_t i = 0; i < services.size(); i++) {
2836eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        sp<IBinder> obj = sm->checkService(services[i]);
2846eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (obj != NULL) {
2856eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            Parcel data;
2866eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
2876eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    NULL, 0) != OK) {
2886eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (false) {
2896eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    // XXX: For some reason this fails on tablets trying to
2906eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    // poke the "phone" service.  It's not clear whether some
2916eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    // are expected to fail.
2926eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    String8 svc(services[i]);
2936eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    fprintf(stderr, "error poking binder service %s\n",
2946eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                        svc.string());
2956eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    return false;
2966eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
2976eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
2986eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
2996eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
3006eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return true;
3016eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
3026eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
3036eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Set the trace tags that userland tracing uses, and poke the running
3046eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// processes to pick up the new value.
3056eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool setTagsProperty(uint64_t tags)
3066eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
3076eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    char buf[64];
3086eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    snprintf(buf, 64, "%#llx", tags);
3096eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    if (property_set(k_traceTagsProperty, buf) < 0) {
3106eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        fprintf(stderr, "error setting trace tags system property\n");
3116eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        return false;
3126eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
3136eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return pokeBinderServices();
3146eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
3156eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
3166eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Disable all /sys/ enable files.
3176eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool disableKernelTraceEvents() {
3186eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    bool ok = true;
3196eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
3206eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const TracingCategory &c = k_categories[i];
3216eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        for (int j = 0; j < MAX_SYS_FILES; j++) {
3226eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            const char* path = c.sysfiles[j].path;
3236eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (path != NULL && fileIsWritable(path)) {
3246eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                ok &= setKernelOptionEnable(path, false);
3256eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
3266eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
3276eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
3286eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return ok;
3296eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
3306eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
331fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Enable tracing in the kernel.
3326eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool startTrace()
333fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
334fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    bool ok = true;
335fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
3366eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Set up the tracing options.
337fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTraceOverwriteEnable(g_traceOverwrite);
338cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
339fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setGlobalClockEnable(true);
340fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
3416eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Set up the tags property.
3426eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    uint64_t tags = 0;
3436eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
3446eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (g_categoryEnables[i]) {
3456eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            const TracingCategory &c = k_categories[i];
3466eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            tags |= c.tags;
3476eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
3486eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
3496eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    ok &= setTagsProperty(tags);
3506eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
3516eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Disable all the sysfs enables.  This is done as a separate loop from
3526eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // the enables to allow the same enable to exist in multiple categories.
3536eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    ok &= disableKernelTraceEvents();
3546eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
3556eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Enable all the sysfs enables that are in an enabled category.
3566eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
3576eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (g_categoryEnables[i]) {
3586eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            const TracingCategory &c = k_categories[i];
3596eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            for (int j = 0; j < MAX_SYS_FILES; j++) {
3606eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                const char* path = c.sysfiles[j].path;
3616eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                bool required = c.sysfiles[j].required == REQ;
3626eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (path != NULL) {
3636eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    if (fileIsWritable(path)) {
3646eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                        ok &= setKernelOptionEnable(path, true);
3656eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    } else if (required) {
3666eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                        fprintf(stderr, "error writing file %s\n", path);
3676eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                        ok = false;
3686eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    }
3696eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
3706eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
3716eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
3724b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis    }
3734b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
374fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Enable tracing.
375fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    ok &= setTracingEnabled(true);
376fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
377fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return ok;
378fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
379fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
380fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Disable tracing in the kernel.
3816eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic void stopTrace()
382fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
383fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Disable tracing.
384fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTracingEnabled(false);
385fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
3866eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Disable all tracing that we're able to.
3876eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    disableKernelTraceEvents();
3886eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
3896eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    // Disable all the trace tags.
3906eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    setTagsProperty(0);
3916eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
392fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Set the options back to their defaults.
393fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setTraceOverwriteEnable(true);
394fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    setGlobalClockEnable(false);
395cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
396cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Note that we can't reset the trace buffer size here because that would
397cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // clear the trace before we've read it.
398fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
399fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
400fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis// Read the current kernel trace and write it to stdout.
401fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisstatic void dumpTrace()
402fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
403fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    int traceFD = open(k_tracePath, O_RDWR);
404fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (traceFD == -1) {
405fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
406fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                strerror(errno), errno);
407fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        return;
408fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
409fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
4107b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    if (g_compress) {
4117b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        z_stream zs;
4127b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        uint8_t *in, *out;
4137b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        int result, flush;
4147b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4157b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        bzero(&zs, sizeof(zs));
4167b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
4177b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
4187b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error initializing zlib: %d\n", result);
4197b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            close(traceFD);
4207b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            return;
4217b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
4227b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4237b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        const size_t bufSize = 64*1024;
4247b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        in = (uint8_t*)malloc(bufSize);
4257b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        out = (uint8_t*)malloc(bufSize);
4267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        flush = Z_NO_FLUSH;
4277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4287b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.next_out = out;
4297b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        zs.avail_out = bufSize;
4307b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4317b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        do {
4327b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4337b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_in == 0) {
4347b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // More input is needed.
4357b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = read(traceFD, in, bufSize);
4367b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if (result < 0) {
4377b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error reading trace: %s (%d)\n",
4387b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
4397b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END;
4407b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
4417b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else if (result == 0) {
4427b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    flush = Z_FINISH;
4437b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                } else {
4447b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.next_in = in;
4457b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_in = result;
4467b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
4477b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
4487b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4497b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if (zs.avail_out == 0) {
4507b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                // Need to write the output.
4517b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                result = write(STDOUT_FILENO, out, bufSize);
4527b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                if ((size_t)result < bufSize) {
4537b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    fprintf(stderr, "error writing deflated trace: %s (%d)\n",
4547b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                            strerror(errno), errno);
4557b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    result = Z_STREAM_END; // skip deflate error message
4567b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    zs.avail_out = bufSize; // skip the final write
4577b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    break;
4587b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                }
4597b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.next_out = out;
4607b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                zs.avail_out = bufSize;
4617b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
4627b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4637b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        } while ((result = deflate(&zs, flush)) == Z_OK);
4647b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4657b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_STREAM_END) {
4667b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error deflating trace: %s\n", zs.msg);
4677b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
4687b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4697b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (zs.avail_out < bufSize) {
4707b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            size_t bytes = bufSize - zs.avail_out;
4717b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            result = write(STDOUT_FILENO, out, bytes);
4727b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            if ((size_t)result < bytes) {
4737b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                fprintf(stderr, "error writing deflated trace: %s (%d)\n",
4747b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                        strerror(errno), errno);
4757b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            }
4767b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
4777b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4787b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        result = deflateEnd(&zs);
4797b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (result != Z_OK) {
4807b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error cleaning up zlib: %d\n", result);
4817b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
4827b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
4837b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(in);
4847b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        free(out);
4857b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis    } else {
4867b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        ssize_t sent = 0;
4877b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        while ((sent = sendfile(STDOUT_FILENO, traceFD, NULL, 64*1024*1024)) > 0);
4887b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        if (sent == -1) {
4897b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
4907b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                    errno);
4917b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis        }
492fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
493fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
494fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    close(traceFD);
495fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
496fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
4976eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic void handleSignal(int signo)
498fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
49931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    if (!g_nohup) {
50031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        g_traceAborted = true;
50131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    }
502fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
503fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5046eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic void registerSigHandler()
5056eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
506fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    struct sigaction sa;
507fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigemptyset(&sa.sa_mask);
508fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_flags = 0;
509fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sa.sa_handler = handleSignal;
510fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGHUP, &sa, NULL);
511fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGINT, &sa, NULL);
512fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGQUIT, &sa, NULL);
513fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    sigaction(SIGTERM, &sa, NULL);
514fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
515fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5166eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic bool setCategoryEnable(const char* name, bool enable)
5176eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
5186eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
5196eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const TracingCategory& c = k_categories[i];
5206eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (strcmp(name, c.name) == 0) {
5216eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            if (isCategorySupported(c)) {
5226eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                g_categoryEnables[i] = enable;
5236eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                return true;
5246eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            } else {
5256eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (isCategorySupportedForRoot(c)) {
5266eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    fprintf(stderr, "error: category \"%s\" requires root "
5276eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                            "privileges.\n", name);
5286eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                } else {
5296eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    fprintf(stderr, "error: category \"%s\" is not supported "
5306eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                            "on this device.\n", name);
5316eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
5326eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                return false;
5336eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
5346eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
5356eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
5366eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    fprintf(stderr, "error: unknown tracing category \"%s\"\n", name);
5376eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    return false;
5386eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
5396eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
5406eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic void listSupportedCategories()
5416eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
5426eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    for (int i = 0; i < NELEM(k_categories); i++) {
5436eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        const TracingCategory& c = k_categories[i];
5446eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        if (isCategorySupported(c)) {
5456eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            printf("  %10s - %s\n", c.name, c.longname);
5466eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        }
5476eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    }
5486eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
5496eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
5506eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis// Print the command usage help to stderr.
5516eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennisstatic void showHelp(const char *cmd)
5526eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis{
5536eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    fprintf(stderr, "usage: %s [options] [categories...]\n", cmd);
5546eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    fprintf(stderr, "options include:\n"
5556eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -b N            use a trace buffer size of N KB\n"
5566eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -c              trace into a circular buffer\n"
5576eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -n              ignore signals\n"
5586eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -s N            sleep for N seconds before tracing [default 0]\n"
5596eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -t N            trace for N seconds [defualt 5]\n"
5606eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  -z              compress the trace dump\n"
5616eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  --async_start   start circular trace and return immediatly\n"
5626eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  --async_dump    dump the current contents of circular trace buffer\n"
5636eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "  --async_stop    stop tracing and dump the current contents of circular\n"
5646eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    "                    trace buffer\n"
5656eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            );
5666eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis}
5676eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis
568fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennisint main(int argc, char **argv)
569fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis{
5704edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool async = false;
5714edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool traceStart = true;
5724edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool traceStop = true;
5734edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    bool traceDump = true;
5744b23eefd72501b358c61fb1a7096a2a94e5ea351Jamie Gennis
575fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
576fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        showHelp(argv[0]);
577fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        exit(0);
578fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
579fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
580fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    for (;;) {
581fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        int ret;
5824edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        int option_index = 0;
5834edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        static struct option long_options[] = {
5844edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {"async_start",     no_argument, 0,  0 },
5854edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {"async_stop",      no_argument, 0,  0 },
5864edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            {"async_dump",      no_argument, 0,  0 },
5876eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            {"list_categories", no_argument, 0,  0 },
5886eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            {           0,                0, 0,  0 }
5894edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        };
590fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
5916eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        ret = getopt_long(argc, argv, "b:cns:t:z",
5924edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                          long_options, &option_index);
593fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
594fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (ret < 0) {
5956eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            for (int i = optind; i < argc; i++) {
5966eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                if (!setCategoryEnable(argv[i], true)) {
5976eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    fprintf(stderr, "error enabling tracing category \"%s\"\n", argv[i]);
5986eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    exit(1);
5996eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                }
6006eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis            }
601fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
602fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
603fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
604fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        switch(ret) {
605cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            case 'b':
606cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                g_traceBufferSizeKB = atoi(optarg);
607cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis            break;
608cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
609fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 'c':
610fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceOverwrite = true;
611fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
612fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
61331be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            case 'n':
61431be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                g_nohup = true;
61531be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                break;
61631be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
617fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 's':
61831be80f02cddda55e75614884038fa4645b694cdGlenn Kasten                g_initialSleepSecs = atoi(optarg);
61931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten            break;
62031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
621fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            case 't':
622fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                g_traceDurationSeconds = atoi(optarg);
623fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
624fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
6257b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            case 'z':
6267b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis                g_compress = true;
6277b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis            break;
6287b5170b249c1d312cfe3b5658b6c140b2a48226fJamie Gennis
6294edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling            case 0:
6304edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                if (!strcmp(long_options[option_index].name, "async_start")) {
6314edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    async = true;
6324edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStop = false;
6334edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceDump = false;
6344edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    g_traceOverwrite = true;
6354edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                } else if (!strcmp(long_options[option_index].name, "async_stop")) {
6364edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    async = true;
6374edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStop = false;
6384edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                } else if (!strcmp(long_options[option_index].name, "async_dump")) {
6394edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    async = true;
6404edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStart = false;
6414edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                    traceStop = false;
6426eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                } else if (!strcmp(long_options[option_index].name, "list_categories")) {
6436eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    listSupportedCategories();
6446eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis                    exit(0);
6454edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                }
6464edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling                break;
6474edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling
648fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            default:
649cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis                fprintf(stderr, "\n");
650fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                showHelp(argv[0]);
651fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                exit(-1);
652fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            break;
653fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
654fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
655fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
656fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    registerSigHandler();
657fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
65831be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    if (g_initialSleepSecs > 0) {
65931be80f02cddda55e75614884038fa4645b694cdGlenn Kasten        sleep(g_initialSleepSecs);
66031be80f02cddda55e75614884038fa4645b694cdGlenn Kasten    }
66131be80f02cddda55e75614884038fa4645b694cdGlenn Kasten
6626eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis    bool ok = startTrace();
663fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
6644edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (ok && traceStart) {
665fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        printf("capturing trace...");
666fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fflush(stdout);
667fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
668fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // We clear the trace after starting it because tracing gets enabled for
669fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // each CPU individually in the kernel. Having the beginning of the trace
670fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // contain entries from only one CPU can cause "begin" entries without a
671fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // matching "end" entry to show up if a task gets migrated from one CPU to
672fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        // another.
673fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        ok = clearTrace();
674fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
6754edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        if (ok && !async) {
676fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            // Sleep to allow the trace to be captured.
677fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            struct timespec timeLeft;
678fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_sec = g_traceDurationSeconds;
679fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            timeLeft.tv_nsec = 0;
680fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            do {
681fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                if (g_traceAborted) {
682fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                    break;
683fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis                }
684fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
685fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
686fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
687fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
688fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    // Stop the trace and restore the default settings.
6894edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (traceStop)
6906eea6fb259a6d0b1c585d3267b8df7ca29a1206dJamie Gennis        stopTrace();
691fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
6924edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (ok && traceDump) {
693fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        if (!g_traceAborted) {
694fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf(" done\nTRACE:\n");
695fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
696fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            dumpTrace();
697fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        } else {
698fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            printf("\ntrace aborted.\n");
699fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis            fflush(stdout);
700fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        }
701fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        clearTrace();
7024edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    } else if (!ok) {
703fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis        fprintf(stderr, "unable to start tracing\n");
704fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    }
705fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis
706cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis    // Reset the trace buffer size to 1.
7074edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling    if (traceStop)
7084edbd078cddcc1cbe59156a0e7ece01de75156e0Erik Gilling        setTraceBufferSizeKB(1);
709cc24c8e6b48c2eb204bf3d7f974dbff6dc0cc862Jamie Gennis
710fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis    return g_traceAborted ? 1 : 0;
711fb31ba69282e34df62005ec63afda2b8ec69533eJamie Gennis}
712