#!/bin/bash
# core/timer - duration measuring support

set -e

lib_load 'sys/tool/bc'


######
# Internal Functions

timer_now() { date '+%s.%N'; }

timer_var_running() { echo "$1"; }
timer_var_start() { echo "${1}_start"; }
timer_var_final() { echo "${1}_final"; }
timer_var_marks() { echo "${1}_marks"; }


######
# Timer Mark Interface

timer_mark() {
	min_args 1 "$@"
	local var when
	var=$(timer_var_marks "$1")
	when=${2:-$(timer_now)}
	[ "$when" ] || error "timer $1: unable to set mark"
	eval "$var+=( $when )"
}

timer_mark_all() {
	has_args 1 "$@"
	local marksvar=$(timer_var_marks "$1")
	eval "echo \"\${${marksvar}[*]}\""
}

timer_mark_count() {
	has_args 1 "$@"
	local marksvar
	marksvar=$(timer_var_marks "$1")
	eval "echo \$((\${#$marksvar[*]}))"
}

timer_mark_first() {
	has_args 1 "$@"
	local marksvar
	marksvar=$(timer_var_marks "$1")
	eval "echo \"\$$marksvar\""
}

timer_mark_get() {
	has_args 2 "$@"
	local marksvar
	marksvar=$(timer_var_marks "$1")
	eval "echo \"\${${marksvar}[$2]}\""
}

timer_mark_measure() {
	has_args 3 "$@"
	local name=$1
	local idxstart=$2
	local idxfinal=$3

	local count
	count=$(timer_mark_count "$name")
	if ! [ $idxstart -lt $count -a $idxfinal -lt $count ]; then
		local msg="cannot measure from $idxstart to $idxfinal"
		error "timer $name: $msg with $count marks"
	fi

	local start final elapsed
	start=$(timer_mark_get $name $idxstart)
	final=$(timer_mark_get $name $idxfinal)
	bc_gen_sub $final $start | bc_run
}


######
# Timer Lap Interface

timer_laps() {
	has_args 1 "$@"
	local count
	count=$(timer_mark_count "$1")
	if [ $count -gt 1 ]; then
		echo $((count - 1))
	else
		echo 0
	fi
}

timer_has_laps() {
	has_args 1 "$@"
	local laps=$(timer_laps "$1")
	[ $laps -gt 0 ]
}

timer_lap_measure() {
	has_args 3 "$@"
	local name=$1
	if ! timer_has_laps "$name"; then
		warn "timer: $name: no laps recorded"
		return
	fi
	timer_mark_measure "$2" "$3"
}

timer_lap_last() {
	has_args 1 "$@"
	timer_lap_measure "$1" -2 -1 
}


######
# Timer Query

timer_exists() {
	local -n running=$(timer_var_running "$1")
	[ "$running" ]
}

timer_is_running() {
	has_args 1 "$@"
	local -n running=$(timer_var_running "$1")
	[ "$running" ] && $running
}

timer_running() {
	local -n running=$(timer_var_running "$1")
	running=$2
}


######
# Timer Control

timer_start() {
	has_args 1 "$@"
	local name=$1

	if timer_is_running "$name"; then
		warn "$name: timer already running"
		return
	fi

	timer_running true

	local -n start=$(timer_var_start "$name")
	start=$(timer_now)

	timer_mark $name $start
}

timer_stop() {
	has_args 1 "$@"
	local name=$1

	local -n final=$(timer_var_final "$name")
	final=$(timer_now)

	timer_mark $name $final
	timer_running false
}


######
# Timer Reporting

timer_elapsed() {
	timer_elapsed_hms "$@"
}

timer_elapsed_hms() {
	local elapsed
	elapsed=$(timer_elapsed_seconds "$@")
	local sec=${elapsed%.*}
	local nsec=${elapsed#*.}

	local hrs=$((sec / 3600))
	[ $hrs -gt 0 ] && echo "$hrs hours" || hrs=''

	secs=$((secs % 3600))

	local min=$((sec / 60))
	[ "$hrs" -o $min -gt 0 ] && echo "${hrs:+, }$min minutes" || min=''

	sec=$((sec % 60))

	echo "${min:+, }$sec.$nsec seconds"
}

timer_elapsed_seconds() {
	has_args 1 "$@"
	echo "$(timer_mark_measure "$1" 0 -1)"
}

View the Script Reference Index


Generated on Tue Apr 25 21:20:18 PDT 2017 by mcsh i7 v0.18.0.