Skip to content

Commit

Permalink
benchmark: improve determination of the base time
Browse files Browse the repository at this point in the history
  • Loading branch information
akinomyoga committed Jan 20, 2022
1 parent 72d968f commit ad866c1
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 28 deletions.
1 change: 1 addition & 0 deletions docs/ChangeLog.md
Expand Up @@ -314,6 +314,7 @@
- edit (`command-help`): use `ble/util/assign/.mktmp` to determine the temporary filename `#D1663` 1af0800
- make: update lint check `#D1709` 7e26dcd
- test: save the test log to a file `#D1735` 0000000
- benchmark: improve determination of the base time `#D1737` 0000000

## Contrib

Expand Down
63 changes: 63 additions & 0 deletions note.txt
Expand Up @@ -5810,6 +5810,69 @@ bash_tips
Done (実装ログ)
-------------------------------------------------------------------------------

2022-01-18

* ble-measure の base がやはりずれる。より良い更新式を取得したい [#D1737]

うーん。というより此処まで大きくずれるのであれば nest レベル毎に計測を実施
するべきなのではないか。但し、ble-measure を自信から呼び出して使うと nest
レベルが1だけずれてしまう。然し、それでも nest レベル毎に計測し直した方が遥
かに良い値が出ている。

一応 nest レベルの 1 のずれを補正する事にする。${#FUNCNAME[*]} 1..11 まで計
測してそれを線形フィットする。

| gnuplot> plot 'a.txt'
| gnuplot> f(x) = a * x + b
| gnuplot> b=4500;a=100
| gnuplot> fit f(x) 'a.txt' via a,b
| iter chisq delta/lim lambda a b
| 0 1.5114300000e+05 0.00e+00 3.22e+03 1.000000e+02 4.500000e+03
| 1 3.2658557879e+04 -3.63e+05 3.22e+02 9.857978e+01 4.410413e+03
| 2 1.9568027480e+04 -6.69e+04 3.22e+01 8.865848e+01 4.465751e+03
| 3 1.9468872818e+04 -5.09e+02 3.22e+00 8.771000e+01 4.471467e+03
| 4 1.9468872727e+04 -4.67e-04 3.22e-01 8.770909e+01 4.471473e+03
| iter chisq delta/lim lambda a b
|
| After 4 iterations the fit converged.
| final sum of squares of residuals : 19468.9
| rel. change during last iteration : -4.66698e-09
|
| degrees of freedom (FIT_NDF) : 9
| rms of residuals (FIT_STDFIT) = sqrt(WSSR/ndf) : 46.5103
| variance of residuals (reduced chisquare) = WSSR/ndf : 2163.21
|
| Final set of parameters Asymptotic Standard Error
| ======================= ==========================
| a = 87.7091 +/- 4.435 (5.056%)
| b = 4471.47 +/- 30.08 (0.6726%)
|
| correlation matrix of the fit parameters:
| a b
| a 1.000
| b -0.885 1.000

4471.47 + 87.71 * ${FUNCNAME[*]}

現在のレベルが x の時、x+1 の計測結果は b+a(x+1) になっていると考えられるので、
[b+ax]/[b+a(x+1)] 倍すれば補正できる。

* うーん。最小時間を記録したらそれで更新する様にしたい。

線形フィットを実測値から実施する。然しそうしたとしてどのタイミングでその
値を使用するのだろうか? もし未知の場合には必ずその場で試行するのだとした
ら線形フィットを用意しておく意味はあるのだろうか。

* うーん。a=0 自体にも本来は実行コストが存在する筈である。それを計る事はで
きないのか。例えば a=0;a=0 とやると 670ns ぐらいはかかる。という事は、
600ns ぐらいは a=0 で消費している事になるが、一方でこれをどうやって自動的
に補正するかが問題になる。関数を空にする事ができないのが問題である。

計測する関数定義に return 0 を追加する事にした。これによって実際に計測時
間が 1us 程度増加してしまう様だが仕方がない。3nest 分の遅延と同じなので余
り気にしない事にする。→これで測ってみた所、a=0 の実行時間は最短で 666ns
になった。事前の見積もりと一貫した結果である。

2022-01-11

* def.sh にある設定更新メッセージが make install で削除されるのでは? [#D1736]
Expand Down
103 changes: 75 additions & 28 deletions src/benchmark.sh
@@ -1,12 +1,13 @@
#!/bin/bash

if ! type ble/util/print &>/dev/null; then
function ble/util/unlocal { builtin unset -v "$@"; }
function ble/util/print { builtin printf '%s\n' "$1"; }
function ble/util/print-lines { builtin printf '%s\n' "$@"; }
fi

function ble-measure/.loop {
builtin eval "function _target { $2; }"
builtin eval "function _target { ${2:+$2; }return 0; }"
local _i _n=$1
for ((_i=0;_i<_n;_i++)); do
_target
Expand Down Expand Up @@ -81,12 +82,13 @@ else
fi

_ble_measure_base= # [nsec]
_ble_measure_base_real=()
_ble_measure_base_nestcost=0 # [nsec/10]
_ble_measure_count=1 # 同じ倍率で _ble_measure_count 回計測して最小を取る。
_ble_measure_threshold=100000 # 一回の計測が threshold [usec] 以上になるようにする

## @fn ble-measure/calibrate
function ble-measure/calibrate.0 { local a; ble-measure a=1; }
function ble-measure/calibrate.0 { ble-measure -qc"$calibrate_count" ''; }
function ble-measure/calibrate.1 { ble-measure/calibrate.0; }
function ble-measure/calibrate.2 { ble-measure/calibrate.1; }
function ble-measure/calibrate.3 { ble-measure/calibrate.2; }
Expand All @@ -97,24 +99,40 @@ function ble-measure/calibrate.7 { ble-measure/calibrate.6; }
function ble-measure/calibrate.8 { ble-measure/calibrate.7; }
function ble-measure/calibrate.9 { ble-measure/calibrate.8; }
function ble-measure/calibrate.A { ble-measure/calibrate.9; }
function ble-measure/calibrate.assign2 { local a b; ble-measure 'a=1; b=2'; }
function ble-measure/calibrate {
local ret nsec

local calibrate_count=1
_ble_measure_base=0
_ble_measure_base_nestcost=0

# nest0: calibrate.0 の ble-measure 内部での ${#FUNCNAME[*]}
local nest0=$((${#FUNCNAME[@]}+2))
local nestA=$((nest0+10))
ble-measure/calibrate.0 &>/dev/null; local x0=$nsec
ble-measure/calibrate.A &>/dev/null; local xA=$nsec
ble-measure/calibrate.assign2 &>/dev/null; local y0=$nsec

ble-measure/calibrate.0; local x0=$nsec
ble-measure/calibrate.A; local xA=$nsec
local nest_cost=$((xA-x0))
local nest_base=$((x0-nest_cost*nest0/10))
_ble_measure_base=$((nest_base-(y0-x0)))
_ble_measure_base=$((x0-nest_cost*nest0/10))
_ble_measure_base_nestcost=$nest_cost
}
function ble-measure/fit {
local ret nsec
_ble_measure_base=0
_ble_measure_base_nestcost=0

local calibrate_count=10

local c nest_level=${#FUNCNAME[@]}
for c in {0..9} A; do
"ble-measure/calibrate.$c"
ble/util/print "$((nest_level++)) $nsec"
done > a.txt

gnuplot - <<EOF
f(x) = a * x + b
b=4500;a=100
fit f(x) 'a.txt' via a,b
EOF
}

## @fn ble-measure/.read-arguments.get-optarg
## @var[in,out] args iarg arg i c
Expand Down Expand Up @@ -161,7 +179,7 @@ function ble-measure/.read-arguments {
measure_threshold=$optarg ;;
(B)
ble-measure/.read-arguments.get-optarg &&
measure_base=$optarg measure_nestcost= ;;
__base=$optarg ;;
(*)
ble/util/print "ble-measure: unrecognized option '-$c'."
flags=E$flags ;;
Expand All @@ -188,20 +206,9 @@ function ble-measure/.read-arguments {
## @var[out] nsec
## 実行時間を nsec 単位で返します。
function ble-measure {
if [[ ! $_ble_measure_base ]]; then
_ble_measure_base=0 nsec=0
# : よりも a=1 の方が速い様だ
local a
ble-measure -qc3 'a=1'
# hp2019 上での評価 (assign=4695 nestcost=619 base=3113)
_ble_measure_base=$((nsec*663/1000))
_ble_measure_base_nestcost=$((nsec*132/1000))
fi

local __level=${#FUNCNAME[@]} __base=
local flags= command= count=$_ble_measure_count
local measure_threshold=$_ble_measure_threshold
local measure_base=$_ble_measure_base
local measure_nestcost=$_ble_measure_base_nestcost
ble-measure/.read-arguments "$@" || return "$?"
if [[ $flags == *h* ]]; then
ble/util/print-lines \
Expand All @@ -211,7 +218,7 @@ function ble-measure {
' Options:' \
' -q Do not print results to stdout.' \
' -a COUNT Measure COUNT times and average.' \
' -c COUNT Measure COUNT times and take maximum.' \
' -c COUNT Measure COUNT times and take minimum.' \
' -T TIME Set minimal measuring time.' \
' -B BASE Set base time (overhead of ble-measure).' \
' -- The rest arguments are treated as command.' \
Expand All @@ -226,6 +233,33 @@ function ble-measure {
return 2
fi

if [[ ! $__base ]]; then
if [[ $_ble_measure_base ]]; then
# ble-measure/calibrate 実行済みの時
__base=$((_ble_measure_base+_ble_measure_base_nestcost*__level/10))
else
# それ以外の時は __level 毎に計測
if [[ ! $ble_measure_calibrate && ! ${_ble_measure_base[__level]} ]]; then
if [[ ! ${_ble_measure_base_real[__level+1]} ]]; then
local ble_measure_calibrate=1
local a; ble-measure -qc3 -B 0 ''
ble/util/unlocal ble_measure_calibrate a
_ble_measure_base_real[__level+1]=$nsec
_ble_measure_base[__level+1]=$nsec
fi

# linear-fit result in chatoyancy
# 65.9818 pm 2.945 (4.463%)
# 4356.75 pm 19.97 (0.4585%)
local A=6598 B=435675
nsec=${_ble_measure_base_real[__level+1]}
_ble_measure_base[__level]=$((nsec*(B+A*(__level-1))/(B+A*__level)))
ble/util/unlocal A B
fi
__base=${_ble_measure_base[__level]:-0}
fi
fi

local prev_n= prev_utot=
local -i n
for n in {1,10,100,1000,10000}\*{1,2,5}; do
Expand All @@ -235,14 +269,14 @@ function ble-measure {
[[ $flags != *q* ]] && printf '%s (x%d)...' "$command" "$n" >&2
ble-measure/.time "$command" || return 1
[[ $flags != *q* ]] && printf '\r\e[2K' >&2
((utot >= measure_threshold)) || continue

prev_n=$n prev_utot=$utot

((utot >= measure_threshold)) || continue
local min_utot=$utot

# 繰り返し計測して最小値 (-a の時は平均値) を採用
if [[ $count ]]; then
local min_utot=$utot sum_utot=$utot sum_count=1 i
local sum_utot=$utot sum_count=1 i
for ((i=2;i<=count;i++)); do
[[ $flags != *q* ]] && printf '%s' "$command (x$n $i/$count)..." >&2
if ble-measure/.time "$command"; then
Expand All @@ -258,7 +292,20 @@ function ble-measure {
fi
fi

local nsec0=$((measure_base+measure_nestcost*${#FUNCNAME[*]}/10))
# upate base if the result is shorter than base
if ((min_utot<0x7FFFFFFFFFFFFFFF/1000)); then
local __real=$((min_utot*1000/n))
[[ ${_ble_measure_base_real[__level]} ]] &&
((__real<_ble_measure_base_real[__level])) &&
_ble_measure_base_real[__level]=$__real
[[ ${_ble_measure_base[__level]} ]] &&
((__real<_ble_measure_base[__level])) &&
_ble_measure_base[__level]=$__real
((__real<__base)) &&
__base=$__real
fi

local nsec0=$__base
if [[ $flags != *q* ]]; then
local reso=$_ble_measure_resolution
local awk=ble/bin/awk
Expand Down

0 comments on commit ad866c1

Please sign in to comment.