diff options
Diffstat (limited to 'eshprof/flat-profile.esh')
-rw-r--r-- | eshprof/flat-profile.esh | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/eshprof/flat-profile.esh b/eshprof/flat-profile.esh new file mode 100644 index 0000000..ecf2a6e --- /dev/null +++ b/eshprof/flat-profile.esh @@ -0,0 +1,199 @@ +# Flat profiler +# +# Copyright (C) 2016 Patrick "P. J." McDermott +# +# This file is part of the Eggshell Profiler. +# +# The Eggshell Profiler is free software: you can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# The Eggshell Profiler is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Eggshell Profiler. If not, see +# <http://www.gnu.org/licenses/>. + +sp= +fn_name= +fn_start_time= +fn_end_time= +fns= +total_runtime= + +sp_inc() +{ + sp=$((${sp} + 1)) +} + +sp_dec() +{ + sp=$((${sp} - 1)) +} + +frame_set() +{ + local p="${1}" + shift 1 + + eval "frame_${p}_name=\${fn_name}" + eval "frame_${p}_time=0" +} + +frame_get() +{ + local p="${1}" + shift 1 + + eval "fn_name=\${frame_${p}_name}" + eval "fn_time=\${frame_${p}_time}" +} + +frame_unset() +{ + local p="${1}" + shift 1 + + unset "frame_${p}_name" + unset "frame_${p}_time" +} + +frame_inc_time() +{ + local p="${1}" + local value="${2}" + + eval "frame_${p}_time=\$(awk \ + -v time=\${frame_${p}_time} -v value=\${value} \ + 'BEGIN { print(time + value); }')" +} + +frame_dec_time() +{ + local p="${1}" + local value="${2}" + + eval "frame_${p}_time=\$(awk \ + -v time=\${frame_${p}_time} -v value=\${value} \ + 'BEGIN { print(time - value); }')" +} + +ctxsw() +{ + local prev_sp="${1}" + local next_sp="${2}" + local time="${3}" + shift 2 + + frame_inc_time ${prev_sp} ${time} + frame_dec_time ${next_sp} ${time} +} + +record() +{ + local name="${1}" + local time="${2}" + shift 2 + + case " ${fns} " in + "${name}") + eval "fn_timing_${name}=\$(awk \ + -v time=\${fn_timing_${name}} -v inc=\${time} \ + 'BEGIN { print(time + inc); }')" + eval "fn_calls_${name}=\$((\${fn_calls_${name}} + 1))" + ;; + *) + eval "fn_timing_${name}=\${time}" + eval "fn_calls_${name}=1" + fns="${fns} ${name}" + ;; + esac + total_runtime=$(awk -v total=${total_runtime} -v inc=${time} \ + 'BEGIN { print(total + inc); }') +} + +fn_begin() +{ + local name="${1}" + local time="${2}" + shift 2 + local old_sp= + + old_sp=${sp} + sp_inc + fn_name="${name}" + frame_set ${sp} + ctxsw ${old_sp} ${sp} ${time} +} + +fn_end() +{ + local name="${1}" + local time="${2}" + shift 2 + local old_sp= + + old_sp=${sp} + sp_dec + ctxsw ${old_sp} ${sp} ${time} + frame_get ${old_sp} + record ${fn_name} ${fn_time} + frame_unset ${old_sp} +} + +read_profile() +{ + local profile="${1}" + shift 1 + + while read time change fn; do + #time="${time%.*}${time#*.}" + case "${change}" in + 'B') + fn_begin "${fn}" "${time}" + ;; + 'E') + fn_end "${fn}" "${time}" + ;; + esac + done <"${profile}" +} + +show_table() +{ + local fn= + local time= + local percent= + local calls= + + printf ' self\n' + printf '%% time seconds calls name\n' + for fn in ${fns}; do + eval "time=\${fn_timing_${fn}}" + percent=$(awk -v time=${time} -v total=${total_runtime} \ + 'BEGIN { print(time / total * 100); }') + eval "calls=\${fn_calls_${fn}}" + printf '%6.2f ' ${percent} + printf '%14.9f ' ${time} + printf '%8d ' ${calls} + printf '%s\n' "${fn}" + done | sort -r -k 2,4 +} + +flat_profile() +{ + local profile="${1}" + shift 1 + sp=0 + fn_name='' + fn_time=0 + fns='' + total_runtime=0 + + read_profile "${profile}" + show_table +} |