#! /bin/sh

# cpufreq-mon v1.0
# Monitor CPU frequency scaling
# Copyright (c) 2016 Raphaël Halimi <raphael.halimi@gmail.com>

# Source shell-script-helper
. /lib/shell-script-helper


#
# Variables
#

# Configuration files
SYSTEM_CONFIG_FILE="/etc/$(basename "$0").conf"
USER_CONFIG_FILE="$HOME/.$(basename "$0").conf"

# Options defaults
REFRESH=1

#
# Functions
#

print_usage () {
  printf "Usage: %s [OPTION]...\n" "$(basename "$0")"
  printf "Monitor CPU frequency scaling\n"
  printf "\nOPTIONS:\n"
  print_option "-r REFRESH" "Refresh interval (in seconds), default is 1"
  print_option "-v" "Verbose mode"
  print_option "-d" "Debug mode"
  print_option "-h" "Print this help message"
}

convert_value() {
  CORE_VALUE="$1"
  if [ "$CORE_VALUE" -ge 1000000 ] ; then
    printf "%g %s" "$(printf "scale=2; %i/1000000\n" "$CORE_VALUE" | bc -q)" "GHz"
  elif [ "$CORE_VALUE" -ge 1000 ] ; then
    printf "%g %s" "$(printf "scale=2; %i/1000\n" "$CORE_VALUE" | bc -q)" "MHz"
  else
    printf "%i %s" "$CORE_VALUE" "kHz"
  fi
}


#
# Configuration files
#

[ -e "$SYSTEM_CONFIG_FILE" ] && . "$SYSTEM_CONFIG_FILE"
[ -e "$USER_CONFIG_FILE" ] && . "$USER_CONFIG_FILE"


#
# Options processing
#

while getopts "r:vdh" OPTION ; do
  case $OPTION in
    r) REFRESH="$OPTARG" ;;
    v) enable_verbose ;;
    d) enable_debug ;;
    h) print_usage ; exit 0 ;;
    *) print_usage ; exit 1 ;;
  esac
done ; shift $((OPTIND-1))
print_debug "REFRESH=$REFRESH"


#
# Checks
#

[ -d /sys/devices/system/cpu/cpufreq ] || die "CPU frequency scaling disabled"


#
# MAIN
#

# Interrupt from keyboard *is* expected
trap - INT

# CPUs
CPU_MAX=$(cut -d "-" -f 2 < /sys/devices/system/cpu/online)
print_debug "CPU_MAX=$CPU_MAX"

# Main loop
while true ; do 
  [ "$DEBUG" -eq 0 ] && clear

  # Columns headers
  printf "%-5s%-15s%-20s%-20s%-10s%-10s\n\n" "CPU" "Governor" "Current: kernel" "Current: real" "Minimum" "Maximum"

  # Loop through all CPUs
  CPU=0 ; while [ "$CPU" -le "$CPU_MAX" ] ; do
    print_debug "CPU=$CPU"

    # Data path for this CPU
    FREQ_FILE_PATH="/sys/devices/system/cpu/cpu${CPU}/cpufreq"
    print_debug "FREQ_FILE_PATH=$FREQ_FILE_PATH"

    # Get values
    GOVERNOR="$(cat "$FREQ_FILE_PATH/scaling_governor")"
    MIN_FREQ="$(cat "$FREQ_FILE_PATH/scaling_min_freq")"
    MAX_FREQ="$(cat "$FREQ_FILE_PATH/scaling_max_freq")"
    CUR_FREQ="$(cat "$FREQ_FILE_PATH/scaling_cur_freq")"
    [ "$USER" = "root" ] && HARD_FREQ="$(cat "$FREQ_FILE_PATH/cpuinfo_cur_freq")"
    print_debug "GOVERNOR=$GOVERNOR" "MIN_FREQ=$MIN_FREQ" "MAX_FREQ=$MAX_FREQ" "CUR_FREQ=$CUR_FREQ" "HARD_FREQ=$HARD_FREQ"

    # Display

    # CPU number
    printf "%-5s" "$CPU"

    # Governor
    printf "%-15s" "$GOVERNOR"

    # Frequency
    printf "%-20s" "$(convert_value "$CUR_FREQ") ($(printf "%i*100/%i\n" "$CUR_FREQ" "$MAX_FREQ" | bc -q)%)"

    # Hardware frequency (root-only)
    if [ "$USER" = "root" ] ; then
      printf "%-20s" "$(convert_value "$HARD_FREQ") ($(printf "%i*100/%i\n" "$HARD_FREQ" "$MAX_FREQ" | bc -q)%)"
    else
      printf "%-20s" "N/A"
    fi

    # Minimum frequency
    printf "%-10s" "$(convert_value "$MIN_FREQ")"

    # Maximum frequency
    printf "%-10s\n" "$(convert_value "$MAX_FREQ")"

    # Increment CPU number
    CPU=$((CPU+1))
  done

  printf "\nPress Ctrl-C to stop."
  sleep "$REFRESH"
done
