#!/bin/bash

# ----------------------------------------------------------------------------
# toggle-ht: toggle hyperthreading
# ----------------------------------------------------------------------------

# ==============================================================================
# constants {{{

readonly CPUS=(/sys/devices/system/cpu/cpu[0-9]*)

# toggle-ht version number
readonly VERSION=0.5.2

# end constants }}}
# ==============================================================================
# usage {{{

_usage() {
read -r -d '' _usage_string <<EOF
Usage:
  toggle-ht [-h|--help] <off|on>

Options:
  -h, --help  Show this help text

Commands:
  off         Disable hyperthreading
  on          Enable hyperthreading
EOF
echo "$_usage_string"
}

_POSITIONAL=()

while [[ $# -gt 0 ]]; do
  case "$1" in
    -h|--help)
      _usage
      exit 0
      ;;
    -v|--version)
      echo "$VERSION"
      exit 0
      ;;
    -*)
      # unknown option
      _usage
      exit 1
      ;;
    off|on)
      _POSITIONAL+=("$1")
      shift
      ;;
    *)
      # unknown command
      _usage
      exit 1
      ;;
  esac
done

if ! [[ "${#_POSITIONAL[@]}" == '1' ]]; then
  _usage
  exit 1
fi

# restore positional params
set -- "${_POSITIONAL[@]}"

# end usage }}}
# ==============================================================================

INFO() {
  echo -n "toggle-ht#info: $*"
}

INFO_N() {
  echo "toggle-ht#info: $*"
}

off() {
  local _cpuid
  local _thread1
  INFO_N 'Disabling hyperthreading'
  for _cpu in ${CPUS[@]}; do
    _cpuid="$(basename "$_cpu" | cut -b4-)"
    INFO "CPU$_cpuid "
    if [[ -e "$_cpu/online" ]]; then
      _thread1="$(cut -f1 -d, "$_cpu/topology/thread_siblings_list")"
      if [[ "$_cpuid" == "$_thread1" ]]; then
        echo '-> enable'
        echo '1' > "$_cpu/online"
      else
        echo '-> disable'
        echo '0' > "$_cpu/online"
      fi
    else
      # handle CPU0, which is always enabled
      echo '-> enable'
    fi
  done
}

on() {
  local _cpuid
  INFO_N 'Enabling hyperthreading'
  for _cpu in ${CPUS[@]}; do
    _cpuid="$(basename "$_cpu" | cut -b4-)"
    INFO "CPU$_cpuid "
    # handle CPU0, which is always enabled
    echo '-> enable'
    if [[ -e "$_cpu/online" ]]; then
      echo '1' > "$_cpu/online"
    fi
  done
}

main() {
  if ! [[ "$UID" == '0' ]]; then
    echo 'Sorry, requires root privileges'
    exit 1
  fi
  if [[ "$1" == 'off' ]]; then
    off
  elif [[ "$1" == 'on' ]]; then
    on
  else
    # unknown command
    _usage
    exit 1
  fi
}

main "$1"

# vim: set filetype=sh foldmethod=marker foldlevel=0 nowrap:
