Confirmed users
507
edits
No edit summary |
|||
| Line 619: | Line 619: | ||
= systemtap = | = systemtap = | ||
== Compiling systemtap == | |||
Think of the children, get the [http://www.jnchen.com/_media/projects/mozilla/moz-systemtap-1.5.tar.bz2 prebuilt version]. Extract it to your host machine, and to /data on your device. | |||
Basically running systemtap consists of the host portion and the target portion. For the host portion you use a standard systemtap installation to cross compile your script into a kernel module. For the target portion you transfer the kernel module to your device and run it on the device. | |||
The host portion you can get through apt-get. The target portion you have to compile (use the [http://www.codesourcery.com/sgpp/lite/arm/portal/subscription?@template=lite CodeSourcery ARM GNU/Linux toolchain]): | |||
LDFLAGS=-static \ | |||
ac_cv_file__usr_include_avahi_common=no \ | |||
ac_cv_file__usr_include_avahi_client=no \ | |||
ac_cv_file__usr_include_nspr=no \ | |||
ac_cv_file__usr_include_nspr4=no \ | |||
ac_cv_file__usr_include_nss=no \ | |||
ac_cv_file__usr_include_nss3=no \ | |||
./configure --prefix=/data/systemtap --host=arm-none-linux-gnueabi \ | |||
--disable-translator --disable-nls | |||
make install | |||
Note that prefix has to be /data/systemtap (or another path that matches Android file system) so you need to make a /data directory on your host machine before you run make install. | |||
You might need libelf. Get the latest elfutils release, then compile: | |||
./configure --host=arm-none-linux-gnueabi --disable-nls \ | |||
--prefix=/PATH/TO/TOOLCHAIN/arm-none-linux-gnueabi/libc/usr | |||
cd libelf | |||
make install | |||
Where /PATH/TO/TOOLCHAIN is the path to your CodeSourcery toolchain. | |||
== Using systemtap == | |||
Before you start, you need the source of your device's kernel. See the oprofile section for one example way to get the kernel source. | |||
To compile your script on the host, make sure you have the NDK toolchain (r5 or above), then run | |||
stap -gv -a arm -B CROSS_COMPILE=arm-linux-androideabi- \ | |||
-r /PATH/TO/KERNEL -R /PATH/TO/SYSTEMTAP/RUNTIME \ | |||
-m NAME -B CFLAGS_MODULE="-DMODULE -fno-pic" NAME.stp | |||
where NAME is the name of your script, /PATH/TO/KERNEL is the path to your kernel source, and /PATH/TO/SYSTEMTAP/RUNTIME is the path to your target systemtap runtime (for example if you're using the prebuilt version above, /PATH/TO/SYSTEMTAP/RUNTIME = systemtap/share/systemtap/runtime) | |||
adb push your kernel module to your device, then run | |||
staprun -x PID NAME.ko | |||
where PID is the pid of fennec process | |||
== Sample systemtap scripts == | |||
=== glandium's I/O tracking script === | |||
global targetpid; | |||
global file_path; | |||
probe begin { | |||
targetpid = target(); | |||
} | |||
probe kernel.function("__do_page_cache_readahead") { | |||
if (targetpid == pid()) | |||
file_path[tid()] = d_path(&$filp->f_path); | |||
} | |||
probe kernel.function("do_mpage_readpage") { | |||
if (targetpid == pid() && (tid() in file_path)) { | |||
now = gettimeofday_us(); | |||
printf("%d %s %d\n", now, file_path[tid()], $page->index*4096); | |||
} | |||
} | |||
probe kernel.function("__do_page_cache_readahead").return { | |||
if (targetpid == pid()) | |||
delete file_path[tid()]; | |||
} | |||
=== jchen's I/O tracking script === | |||
Note that this script accesses the hardware timer directly to overcome limitations in the systemtap gettimeofday() resolution (basically in systemtap, gettimeofday() is limited to jiffy resolution). | |||
This also means to run it on a processor other than a MSM7x30, get_rawtime() will need to change. | |||
%{ | |||
#include <arch/arm/include/asm/io.h> | |||
#define MSM_CSR_BASE ((void*)0xF8001000) | |||
#define MSM_TMR_BASE MSM_CSR_BASE | |||
#define MSM_GPT_BASE (MSM_TMR_BASE + 0x04) | |||
#define MSM_DGT_BASE (MSM_TMR_BASE + 0x24) | |||
#define TIMER_COUNT_VAL 0x0004 | |||
%} | |||
function get_rawtime:long () %{ /* pure */ /* unprivileged */ | |||
cycles_t c = readl(MSM_DGT_BASE + TIMER_COUNT_VAL); | |||
THIS->__retvalue = ((int64_t) (int32_t) c) - global.s_origin_time; | |||
%} | |||
global parentid, childid; | |||
global start_time, total_time; | |||
global origin_time; | |||
global creation_time; | |||
probe begin { | |||
parentid = 0; | |||
childid = 0; | |||
origin_time = get_rawtime() | |||
} | |||
function is_parent:long () { | |||
if (pid() == parentid) | |||
return parentid; | |||
if (0 == parentid && isinstr(execname(), "fennec")) { | |||
parentid = pid(); | |||
return parentid; | |||
} | |||
return 0; | |||
} | |||
function is_child:long () { | |||
if (pid() == childid) | |||
return childid; | |||
if (0 == childid && isinstr(execname(), "plugin")) { | |||
childid = pid(); | |||
return childid; | |||
} | |||
return 0; | |||
} | |||
probe syscall.fork.return { | |||
if (is_parent() || is_child()) { | |||
if ($return != 0) { | |||
thdid = is_parent() ? $return : -$return; | |||
creation_time[thdid] = get_rawtime(); | |||
total_time[thdid, "", creation_time[thdid] / 8192] = -1; | |||
} | |||
} | |||
} | |||
probe syscall.execve.return { | |||
if (is_parent() || is_child()) { | |||
thdid = is_parent() ? tid() : -tid(); | |||
creation_time[thdid] = get_rawtime(); | |||
total_time[thdid, "", creation_time[thdid] / 8192] = -1; | |||
} | |||
} | |||
probe syscall.exit { | |||
if (is_parent() || is_child()) { | |||
thdid = is_parent() ? tid() : -tid(); | |||
total_time[thdid, "", creation_time[thdid] / 8192] = | |||
get_rawtime() - creation_time[thdid]; | |||
} | |||
} | |||
probe vfs.read { | |||
if (bytes_to_read > 0 && (is_parent() || is_child())) { | |||
thdid = is_parent() ? tid() : -tid(); | |||
start_time[thdid] = get_rawtime(); | |||
} | |||
} | |||
probe vfs.read.return { | |||
if (bytes_to_read > 0 && (is_parent() || is_child())) { | |||
thdid = is_parent() ? tid() : -tid(); | |||
fn = "rd:" . __file_filename(file); | |||
st = start_time[thdid]; | |||
total_time[thdid, fn, st / 8192] += get_rawtime() - st; | |||
} | |||
} | |||
probe kernel.function("filemap_fault") { | |||
if (is_parent() || is_child()) { | |||
thdid = is_parent() ? tid() : -tid(); | |||
start_time[thdid] = get_rawtime(); | |||
} | |||
} | |||
probe kernel.function("filemap_fault").return { | |||
if (is_parent() || is_child()) { | |||
thdid = is_parent() ? tid() : -tid(); | |||
fn = "mm:" . __file_filename($vma->vm_file); | |||
st = start_time[thdid]; | |||
total_time[thdid, fn, st / 8192] += get_rawtime() - st; | |||
} | |||
} | |||
probe end { | |||
foreach ([t, fn, st] in total_time) { | |||
printf("%d, %s, %d, %d\n", t, fn, st, total_time[t, fn, st]); | |||
} | |||
} | |||