Merge "atrace: add support for tracing kernel functions" into jb-mr2-dev

This commit is contained in:
Jamie Gennis 2013-03-18 21:54:44 +00:00 committed by Android (Google) Code Review
commit 79fb99d0de

View File

@ -117,6 +117,7 @@ static int g_traceBufferSizeKB = 2048;
static bool g_compress = false;
static bool g_nohup = false;
static int g_initialSleepSecs = 0;
static const char* g_kernelTraceFuncs = NULL;
/* Global state */
static bool g_traceAborted = false;
@ -132,6 +133,30 @@ static const char* k_traceBufferSizePath =
static const char* k_tracingOverwriteEnablePath =
"/sys/kernel/debug/tracing/options/overwrite";
static const char* k_currentTracerPath =
"/sys/kernel/debug/tracing/current_tracer";
static const char* k_printTgidPath =
"/sys/kernel/debug/tracing/options/print-tgid";
static const char* k_funcgraphAbsTimePath =
"/sys/kernel/debug/tracing/options/funcgraph-abstime";
static const char* k_funcgraphCpuPath =
"/sys/kernel/debug/tracing/options/funcgraph-cpu";
static const char* k_funcgraphProcPath =
"/sys/kernel/debug/tracing/options/funcgraph-proc";
static const char* k_funcgraphFlatPath =
"/sys/kernel/debug/tracing/options/funcgraph-flat";
static const char* k_funcgraphDurationPath =
"/sys/kernel/debug/tracing/options/funcgraph-duration";
static const char* k_ftraceFilterPath =
"/sys/kernel/debug/tracing/set_ftrace_filter";
static const char* k_tracingOnPath =
"/sys/kernel/debug/tracing/tracing_on";
@ -148,10 +173,22 @@ static bool fileIsWritable(const char* filename) {
return access(filename, W_OK) != -1;
}
// Write a string to a file, returning true if the write was successful.
static bool writeStr(const char* filename, const char* str)
// Truncate a file.
static bool truncateFile(const char* path)
{
int fd = open(filename, O_WRONLY);
int err = truncate(path, 0);
if (err != 0) {
fprintf(stderr, "error truncating %s: %s (%d)\n", path,
strerror(errno), errno);
return false;
}
return true;
}
static bool _writeStr(const char* filename, const char* str, int flags)
{
int fd = open(filename, flags);
if (fd == -1) {
fprintf(stderr, "error opening %s: %s (%d)\n", filename,
strerror(errno), errno);
@ -171,6 +208,18 @@ static bool writeStr(const char* filename, const char* str)
return ok;
}
// Write a string to a file, returning true if the write was successful.
static bool writeStr(const char* filename, const char* str)
{
return _writeStr(filename, str, O_WRONLY);
}
// Append a string to a file, returning true if the write was successful.
static bool appendStr(const char* filename, const char* str)
{
return _writeStr(filename, str, O_APPEND|O_WRONLY);
}
// Enable or disable a kernel option by writing a "1" or a "0" into a /sys
// file.
static bool setKernelOptionEnable(const char* filename, bool enable)
@ -244,16 +293,7 @@ static bool setTracingEnabled(bool enable)
// Clear the contents of the kernel trace.
static bool clearTrace()
{
int traceFD = creat(k_tracePath, 0);
if (traceFD == -1) {
fprintf(stderr, "error truncating %s: %s (%d)\n", k_tracePath,
strerror(errno), errno);
return false;
}
close(traceFD);
return true;
return truncateFile(k_tracePath);
}
// Set the size of the kernel's trace buffer in kilobytes.
@ -275,6 +315,14 @@ static bool setGlobalClockEnable(bool enable)
return writeStr(k_traceClockPath, enable ? "global" : "local");
}
static bool setPrintTgidEnableIfPresent(bool enable)
{
if (fileExists(k_printTgidPath)) {
return setKernelOptionEnable(k_printTgidPath, enable);
}
return true;
}
// Poke all the binder-enabled processes in the system to get them to re-read
// their system properties.
static bool pokeBinderServices()
@ -330,8 +378,90 @@ static bool disableKernelTraceEvents() {
return ok;
}
// Enable tracing in the kernel.
static bool startTrace()
// Verify that the comma separated list of functions are being traced by the
// kernel.
static bool verifyKernelTraceFuncs(const char* funcs)
{
int fd = open(k_ftraceFilterPath, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
strerror(errno), errno);
return false;
}
char buf[4097];
ssize_t n = read(fd, buf, 4096);
close(fd);
if (n == -1) {
fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath,
strerror(errno), errno);
return false;
}
buf[n] = '\0';
String8 funcList = String8::format("\n%s", buf);
// Make sure that every function listed in funcs is in the list we just
// read from the kernel.
bool ok = true;
char* myFuncs = strdup(funcs);
char* func = strtok(myFuncs, ",");
while (func) {
String8 fancyFunc = String8::format("\n%s\n", func);
bool found = funcList.find(fancyFunc.string(), 0) >= 0;
if (!found || func[0] == '\0') {
fprintf(stderr, "error: \"%s\" is not a valid kernel function "
"to trace.\n", func);
ok = false;
}
func = strtok(NULL, ",");
}
free(myFuncs);
return ok;
}
// Set the comma separated list of functions that the kernel is to trace.
static bool setKernelTraceFuncs(const char* funcs)
{
bool ok = true;
if (funcs == NULL || funcs[0] == '\0') {
// Disable kernel function tracing.
ok &= writeStr(k_currentTracerPath, "nop");
if (fileExists(k_ftraceFilterPath)) {
ok &= truncateFile(k_ftraceFilterPath);
}
} else {
// Enable kernel function tracing.
ok &= writeStr(k_currentTracerPath, "function_graph");
ok &= setKernelOptionEnable(k_funcgraphAbsTimePath, true);
ok &= setKernelOptionEnable(k_funcgraphCpuPath, true);
ok &= setKernelOptionEnable(k_funcgraphProcPath, true);
ok &= setKernelOptionEnable(k_funcgraphFlatPath, true);
// Set the requested filter functions.
ok &= truncateFile(k_ftraceFilterPath);
char* myFuncs = strdup(funcs);
char* func = strtok(myFuncs, ",");
while (func) {
ok &= appendStr(k_ftraceFilterPath, func);
func = strtok(NULL, ",");
}
free(myFuncs);
// Verify that the set functions are being traced.
if (ok) {
ok &= verifyKernelTraceFuncs(funcs);
}
}
return ok;
}
// Set all the kernel tracing settings to the desired state for this trace
// capture.
static bool setUpTrace()
{
bool ok = true;
@ -339,6 +469,8 @@ static bool startTrace()
ok &= setTraceOverwriteEnable(g_traceOverwrite);
ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
ok &= setGlobalClockEnable(true);
ok &= setPrintTgidEnableIfPresent(true);
ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
// Set up the tags property.
uint64_t tags = 0;
@ -373,18 +505,12 @@ static bool startTrace()
}
}
// Enable tracing.
ok &= setTracingEnabled(true);
return ok;
}
// Disable tracing in the kernel.
static void stopTrace()
// Reset all the kernel tracing settings to their default state.
static void cleanUpTrace()
{
// Disable tracing.
setTracingEnabled(false);
// Disable all tracing that we're able to.
disableKernelTraceEvents();
@ -393,10 +519,23 @@ static void stopTrace()
// Set the options back to their defaults.
setTraceOverwriteEnable(true);
setTraceBufferSizeKB(1);
setGlobalClockEnable(false);
setPrintTgidEnableIfPresent(false);
setKernelTraceFuncs(NULL);
}
// Note that we can't reset the trace buffer size here because that would
// clear the trace before we've read it.
// Enable tracing in the kernel.
static bool startTrace()
{
return setTracingEnabled(true);
}
// Disable tracing in the kernel.
static void stopTrace()
{
setTracingEnabled(false);
}
// Read the current kernel trace and write it to stdout.
@ -556,6 +695,7 @@ static void showHelp(const char *cmd)
fprintf(stderr, "options include:\n"
" -b N use a trace buffer size of N KB\n"
" -c trace into a circular buffer\n"
" -k fname,... trace the listed kernel functions\n"
" -n ignore signals\n"
" -s N sleep for N seconds before tracing [default 0]\n"
" -t N trace for N seconds [defualt 5]\n"
@ -592,7 +732,7 @@ int main(int argc, char **argv)
{ 0, 0, 0, 0 }
};
ret = getopt_long(argc, argv, "b:cns:t:z",
ret = getopt_long(argc, argv, "b:ck:ns:t:z",
long_options, &option_index);
if (ret < 0) {
@ -614,6 +754,10 @@ int main(int argc, char **argv)
g_traceOverwrite = true;
break;
case 'k':
g_kernelTraceFuncs = optarg;
break;
case 'n':
g_nohup = true;
break;
@ -663,7 +807,9 @@ int main(int argc, char **argv)
sleep(g_initialSleepSecs);
}
bool ok = startTrace();
bool ok = true;
ok &= setUpTrace();
ok &= startTrace();
if (ok && traceStart) {
printf("capturing trace...");
@ -709,7 +855,7 @@ int main(int argc, char **argv)
// Reset the trace buffer size to 1.
if (traceStop)
setTraceBufferSizeKB(1);
cleanUpTrace();
return g_traceAborted ? 1 : 0;
}