blob: f3da5af05835c888d9c2efa140e36a333cd60ccf [file] [log] [blame]
#!/bin/sh
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# Helper script for turning system event tracing on/off.
#
# systrace start [ event-or-category ... ]
# systrace stop
# systrace [status]
#
# It is possible to pass either events category or event itself.
# Category is a group of predefined events. Event categories are one or more of
# "sched" (thread switch events), "workq" (workq start/stop events)
# "gfx" (select i915 events) and "power" (cpu frequency change events).
# "all" can be used to enable all supported event categories. If no
# categories or events are specified then "all" are enabled.
#
# While collecting events the trace ring-buffer size is increased
# based on the set of enabled events.
#
# On disabling tracing collected events are written to standard out
# which is expected to be directed to a file or similar.
#
set -e
CMD=${1:-status}
tracing_path=/sys/kernel/debug/tracing
# TODO(sleffler) enable more/different events
sched_events="
sched:sched_switch
sched:sched_wakeup
"
workq_events="
workqueue:workqueue_execute_start
workqueue:workqueue_execute_end
"
gfx_events="
i915:i915_flip_request
i915:i915_flip_complete
i915:i915_gem_object_pwrite
i915:intel_gpu_freq_change
exynos:exynos_flip_request
exynos:exynos_flip_complete
exynos:exynos_page_flip_state
drm_msm_gpu:msm_gpu_freq_change
drm_msm_gpu:msm_gpu_submit_flush
drm_msm_gpu:msm_gpu_submit_retired
drm_msm_atomic:msm_atomic_commit_tail_start
drm_msm_atomic:msm_atomic_commit_tail_finish
drm:drm_vblank_event
dma_fence:dma_fence_init
dma_fence:dma_fence_emit
dma_fence:dma_fence_destroy
dma_fence:dma_fence_enable_signal
dma_fence:dma_fence_signaled
dma_fence:dma_fence_wait_start
dma_fence:dma_fence_wait_end
"
power_events="
power:cpu_idle
power:cpu_frequency
power:cpu_frequency_limits
power:clock_enable
power:clock_disable
power:clock_set_rate
interconnect:icc_set_bw_end
mali:mali_dvfs_set_clock
mali:mali_dvfs_set_voltage
cpufreq_interactive:cpufreq_interactive_boost
cpufreq_interactive:cpufreq_interactive_unboost
exynos_busfreq:exynos_busfreq_target_int
exynos_busfreq:exynos_busfreq_target_mif
regulator:regulator_enable_complete
regulator:regulator_disable_complete
regulator:regulator_set_voltage_complete
"
input_events="
irq:irq_threaded_handler_entry
irq:irq_threaded_handler_exit
"
# TODO(sleffler) calculate based on enabled events
buffer_size_running=7040 # ring-buffer size in kb / cpu
buffer_size_idle=1408 # ring-buffer size while idle
if test ! -e ${tracing_path}; then
echo "Kernel tracing not available (missing ${tracing_path})" >&2
exit
fi
tracing_write()
{
echo $1 > $tracing_path/$2
}
tracing_enable()
{
tracing_write 1 tracing_on
}
tracing_disable()
{
tracing_write 0 tracing_on
}
tracing_enable_events()
{
local events_enabled
local events_failed
for ev; do
# NB: note >>
if echo ${ev} >> ${tracing_path}/set_event; then
events_enabled="${events_enabled} ${ev}"
else
events_failed="${events_failed} ${ev}"
fi
done
logger -t systrace "enable events ${events_enabled}"
if [ -n "${events_failed}" ]; then
logger -t systrace "Warning, events ${events_failed} were not enabled"
fi
}
tracing_reset()
{
tracing_disable # stop kernel tracing
tracing_write "" set_event # clear enabled events
}
parse_event_or_category()
{
case $1 in
gfx) echo "${gfx_events}";;
input) echo "${input_events}";;
power) echo "${power_events}";;
sched) echo "${sched_events}";;
workq) echo "${workq_events}";;
all) echo "${gfx_events}
${input_events}
${power_events}
${sched_events}
${workq_events}";;
*)
if ! echo "$1" | grep -E "^[a-z0-9_-]+:[a-zA-Z0-9_-]+$"; then
echo "Unknown event/category '$1'" >&2
exit 1
fi
;;
esac
}
is_enabled=$(cat "${tracing_path}/tracing_on")
case "$CMD" in
start)
events=""
shift
for cat; do
events="${events} $(parse_event_or_category $cat)"
done
if [ -z "${events}" ]; then
events=$(parse_event_or_category 'all')
fi
if [ "${is_enabled}" = "1" ]; then
tracing_reset
fi
logger -t systrace "start tracing"
tracing_write "mono" trace_clock # monotonic clock for timestamps
# NOTE lack of double quotes is intentional, we want ${events} word
# splitting here:
# shellcheck disable=SC2086
tracing_enable_events ${events}
# Pre v4.13 kernel uses print-tgid, but v4.13+ upstream replaced it with
# record-tgid option. Both options produce the same ftrace format change.
tgid_option=$(grep -e '^[a-z]*-tgid$' "${tracing_path}/trace_options") || :
if [ "${tgid_option}" = "noprint-tgid" ]; then
tracing_write "print-tgid" trace_options
elif [ "${tgid_option}" = "norecord-tgid" ]; then
tracing_write "record-tgid" trace_options
fi
tracing_write "${buffer_size_running}" buffer_size_kb
tracing_enable # start kernel tracing
;;
stop)
if [ "${is_enabled}" = "0" ]; then
echo "Tracing is not enabled; nothing to do" >&2
exit
fi
logger -t systrace "stop tracing"
# Add null sync marker for chrome so events are 0-time-shifted
# (on chrome os user-space events are stamped with the kernel
# trace clock so there is no need to time-shift events).
tracing_write 'trace_event_clock_sync: parent_ts=0' trace_marker
tracing_reset
# NB: debugd attaches stdout to an fd passed in by the client
cat ${tracing_path}/trace
tracing_write "0" trace # clear trace buffer
tracing_write "${buffer_size_idle}" buffer_size_kb
;;
status)
echo -n 'enabled: '; cat ${tracing_path}/tracing_on
echo -n 'clock: '; cat ${tracing_path}/trace_clock
echo 'enabled events:'; cat ${tracing_path}/set_event | sed 's/^/ /'
;;
*)
echo "Unknown request ${CMD}; use one of start, stop, status" >&2
exit 1
esac
exit 0