#!/bin/bash
# SPDX-License-Identifier: GPL-3.0+
# Copyright (C) 2017 Omar Sandoval
#
# Hotplug CPUs online and offline while we do IO.

. tests/block/rc
. common/cpuhotplug

DESCRIPTION="do IO while hotplugging CPUs"
TIMED=1

requires() {
	_have_cpu_hotplug && _have_fio
}

test_device() {
	echo "Running ${TEST_NAME}"

	if _test_dev_is_rotational; then
		size="32m"
	else
		size="1g"
	fi

	# Start fio job. When using the default cpu clocksource, fio does some
	# sched_setaffinity() calls, which may race with our hotplugging. Use
	# the clock_gettime clocksource to avoid that.
	_run_fio_rand_io --filename="$TEST_DEV" --size="$size" --clocksource=clock_gettime &


	local online_cpus=()
	local offline_cpus=()
	local offlining=1
	local max_offline=${#HOTPLUGGABLE_CPUS[@]}
	if [[ ${#HOTPLUGGABLE_CPUS[@]} -eq ${#ALL_CPUS[@]} ]]; then
		(( max_offline-- ))
	fi
	for cpu in "${HOTPLUGGABLE_CPUS[@]}"; do
		if (( "$(cat "/sys/devices/system/cpu/cpu${cpu}/online")" )); then
			online_cpus+=("$cpu")
		else
			offline_cpus+=("$cpu")
		fi
	done

	# while job is running, hotplug CPUs
	while sleep .2; kill -0 $! 2> /dev/null; do
		if (( offlining && ${#offline_cpus[@]} == max_offline )); then
			offlining=0
		elif (( ! offlining && ${#online_cpus[@]} == ${#HOTPLUGGABLE_CPUS[@]} )); then
			offlining=1
		fi

		if (( offlining )); then
			idx=$((RANDOM % ${#online_cpus[@]}))
			_offline_cpu "${online_cpus[$idx]}"
			offline_cpus+=("${online_cpus[$idx]}")
			unset online_cpus["$idx"]
			online_cpus=("${online_cpus[@]}")
		else
			idx=$((RANDOM % ${#offline_cpus[@]}))
			_online_cpu "${offline_cpus[$idx]}"
			online_cpus+=("${offline_cpus[$idx]}")
			unset offline_cpus["$idx"]
			offline_cpus=("${offline_cpus[@]}")
		fi
	done

	FIO_PERF_FIELDS=("read iops")
	_fio_perf_report

	echo "Test complete"
}
