#!/usr/bin/env bash # mac-ops :: boot-perf.sh # Measure boot duration and identify slow startup components. # macOS records boot events in the unified log; we extract the markers. set -u DAYS=7 SHOW_N=10 while [[ $# -gt 0 ]]; do case "$1" in --days) DAYS="$2"; shift 2 ;; --show) SHOW_N="$2"; shift 2 ;; --help|-h) cat </dev/null | head -100) if [[ -z "$boots_raw" ]]; then log_info "Boot events" "no boot markers found in window — try a wider --days N" else # Each fresh boot logs "Darwin Kernel Version" once; count them boot_count=$(echo "$boots_raw" | grep -c "Darwin Kernel Version" || echo 0) log_info "Boots in last ${DAYS}d" "${boot_count:-0}" note " Recent boot markers (most recent ${SHOW_N}):" echo "$boots_raw" | grep "Darwin Kernel Version" | tail -"$SHOW_N" | awk '{print $1, $2}' | sed 's/^/ /' fi # ---------------------------------------------------------------------------- section "2. CURRENT BOOT DURATION ESTIMATE" # ---------------------------------------------------------------------------- # Find the most recent boot marker (Darwin Kernel Version line) boot_start_line=$(log show --last "${DAYS}d" --style compact --predicate \ 'process == "kernel" AND eventMessage CONTAINS "Darwin Kernel Version"' \ 2>/dev/null | tail -1) boot_start_ts=$(echo "$boot_start_line" | awk '{print $1, $2}') if [[ -z "$boot_start_ts" ]]; then log_warn "Boot start timestamp" "could not extract" else note " Boot start: $boot_start_ts" # Find first WindowServer / loginwindow ready event AFTER boot if loginwindow_evt=$(log show --start "$boot_start_ts" --style compact 2>/dev/null \ | grep -E "(loginwindow.*started|WindowServer.*started|opendirectoryd started)" \ | head -3); then note " Earliest user-space events after boot:" echo "$loginwindow_evt" | sed 's/^/ /' fi # Attempt to compute seconds from boot to loginwindow first_user_event=$(echo "$loginwindow_evt" | head -1 | awk '{print $1, $2}') if [[ -n "$first_user_event" ]] && command -v gdate >/dev/null 2>&1; then b=$(gdate -d "$boot_start_ts" +%s 2>/dev/null) f=$(gdate -d "$first_user_event" +%s 2>/dev/null) if [[ -n "$b" ]] && [[ -n "$f" ]]; then diff=$((f - b)) log_info "Boot duration (boot → user-space)" "${diff}s" fi else log_info "Boot duration calc" "install coreutils (brew install coreutils) for gdate-based timing" fi fi # ---------------------------------------------------------------------------- section "3. SLOW LAUNCH AGENTS" # ---------------------------------------------------------------------------- # Find agents that took long to start. Narrow to launchd messages specifically; # avoid matching Wi-Fi/airportd "throttled=0" noise. slow_events=$(log show --last "${DAYS}d" --style compact --predicate \ 'process == "launchd" AND (eventMessage CONTAINS "took longer than" OR eventMessage CONTAINS "throttled by" OR eventMessage CONTAINS "exited with abnormal code")' \ 2>/dev/null | head -20) if [[ -z "$slow_events" ]]; then log_pass "Slow launchd events" "none found" else n=$(echo "$slow_events" | wc -l | tr -d ' ') log_warn "Slow launchd events" "$n events — see below" echo "$slow_events" | head -10 | sed 's/^/ /' fi # ---------------------------------------------------------------------------- section "4. LOGINWINDOW DELAYS" # ---------------------------------------------------------------------------- # loginwindow logs assertions about slow login items loginwindow_delays=$(log show --last "${DAYS}d" --style compact \ --predicate 'process == "loginwindow"' 2>/dev/null \ | grep -iE "(delay|slow|timed out|waited)" \ | head -10) if [[ -n "$loginwindow_delays" ]]; then log_warn "loginwindow delay messages" "see below" echo "$loginwindow_delays" | sed 's/^/ /' else log_pass "loginwindow delays" "none reported" fi # ---------------------------------------------------------------------------- section "5. SAFE-BOOT / VERBOSE-BOOT INDICATORS" # ---------------------------------------------------------------------------- # nvram for boot args boot_args=$(nvram boot-args 2>/dev/null | awk '{print $2}') if [[ "$boot_args" == *"-v"* ]] || [[ "$boot_args" == *"-x"* ]]; then log_warn "NVRAM boot-args" "$boot_args — non-default boot mode" else log_pass "NVRAM boot-args" "default (${boot_args:-empty})" fi # ---------------------------------------------------------------------------- emit_summary