#!/usr/bin/env awk -f function log10(n) { return log(n)/log(10.0) } function merge_meas(est_val, est_unc, meas_val, meas_unc) { # Kalman filtering compares variances, # convert uncertainties to square units est_unc = (0.5*est_unc)^2.0 meas_unc = (0.5*meas_unc)^2.0 K = (est_unc)/((est_unc) + (meas_unc)) est_val = est_val + K*(meas_val - est_val) est_unc = (est_unc*meas_unc)/(est_unc + meas_unc) # convert est_unc back to original units est_unc = 2.0*sqrt(est_unc) return sprintf(OFMT OFS OFMT ORS, est_val, est_unc) } 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() { "uname" | getline uname close("uname") if (uname ~/OpenBSD/) { "sysctl kern.boottime" | getline t0_k close("sysctl kern.boottime") sub("^.*=", "", t0_k) split(t0_k, t0_k_arr) t0_k_arr[2] = (index("JanFebMarAprMayJunJulAugSepOctNovDec", t0_k_arr[2]) + 2)/3.0 gsub(":", " ", t0_k_arr[4]) t0_k = sprintf("%04d %02d %02d %s", t0_k_arr[5], t0_k_arr[2], t0_k_arr[3], t0_k_arr[4]) t0_k = mktime(t0_k) } return t0_k } # 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] = ck_boottime() ARGV[2] ? t0_est[2] = ARGV[2] : t0_est[2] = systime() } #print("t0_est = ", t0_est[1]) #print("t_boot_unc = ", t0_est[2]) # check uptime, update estimate print(ck_uptime(t0_est[1], t0_est[2])) }