You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
521 lines
15 KiB
521 lines
15 KiB
#!/bin/sh -u |
|
|
|
parseoptions() { |
|
trace_reads=false |
|
trace_writes=false |
|
trace_writepages=false |
|
pid_view=false |
|
|
|
while [ $# -ge 1 ] |
|
do |
|
case $1 in |
|
-r) |
|
trace_reads=true |
|
;; |
|
-w) |
|
trace_writes=true |
|
;; |
|
-p) |
|
trace_writepages=true |
|
;; |
|
-v) |
|
pid_view=true |
|
;; |
|
*) |
|
usage |
|
;; |
|
esac |
|
shift |
|
done |
|
} |
|
|
|
usage() { |
|
echo "Usage: $0 [-r|-w|-p|-v]" |
|
exit 1 |
|
} |
|
|
|
getmodel() { |
|
model=`adb shell getprop ro.product.name` |
|
# Releases are inconsistent with various trailing characters, remove them all |
|
model=`echo $model | sed 's/[ \t\r\n]*$//' ` |
|
echo Found $model Device |
|
|
|
case $model in |
|
aosp_gobo | gobo) |
|
get_go_devnames |
|
;; |
|
marlin | sailfish) |
|
get_marlin_sailfish_devnames |
|
;; |
|
angler) |
|
get_angler_devnames |
|
;; |
|
bullhead) |
|
get_bullhead_devnames |
|
;; |
|
volantis | volantisg) |
|
get_volantis_devnames |
|
;; |
|
*) |
|
echo Unknown Device $model |
|
exit 1 |
|
;; |
|
esac |
|
} |
|
|
|
get_go_devnames () { |
|
# Hardcoding all of the mmcblk0 device for now |
|
block_device=mmcblk0 |
|
bdev_set=true |
|
} |
|
|
|
get_volantis_devnames() { |
|
bdev_set=true |
|
block_device=mmcblk0 |
|
} |
|
|
|
get_bullhead_devnames() { |
|
bdev_set=true |
|
block_device=mmcblk0 |
|
} |
|
|
|
get_marlin_sailfish_devnames() { |
|
bdev_set=true |
|
block_device=sda |
|
} |
|
|
|
get_angler_devnames () { |
|
# Get the underlying bdev from the "by-name" mapping |
|
block_device=`adb shell 'find /dev/block/platform -name by-name | xargs ls -l' | grep system | awk '{ print $10 }' ` |
|
# extract the last component of the absolute device pathname we got above |
|
block_device=`echo $block_device | awk 'BEGIN { FS ="/" } ; { print $4 }' | sed 's/p.*//g' ` |
|
bdev_set=true |
|
} |
|
|
|
disk_stats_before() { |
|
if [ $bdev_set == true ]; then |
|
DISKSTATS=`adb shell 'cat /proc/diskstats' | fgrep -w $block_device ` |
|
# Get BEFORE read stats for bdev |
|
BEFORE_RD_IOS=`echo $DISKSTATS | awk '{ print $4 }' ` |
|
BEFORE_RD_SECTORS=`echo $DISKSTATS | awk '{ print $6 }' ` |
|
# Get BEFORE write stats for bdev |
|
BEFORE_WR_IOS=`echo $DISKSTATS | awk '{ print $8 }' ` |
|
BEFORE_WR_SECTORS=`echo $DISKSTATS | awk '{ print $10 }' ` |
|
fi |
|
if [ $f2fs_fs == 1 ] ; then |
|
adb shell 'mount -o remount,background_gc=off /data' |
|
F2FS_GC_SEGMENTS_BEFORE=`adb shell 'cat /sys/kernel/debug/f2fs/status' | grep segments | egrep 'data|node' | awk '{ segments += $5 } END { print segments }' ` |
|
fi |
|
} |
|
|
|
disk_stats_after() { |
|
if [ $bdev_set == true ]; then |
|
DISKSTATS=`adb shell 'cat /proc/diskstats' | fgrep -w $block_device ` |
|
# Get AFTER read stats for bdev |
|
AFTER_RD_IOS=`echo $DISKSTATS | awk '{ print $4 }' ` |
|
AFTER_RD_SECTORS=`echo $DISKSTATS | awk '{ print $6 }' ` |
|
# Get BEFORE write stats for bdev |
|
AFTER_WR_IOS=`echo $DISKSTATS | awk '{ print $8 }' ` |
|
AFTER_WR_SECTORS=`echo $DISKSTATS | awk '{ print $10 }' ` |
|
fi |
|
if [ $f2fs_fs == 1 ] ; then |
|
F2FS_GC_SEGMENTS_AFTER=`adb shell 'cat /sys/kernel/debug/f2fs/status' | grep segments | egrep 'data|node' | awk '{ segments += $5 } END { print segments }' ` |
|
adb shell 'mount -o remount,background_gc=on /data' |
|
fi |
|
} |
|
|
|
disk_stats_delta_rd() { |
|
file_data_KB=$1 |
|
if [ $bdev_set == true ]; then |
|
# Sectors to KB |
|
READ_KB=`expr $AFTER_RD_SECTORS - $BEFORE_RD_SECTORS` |
|
READ_KB=`expr $READ_KB / 2` |
|
echo "Total (ALL) Read KB $block_device = "$READ_KB |
|
BLOCK_MINUS_FILE=`expr $READ_KB - $file_data_KB` |
|
echo "READ DELTA: Total Blockdev Reads KB - Total File Data Reads KB = "$BLOCK_MINUS_FILE KB |
|
echo "Total (ALL) Read IOs $block_device = "`expr $AFTER_RD_IOS - $BEFORE_RD_IOS` |
|
fi |
|
} |
|
|
|
disk_stats_delta_wr() { |
|
file_data_KB=$1 |
|
if [ $bdev_set == true ]; then |
|
# Sectors to KB |
|
WRITE_KB=`expr $AFTER_WR_SECTORS - $BEFORE_WR_SECTORS` |
|
WRITE_KB=`expr $WRITE_KB / 2` |
|
BLOCK_MINUS_FILE=`expr $WRITE_KB - $file_data_KB` |
|
echo "WRITE DELTA: Total Blockdev Writes KB - Total File Data Writes KB = "$BLOCK_MINUS_FILE KB |
|
echo "Total (ALL) Write IOs $block_device = "`expr $AFTER_WR_IOS - $BEFORE_WR_IOS` |
|
fi |
|
if [ $f2fs_fs == 1 ] ; then |
|
F2FS_GC_SEGMENTS_DELTA=`expr $F2FS_GC_SEGMENTS_AFTER - $F2FS_GC_SEGMENTS_BEFORE` |
|
F2FS_GC_KB_DELTA=`expr $F2FS_GC_SEGMENTS_DELTA \\* 2048` |
|
fi |
|
} |
|
|
|
# For good measure clean up traces and reenable traces |
|
clean_up_tracepoints() { |
|
# This is a good point to check if the Android FS tracepoints are enabled in the |
|
# kernel or not |
|
tracepoint_exists=`adb shell 'if [ -d /sys/kernel/debug/tracing/events/android_fs ]; then echo 0; else echo 1; fi' ` |
|
if [ $tracepoint_exists == 1 ]; then |
|
echo "Android FS tracepoints not enabled in kernel. Exiting..." |
|
exit 1 |
|
fi |
|
adb shell 'echo 0 > /sys/kernel/debug/tracing/tracing_on' |
|
adb shell 'echo 0 > /sys/kernel/debug/tracing/trace' |
|
if [ $trace_reads == true ]; then |
|
adb shell 'echo 1 > /sys/kernel/debug/tracing/events/android_fs/android_fs_dataread_start/enable' |
|
fi |
|
if [ $trace_writes == true ]; then |
|
adb shell 'echo 1 > /sys/kernel/debug/tracing/events/android_fs/android_fs_datawrite_start/enable' |
|
fi |
|
if [ $f2fs_fs == 1 ] ; then |
|
if [ $trace_writepages == true ]; then |
|
adb shell 'echo 1 > /sys/kernel/debug/tracing/events/android_fs/android_fs_writepages/enable' |
|
fi |
|
fi |
|
adb shell 'echo 1 > /sys/kernel/debug/tracing/tracing_on' |
|
} |
|
|
|
# stream trace out of trace_pipe |
|
# Start this in the background ('&') |
|
streamtrace_start() { |
|
adb shell cat /sys/kernel/debug/tracing/trace_pipe > trace_saved |
|
} |
|
|
|
# When signal is received, the trace_pipe reader will get killed |
|
# Call this (just to make sure anyway) |
|
streamtrace_end() { |
|
ps_line=`ps -ef | grep trace_pipe | grep adb ` |
|
if [ $? == 0 ]; then |
|
echo Killing `echo $ps_line | awk '{s = ""; for (i=8; i <= NF ; i++) s = s $i " "; print s}' ` |
|
kill `echo $ps_line | awk '{print $2}' ` |
|
fi |
|
} |
|
|
|
copyout_trace() { |
|
streamtrace_end |
|
if [ $trace_reads == true ]; then |
|
adb shell 'echo 0 > /sys/kernel/debug/tracing/events/android_fs/android_fs_dataread_start/enable' |
|
fi |
|
if [ $trace_writes == true ]; then |
|
adb shell 'echo 0 > /sys/kernel/debug/tracing/events/android_fs/android_fs_datawrite_start/enable' |
|
fi |
|
if [ $f2fs_fs == 1 ] ; then |
|
if [ $trace_writepages == true ]; then |
|
adb shell 'echo 0 > /sys/kernel/debug/tracing/events/android_fs/android_fs_writepages/enable' |
|
fi |
|
fi |
|
adb shell 'echo 0 > /sys/kernel/debug/tracing/tracing_on' |
|
} |
|
|
|
prep_tracefile_common() { |
|
cp trace_saved $infile |
|
# Strip away all the extraneous stuff first |
|
fgrep $1 $infile | sed 's/^.* \[.*\] //' | sed s/://g | sed s/,//g > foo |
|
mv foo $infile |
|
} |
|
|
|
prep_tracefile_rd() { |
|
prep_tracefile_common android_fs_dataread |
|
# Strip away unnecessary stuff so we can compute latencies easily |
|
fgrep android_fs_dataread_start $infile > foo0 |
|
# Throw away everything upto and including android_fs_dataread: |
|
cat foo0 | sed -n -e 's/^.*android_fs_dataread_start //p' > foo1 |
|
mv foo1 $infile |
|
# At this stage, $infile should the following format : |
|
# entry_name <filename> offset <offset> bytes <bytes> cmdline <cmdline> pid <pid> i_size <i_size> ino <ino> |
|
rm foo0 |
|
} |
|
|
|
prep_tracefile_writepages() { |
|
prep_tracefile_common android_fs_writepages |
|
# Throw away everything up to and including android_fs_writepages_start: |
|
cat $infile | sed -n -e 's/^.*android_fs_writepages //p' > foo1 |
|
mv foo1 $infile |
|
# At this stage, $infile should the following format : |
|
# entry_name <filename> bytes <bytes> ino <ino> |
|
} |
|
|
|
# Latencies not supported for Writes. 'Write End' is just when the data has been |
|
# written back to page cache. |
|
prep_tracefile_wr() { |
|
prep_tracefile_common android_fs_datawrite |
|
fgrep android_fs_datawrite_start $infile > foo0 |
|
# Throw away everything upto and including android_fs_datawrite: |
|
cat foo0 | sed -n -e 's/^.*android_fs_datawrite_start //p' > foo1 |
|
mv foo1 $infile |
|
# At this stage, $infile should the following format : |
|
# entry_name <filename> offset <offset> bytes <bytes> cmdline <cmdline> pid <pid> i_size <i_size> ino <ino> |
|
rm foo0 |
|
} |
|
|
|
get_unique_files_rw() { |
|
# Sort first by filename, then by pid |
|
cat $infile | sed s/,//g | sort -d -k2,2 -k8,8 > foo1 |
|
mv foo1 $infile |
|
# $infile now contains lines sorted by <filename, pid> |
|
# How many unique files are there ? |
|
cat $infile | awk '{ print $2 }' > foo1 |
|
cat foo1 | uniq > uniq_files |
|
rm foo1 |
|
} |
|
|
|
get_unique_files_writepages() { |
|
cat $infile | sed s/,//g | sort -d -k2,2 > foo1 |
|
# $infile now contains lines sorted by <filename> |
|
mv foo1 $infile |
|
# How many unique files are there ? |
|
cat $infile | awk '{ print $2 }' > foo1 |
|
cat foo1 | uniq > uniq_files |
|
rm foo1 |
|
} |
|
|
|
get_unique_pids_byfile() { |
|
# How many unique pids are there reading this file ? |
|
cat $1 | awk '{ print $8 }' > foo1 |
|
cat foo1 | uniq > uniq_pids_byfile |
|
rm foo1 |
|
} |
|
|
|
get_unique_pids() { |
|
# Sort first by pid, then by filename |
|
cat $infile | sed s/,//g | sort -d -k8,8 -k2,2 > foo1 |
|
mv foo1 $infile |
|
# $infile now contains lines sorted by <pid, filename> |
|
# How many unique pids are there ? |
|
cat $infile | awk '{ print $8 }' > foo1 |
|
cat foo1 | uniq > uniq_pids |
|
rm foo1 |
|
} |
|
|
|
get_unique_files_bypid() { |
|
# How many unique files are there read by this pid ? |
|
cat $1 | awk '{ print $2 }' > foo1 |
|
cat foo1 | uniq > uniq_files_bypid |
|
rm foo1 |
|
} |
|
|
|
catch_sigint() |
|
{ |
|
echo "signal INT received, killing streaming trace capture" |
|
streamtrace_end |
|
} |
|
|
|
|
|
prep_to_do_something() { |
|
# adb shell "am force-stop com.android.chrome" |
|
# adb shell "am force-stop com.google.android.gm" |
|
adb shell 'echo 3 > /proc/sys/vm/drop_caches' |
|
sleep 1 |
|
} |
|
|
|
do_something() { |
|
# Arrange things so that the first SIGINT will kill the |
|
# child process (sleep), but will return to the parent. |
|
trap 'catch_sigint' INT |
|
echo "OK to kill sleep when test is done" |
|
sleep 30d |
|
# adb shell "am start -W -n com.android.chrome/com.google.android.apps.chrome.Main" |
|
# adb shell "am start -W -n com.google.android.gm/.ConversationListActivityGmail" |
|
} |
|
|
|
# Get the aggregate list of files read/written. For each file, break up the IOs by pid |
|
process_files_rw() { |
|
read_write=$1 |
|
get_unique_files_rw |
|
# Loop over each file that was involved in IO |
|
# Find all the pids doing IO on that file |
|
# Aggregate the IO done by each pid on that file and dump it out |
|
grand_total_KB=0 |
|
cp $infile tempfile |
|
for i in `cat uniq_files` |
|
do |
|
# Get just the tracepoints for this file |
|
fgrep -w "$i" tempfile > subtrace |
|
if [ -s subtrace ]; then |
|
echo "File: $i" |
|
total_file_KB=0 |
|
# Remove the tracepoints we just picked up |
|
fgrep -v -w "$i" tempfile > foo |
|
mv foo tempfile |
|
# Get all the pids doing IO on this file |
|
get_unique_pids_byfile subtrace |
|
for j in `cat uniq_pids_byfile` |
|
do |
|
echo -n " $j $read_write: " |
|
pid_KB=`fgrep -w "$j" subtrace | awk '{ bytes += $6 } END { print bytes }' ` |
|
pid_KB=`expr $pid_KB / 1024` |
|
echo "$pid_KB KB" |
|
total_file_KB=`expr $total_file_KB + $pid_KB` |
|
done |
|
i_size=`tail -n1 subtrace | awk '{ if ($12 > 1024) printf "%d KB", ($12/1024); else printf "%d bytes", $12; }' ` |
|
echo " Total $read_write: $total_file_KB KB i_size: $i_size" |
|
grand_total_KB=`expr $grand_total_KB + $total_file_KB` |
|
fi |
|
done |
|
echo "Grand Total File DATA KB $read_write $grand_total_KB" |
|
rm tempfile |
|
} |
|
|
|
process_files_writepages() { |
|
get_unique_files_writepages |
|
# Loop over each file that was involved in IO |
|
# Aggregate the IO done on that file and dump it out |
|
grand_total_KB=0 |
|
cp $infile tempfile |
|
for i in `cat uniq_files` |
|
do |
|
# Get just the tracepoints for this file |
|
fgrep -w "$i" tempfile > subtrace |
|
if [ -s subtrace ]; then |
|
fgrep -v -w "$i" tempfile > foo |
|
mv foo tempfile |
|
total_file_KB=`cat subtrace | awk '{ bytes += $4 } END { print bytes }' ` |
|
total_file_KB=`expr $total_file_KB / 1024` |
|
if [ $total_file_KB -gt 0 ]; then |
|
echo "File: $i Total $read_write: $total_file_KB KB" |
|
grand_total_KB=`expr $grand_total_KB + $total_file_KB` |
|
fi |
|
fi |
|
done |
|
echo "Grand Total File DATA KB Writepages $grand_total_KB" |
|
rm tempfile |
|
} |
|
|
|
# Get the aggregate list of pids. For each pid, break up the IOs by file |
|
process_pids() { |
|
read_write=$1 |
|
get_unique_pids |
|
list_of_pids=`cat uniq_pids` |
|
# $list_of_pids is a list of all the pids involved in IO |
|
# |
|
# Loop over each pid that was involved in IO |
|
# Find all the files the pid was doing IO on |
|
# Aggregate the IO done by the pid for each file and dump it out |
|
# |
|
grand_total_KB=0 |
|
for i in $list_of_pids |
|
do |
|
echo "PID: $i" |
|
total_pid_KB=0 |
|
# Get just the tracepoints for this pid |
|
fgrep -w "$i" $infile > subtrace |
|
# Get all the pids doing IO on this file |
|
get_unique_files_bypid subtrace |
|
list_of_files=`cat uniq_files_bypid` |
|
# $list_of_files is a list of all the files IO'ed by this pid |
|
for j in $list_of_files |
|
do |
|
i_size=`fgrep -w "$j" subtrace | tail -n1 | awk '{ if ($12 > 1024) printf "%d KB", ($12/1024); else printf "%d bytes", $12; }' ` |
|
file_KB=`fgrep -w "$j" subtrace | awk '{ bytes += $6 } END { print bytes }' ` |
|
file_KB=`expr $file_KB / 1024` |
|
echo " $j $read_write: $file_KB KB i_size: $i_size" |
|
total_pid_KB=`expr $total_pid_KB + $file_KB` |
|
done |
|
echo " Total $read_write: $total_pid_KB KB" |
|
grand_total_KB=`expr $grand_total_KB + $total_pid_KB` |
|
done |
|
echo "Grand Total File DATA KB $read_write $grand_total_KB" |
|
} |
|
|
|
# main() starts here : |
|
|
|
if [ $# -lt 1 ]; then |
|
usage |
|
fi |
|
|
|
bdev_set=false |
|
infile=tracefile.$$ |
|
|
|
parseoptions $@ |
|
adb root && sleep 2 |
|
getmodel |
|
|
|
found_f2fs=`adb shell 'mount | grep f2fs > /dev/null; echo $?' ` |
|
|
|
if [ $found_f2fs == 0 ]; then |
|
f2fs_fs=1 |
|
else |
|
f2fs_fs=0 |
|
fi |
|
|
|
if [ $f2fs_fs == 0 ] && [ $trace_writepages == true ]; then |
|
echo "Writepages is only supported with f2fs, please use -r, -w" |
|
exit 1 |
|
fi |
|
|
|
prep_to_do_something |
|
|
|
clean_up_tracepoints |
|
disk_stats_before |
|
# Start streaming the trace into the tracefile |
|
streamtrace_start & |
|
|
|
do_something |
|
|
|
streamtrace_end |
|
disk_stats_after |
|
|
|
copyout_trace |
|
|
|
if [ $trace_reads == true ]; then |
|
echo |
|
echo "READS :" |
|
echo "_______" |
|
echo |
|
prep_tracefile_rd |
|
# Get file specific stats - for each file, how many pids read that file ? |
|
echo "FILE VIEW:" |
|
process_files_rw Reads |
|
if [ $pid_view == true ]; then |
|
# Get pid specific stats - for each pid, what files do they do IO on ? |
|
echo "PID VIEW:" |
|
process_pids Reads |
|
fi |
|
disk_stats_delta_rd $grand_total_KB |
|
|
|
debug_FileKB_rd=`cat $infile | awk '{ bytes += $6 } END { printf "%d", bytes/1024 }' ` |
|
echo Debug Grand Total KB READ $debug_FileKB_rd |
|
fi |
|
|
|
if [ $trace_writes == true ]; then |
|
echo |
|
echo "Writes :" |
|
echo "_______" |
|
echo |
|
prep_tracefile_wr |
|
# Get file specific stats - for each file, how many pids read that file ? |
|
|
|
echo "FILE VIEW:" |
|
process_files_rw Writes |
|
if [ $pid_view == true ]; then |
|
# Get pid specific stats - for each pid, what files do they do IO on ? |
|
echo "PID VIEW:" |
|
process_pids Writes |
|
fi |
|
disk_stats_delta_wr $grand_total_KB |
|
|
|
if [ $f2fs_fs == 1 ] ; then |
|
echo f2fs GC_KB delta = $F2FS_GC_KB_DELTA |
|
fi |
|
fi |
|
|
|
if [ $f2fs_fs == 1 ] && [ $trace_writepages == true ] ; then |
|
echo |
|
echo "Writepages :" |
|
echo "__________" |
|
echo |
|
prep_tracefile_writepages |
|
# Get file specific stats - for each file, how much did we writepage ? |
|
|
|
echo "FILE VIEW:" |
|
process_files_writepages |
|
|
|
disk_stats_delta_wr $grand_total_KB |
|
|
|
echo f2fs GC_KB delta = $F2FS_GC_KB_DELTA |
|
fi |
|
|
|
rm -rf tracefile* uniq_* subtrace trace_saved
|
|
|