#!/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])) }