From e9d3488a9ef1a1b5bf8e75afc719b3cce68b9853 Mon Sep 17 00:00:00 2001 From: wukong Date: Sat, 22 Nov 2025 00:02:20 -0800 Subject: initial commit. ckt0.awk is launched from ckt0.sh with state stored in a shell variable. --- ckcptime.awk | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ckcptime.sh | 21 +++++++ ckt0.awk | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++ ckt0.sh | 38 +++++++++++++ 4 files changed, 393 insertions(+) create mode 100644 ckcptime.awk create mode 100644 ckcptime.sh create mode 100644 ckt0.awk create mode 100644 ckt0.sh diff --git a/ckcptime.awk b/ckcptime.awk new file mode 100644 index 0000000..4bc9539 --- /dev/null +++ b/ckcptime.awk @@ -0,0 +1,177 @@ +#!/usr/bin/env awk -f + + +function log10(n) { + + return log(n)/log(10.0) + +} + + +function merge_meas(val_est, unc_est, val_meas, unc_meas) { + + # add (meas - est) delta to the measurement uncertainty + # note: this works when tracking a constant value, + # the first derivative of a constant 'should' be zero + # unc_meas = sqrt(unc_meas^2.0 + (val_meas - val_est)^2.0) + + # Kalman filtering compares variances + unc_est = (0.5*unc_est)^2.0 + unc_meas = (0.5*unc_meas)^2.0 + + G_K = (unc_est)/((unc_est) + (unc_meas)) + val_est = val_est + G_K*(val_meas - val_est) + unc_est = (unc_est*unc_meas)/(unc_est + unc_meas) + + # convert unc_est back to same units as val_est + unc_est = 2.0*sqrt(unc_est) + + return sprintf(OFMT OFS OFMT ORS, val_est, unc_est) + +} + + +function sigfig(val, unc) { + + ordmag_val = log10(val) + ordmag_unc = log10(unc) + + sigfig_unc = sprintf("%.f", 6) + sigfig_val = sprintf("%.f", (ordmag_val - ordmag_unc + sigfig_unc)) + + ofmt_val = "%." sigfig_val "g" + ofmt_unc = "%." sigfig_unc "g" + + return sprintf(ofmt_val OFS ofmt_unc ORS, val, unc) + +} + + +function ck_boottime() { + + "sysctl kern.boottime" | getline t_kboot + close("sysctl kern.boottime") + sub("^.*\{", "", t_kboot) + sub("\}.*$", "", t_kboot) + split(t_kboot, t_kboot_arr, ",") + + for (i in t_kboot_arr) { + sub("^.*= ", "", t_kboot_arr[i]) + } + + t_kboot = sprintf(t_kboot_arr[1] "." t_kboot_arr[2]) + return t_kboot + +} + + +function ck_cptime() { + + t_sys_meas[1] = systime() + t_sys_meas[2] = 1.0 + + "sysctl kern.cp_time" | getline cptime_cmd + close("sysctl kern.cp_time") + + split(merge_meas(t_sys_meas[1], t_sys_meas[2], systime(), 1.0), t_sys_meas) + + sub("^.*=", "", cptime_cmd) + gsub(",", OFS, cptime_cmd) + #split(cptime_cmd, cptime_arr, ",") + + return sprintf(OFMT OFS "%s", t_sys_meas[1], cptime_cmd) + +} + + +function ck_uptime(t0_est, t0_unc) { + + t_sys_meas[1] = systime() + t_sys_meas[2] = 1.0 + + "uptime" | getline t_up_cmd + close("uptime") + + split(merge_meas(t_sys_meas[1], t_sys_meas[2], systime(), 1.0), t_sys_meas) + + # estimate (predict) uptime + t_up_est[1] = t_sys_meas[1] - t0_est + t_up_est[2] = t_sys_meas[2] + t0_unc + + # evaluate measured uptime + t_up_meas[1] = 0.0 + t_up_meas[2] = systime() + + sub("^.*up ", "", t_up_cmd) + sub(", load.*$", "", t_up_cmd) + split(t_up_cmd, t_up_cmd_arr, ",") + + for (i in t_up_cmd_arr) { + + # TODO: add cases for days, months, years, etc. + if (t_up_cmd_arr[i] ~ /day/) { + split(t_up_cmd_arr[i], days) + t_up_meas[1] += 86400.0*(days[1] + 0.0) + (t_up_meas[2] > 86400.0) ? t_up_meas[2] = 86400.0 : t_up_meas[2] += 0.0 + } + + if (t_up_cmd_arr[i] ~ /hr/) { + split(t_up_cmd_arr[i], hrs) + t_up_meas[1] += 3600.0*(hrs[1] + 0.0) + (t_up_meas[2] > 3600.0) ? t_up_meas[2] = 3600.0 : t_up_meas[2] += 0.0 + } + + if (t_up_cmd_arr[i] ~ /min/) { + split(t_up_cmd_arr[i], mins) + t_up_meas[1] += (60.0*(mins[1] + 0.0)) + (t_up_meas[2] > 60.0) ? t_up_meas[2] = 60.0 : t_up_meas[2] += 0.0 + } + + if (t_up_cmd_arr[i] ~ /:/) { + split(t_up_cmd_arr[i], hrs_min, ":") + t_up_meas[1] += 3600.0*(hrs_min[1] + 0.0) + (t_up_meas[2] > 3600.0) ? t_up_meas[2] = 3600.0 : t_up_meas[2] += 0.0 + t_up_meas[1] += 60.0*(hrs_min[2] + 0.0) + (t_up_meas[2] > 60.0) ? t_up_meas[2] = 60.0 : t_up_meas[2] += 0.0 + } + + } + + # merge predicted and measured uptimes + split(merge_meas(t_up_est[1], t_up_est[2], t_up_meas[1], t_up_meas[2]), t_up_est) + + # evaluate measured boot time, t0 + t_boot_meas[1] = t_sys_meas[1] - t_up_meas[1] + t_boot_meas[2] = t_sys_meas[2] + t_up_meas[2] + + # merge previous and updated boot time, t0 + split(merge_meas(t0_est, t0_unc, t_boot_meas[1], t_boot_meas[2]), t_boot_est) + + return sigfig(t_boot_est[1], t_boot_est[2]) + +} + + +BEGIN { + + OFMT="%.21g" + #print("_systime_", systime()) + #print("_boottime_", ck_boottime()) + printf("%s" ORS, ck_cptime()) + + # check ARGV for previous estimate + # if (ARGC > 0) { + # ARGV[1] ? t0_est[1] = ARGV[1] : t0_est[1] = 0.0 + # ARGV[2] ? t0_est[2] = ARGV[2] : t0_est[2] = systime() + # } + #print("t0_est = ", t0_est[1]) + #print("t_boot_unc = ", t0_est[2]) + + # wait (sleep) based on uncertainty + # print(60.0/t0_est[2]) + + # check uptime, update estimate + #print(ck_uptime(t0_est[1], t0_est[2])) + +} + diff --git a/ckcptime.sh b/ckcptime.sh new file mode 100644 index 0000000..079faa6 --- /dev/null +++ b/ckcptime.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env sh + +# estimate sytem boot time + +# [debug] enable execution tracing +#set -x +set -e + +# raw input data +#date +%s +#sysctl kern.cp_time | awk -F= '{print($0)}' + +#printf "sec\n" | column -t +for N in $(seq 0 45) ; do + #printf "${N} ${t0_est}\n" | column -t + awk -f ckcptime.awk + sleep $( awk 'BEGIN {print( rand()^2.0 + 1.0 )}' ) +done + +# [debug] disable execution tracing +set +x diff --git a/ckt0.awk b/ckt0.awk new file mode 100644 index 0000000..ebe724f --- /dev/null +++ b/ckt0.awk @@ -0,0 +1,157 @@ +#!/usr/bin/env awk -f + + +function log10(n) { + + return log(n)/log(10.0) + +} + + +function merge_meas(val_est, unc_est, val_meas, unc_meas) { + + # Kalman filtering compares variances, + # convert uncerainties to square units + unc_est = (0.5*unc_est)^2.0 + unc_meas = (0.5*unc_meas)^2.0 + + G_K = (unc_est)/((unc_est) + (unc_meas)) + val_est = val_est + G_K*(val_meas - val_est) + unc_est = (unc_est*unc_meas)/(unc_est + unc_meas) + + # convert unc_est back to original units + unc_est = 2.0*sqrt(unc_est) + + return sprintf(OFMT OFS OFMT ORS, val_est, unc_est) + +} + + +function sigfig(val, unc) { + + ordmag_val = log10(val) + ordmag_unc = log10(unc) + + #sigfig_unc = sprintf("%.f", 6) + sigfig_unc = sprintf("%.f", sqrt((ordmag_val - ordmag_unc)^2.0) + 1.0) + sigfig_val = sprintf("%.f", (ordmag_val - ordmag_unc + sigfig_unc)) + + ofmt_val = "%." sigfig_val "g" + ofmt_unc = "%." sigfig_unc "g" + + return sprintf(ofmt_val OFS ofmt_unc ORS, val, unc) + +} + + +# function ck_boottime() { +# +# "sysctl kern.boottime" | getline t_kboot +# close("sysctl kern.boottime") +# sub("^.*\{", "", t_kboot) +# sub("\}.*$", "", t_kboot) +# split(t_kboot, t_kboot_arr, ",") +# +# for (i in t_kboot_arr) { +# sub("^.*= ", "", t_kboot_arr[i]) +# } +# +# t_kboot = sprintf(t_kboot_arr[1] "." t_kboot_arr[2]) +# return t_kboot +# +# } + + +function ck_uptime(t0_est, t0_unc) { + + t_sys_meas[1] = systime() + t_sys_meas[2] = 1.0 + + "uptime" | getline t_up_cmd + close("uptime") + + split(merge_meas(t_sys_meas[1], t_sys_meas[2], systime(), 1.0), t_sys_meas) + + # estimate (predict) uptime + t_up_est[1] = t_sys_meas[1] - t0_est + t_up_est[2] = t_sys_meas[2] + t0_unc + + # evaluate measured uptime + t_up_meas[1] = 0.0 + t_up_meas[2] = systime() + + sub("^.*up ", "", t_up_cmd) + sub(", load.*$", "", t_up_cmd) + split(t_up_cmd, t_up_cmd_arr, ",") + + for (i in t_up_cmd_arr) { + + # TODO: add cases for days, months, years, etc. + if (t_up_cmd_arr[i] ~ /day/) { + split(t_up_cmd_arr[i], days) + t_up_meas[1] += 86400.0*(days[1] + 0.0) + (t_up_meas[2] > 86400.0) ? t_up_meas[2] = 86400.0 : t_up_meas[2] += 0.0 + } + + if (t_up_cmd_arr[i] ~ /hr/) { + split(t_up_cmd_arr[i], hrs) + t_up_meas[1] += 3600.0*(hrs[1] + 0.0) + (t_up_meas[2] > 3600.0) ? t_up_meas[2] = 3600.0 : t_up_meas[2] += 0.0 + } + + if (t_up_cmd_arr[i] ~ /min/) { + split(t_up_cmd_arr[i], mins) + t_up_meas[1] += (60.0*(mins[1] + 0.0)) + (t_up_meas[2] > 60.0) ? t_up_meas[2] = 60.0 : t_up_meas[2] += 0.0 + } + + if (t_up_cmd_arr[i] ~ /:/) { + split(t_up_cmd_arr[i], hrs_min, ":") + t_up_meas[1] += 3600.0*(hrs_min[1] + 0.0) + (t_up_meas[2] > 3600.0) ? t_up_meas[2] = 3600.0 : t_up_meas[2] += 0.0 + t_up_meas[1] += 60.0*(hrs_min[2] + 0.0) + (t_up_meas[2] > 60.0) ? t_up_meas[2] = 60.0 : t_up_meas[2] += 0.0 + } + + } + + # merge predicted and measured uptimes + split(merge_meas(t_up_est[1], t_up_est[2], t_up_meas[1], t_up_meas[2]), t_up_est) + + # evaluate measured boot time, t0 + t_boot_meas[1] = t_sys_meas[1] - t_up_meas[1] + t_boot_meas[2] = t_sys_meas[2] + t_up_meas[2] + + # merge previous and updated boot time, t0 + split(merge_meas(t0_est, t0_unc, t_boot_meas[1], t_boot_meas[2]), t_boot_est) + + return sigfig(t_boot_est[1], t_boot_est[2]) + +} + + +BEGIN { + + OFMT="%.21g" + pi = 4.0*atan2(1.0, 1.0) + c0 = 299792458 # m/sec + + #print("_systime_", systime()) + #print("_boottime_", ck_boottime()) + + # check ARGV for previous estimate + if (ARGC > 0) { + ARGV[1] ? t0_est[1] = ARGV[1] : t0_est[1] = 0.0 + ARGV[2] ? t0_est[2] = ARGV[2] : t0_est[2] = systime() + } + #print("t0_est = ", t0_est[1]) + #print("t_boot_unc = ", t0_est[2]) + + # wait (sleep) based on uncertainty + # print(60.0/t0_est[2]) + + # check uptime, update estimate + print(ck_uptime(t0_est[1], t0_est[2])) + +} + diff --git a/ckt0.sh b/ckt0.sh new file mode 100644 index 0000000..8b9e785 --- /dev/null +++ b/ckt0.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env sh + +# estimate sytem boot time + +# [debug] enable execution tracing +#set -x +set -e + +# raw input data +#date +%s +sysctl_t0_str=$( sysctl kern.boottime | mawk -F= '{print($NF)}' ) +sysctl_t0=$( date -jf "%a %b %d %H:%M:%S %G" "${sysctl_t0_str}" +%s ) + +#epsilon1="$( mawk 'BEGIN{print(rand()^2.0)}' )" +#t0_est="${sysctl_t0} $(date +%s)" +#t0_est="${sysctl_t0} ${sysctl_t0}" +#t0_est="${sysctl_t0} ${epsilon1}" +#t0_est="${sysctl_t0} 1.0" + +if [ -f t0_est.log ] ; then { + t0_est="$( cat t0_est.log )" +} else { + t0_est="${sysctl_t0} 2.0" +} fi + +printf "N t0_est t0_unc\n" | column -t +for N in $(seq 0 1440) ; do + printf "${N} ${t0_est}\n" | column -t + #t0_est=$( mawk -f ckt0.awk ${t0_est} | tail -n2 ) + mawk -f ckt0.awk ${sysctl_t0} 2.0 + sleep $( mawk 'BEGIN {print( rand()^2.0 + 1.0 )}' ) + #sleep $( echo $t0_est | mawk '{print(sqrt(1.0 + ((60.0*$NF)/(60.0 + $NF))^2.0 + rand()^2.0 ))}' ) +done + +printf "${t0_est}\n" | tee t0_est.log + +# [debug] disable execution tracing +set +x -- cgit v1.2.3