#!/usr/bin/env bash
COLS=4
declare -A prev_idle prev_total

emit_grid() {
  local rows=() row_items=()
  while IFS= read -r line; do
    [[ $line =~ ^cpu([0-9]+) ]] || continue
    local core="${BASH_REMATCH[1]}"
    read -ra f <<< "$line"
    local idle=$(( f[4] + f[5] ))
    local total=0
    for x in "${f[@]:1}"; do (( total += x )); done

    local usage="0.0"
    if [[ -n "${prev_total[$core]+x}" ]]; then
      local dt=$(( total - prev_total[$core] ))
      local di=$(( idle  - prev_idle[$core]  ))
      (( dt > 0 )) && usage=$(awk "BEGIN{printf \"%.1f\", 100*(1-$di/$dt)}")
    fi
    prev_idle[$core]=$idle
    prev_total[$core]=$total

    local freq=0
    local fpath="/sys/devices/system/cpu/cpu${core}/cpufreq/scaling_cur_freq"
    [[ -r $fpath ]] && freq=$(( $(< "$fpath") / 1000 ))

    row_items+=("{\"core\":$core,\"usage\":$usage,\"freq\":$freq}")

    if (( ${#row_items[@]} == COLS )); then
      local row; printf -v row '%s,' "${row_items[@]}"; row="${row%,}"
      rows+=("[$row]")
      row_items=()
    fi
  done < /proc/stat

  if (( ${#row_items[@]} > 0 )); then
    local row; printf -v row '%s,' "${row_items[@]}"; row="${row%,}"
    rows+=("[$row]")
  fi

  local out; printf -v out '%s,' "${rows[@]}"; out="${out%,}"
  echo "[$out]"
}

while true; do
  emit_grid
  sleep 2
done
