Jump to content

systemwide cpu-limiter for debugging [script, linux only, attached]


Recommended Posts

Hi there,

I’ve written a script that limits the available CPU cores and frequencies to user defined values.

Purpose is simulating a slow CPU for testing multithreading performance/mutex locking behaviour on those systems.

This script temporarily turns your high-performance 12core i7 CPU into a slow single-core or dual-core cpu (or whatever you specify)

by disabling cpu cores and limiting the minimum and maximum frequencies of the remaining cores

Disabling 5/6 cores of a 6-core CPU doesn’t exactly give the performance of a single-core CPU with same clock speed(since the multi-core CPU isn’t designed to run that way) but at least it should give some usable approximation.

The script is designed to run in another terminal window. After changing your system, it waits for the user to say "exit" by pressing [Return], and restores everything to the original values(re-enables disabled CPU cores and restores original min/max clock speeds).

It (temporarily) modifies your system, so it has to be run as root user(so check the script first before running it!)

I’ve written 2 variations:

cpu_limiter.sh is interactive and asks the user for input values. It tells you which values are available on your system and checks if the entered values are valid. (it’s not completely failsafe though)

cpu_limiter_plain.sh requires those values as parameters, calling it without any gives a short usage information and prints the available values on your system. This one does not check anything, but assumes you are calling it with correct/working values!

I tested both versions on my system, they are fully working(otherwise i would not have released it)

(my system: Kubuntu 12.10, AMD Phenom II X6 CPU(6 cores))

But I did NOT test what happens, if you feed the plain version with bad arguments(text strings, negative/very high numbers etc.)… just don’t do that! :wink2:

Download:

cpu_limiter.zip

Plaintext version(in the Spoiler):

cpu_limiter.sh:


#!/bin/bash

# cpu_limiter.sh is a bash script to limit the cpu power to specified values
# Copyright (C) 2013 Thomas Hess
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.



# checks if value is element in the array
function contains()
{
local n=$#
local value=${!n}
for ((i=1;i < $#;i++))
{
if [ "${!i}" == "${value}" ]; then
return 0
fi
}
return 1
}

#gather information needed to restore things
num_cpu_in_system=$(grep processor /proc/cpuinfo | wc -l)
num_requested_cpus=1
for((x=0; x<$num_cpu_in_system;x++))
{
cpu_freq_max[x]=$(cat /sys/devices/system/cpu/cpu$x/cpufreq/cpuinfo_max_freq)
cpu_freq_min[x]=$(cat /sys/devices/system/cpu/cpu$x/cpufreq/cpuinfo_min_freq)
cpu_freq_avail[x]=$(cat /sys/devices/system/cpu/cpu$x/cpufreq/scaling_available_frequencies)
}
cpu_frequencies=(${cpu_freq_avail[0]})


echo "Number of CPUs in your System: $num_cpu_in_system"
echo "Maximal CPU frequency(First CPU, in kHz): ${cpu_freq_max[0]}"
echo "Minimal CPU frequency(First CPU, in kHz): ${cpu_freq_min[0]}"
echo "Available CPU frequencies (First CPU, in kHz): ${cpu_freq_avail[0]}"


echo "Enter the number of supposed to be running CPUS: (values between 1 and $num_cpu_in_system allowed"
echo "e.g. want a singlecore? enter 1 [Return]; want a dualcore? enter 2 [Return]"
read num_requested_cpus

while [ "${num_requested_cpus:-0}" -gt "$num_cpu_in_system" ] || [ "${num_requested_cpus:-0}" -le "0" ]; do
echo "Cannot create virtual CPUs or use 0/negative number of CPUS"
echo "Enter a value between 1 and $num_cpu_in_system (both including)"
read num_requested_cpus
done


echo "Your CPU supports the following CPU frequencies(in kHz): ${cpu_frequencies[@]}"
echo "Enter the minimal CPU speed to use:"
read use_minimal_cpu_freq
while ! contains "${cpu_frequencies[@]}" "${use_minimal_cpu_freq:-0}" ; do
echo "Enter a valid value:"
read use_minimal_cpu_freq
done

echo "Enter the maximal CPU speed to use:"
read use_maximal_cpu_freq
while ! contains "${cpu_frequencies[@]}" "${use_maximal_cpu_freq:-0}" || [ "${use_maximal_cpu_freq:-0}" -lt "$use_minimal_cpu_freq" ] ; do
echo "Enter a valid value: (greater than or equal to the minimal frequency)"
read use_maximal_cpu_freq
done

echo "Information collection done!"
echo "Number of requested CPUs: $num_requested_cpus"
echo "new minimal CPU frequency: $use_minimal_cpu_freq "
echo "new maximal CPU frequency: $use_maximal_cpu_freq"

for((x=$num_requested_cpus; x < num_cpu_in_system; x++))
{
echo ${cpu_freq_min[x]} > /sys/devices/system/cpu/cpu$x/cpufreq/scaling_max_freq
echo 0 > /sys/devices/system/cpu/cpu$x/online
}
for((x=0; x<$num_requested_cpus; x++))
{
echo $use_minimal_cpu_freq > /sys/devices/system/cpu/cpu$x/cpufreq/scaling_min_freq
echo $use_maximal_cpu_freq > /sys/devices/system/cpu/cpu$x/cpufreq/scaling_max_freq
}

echo "Press [Return] to restore your CPU configuration and exit"
read

for((x=$num_requested_cpus; x < num_cpu_in_system; x++))
{
echo 1 > /sys/devices/system/cpu/cpu$x/online
}

for((x=0; x < num_cpu_in_system; x++))
{
echo ${cpu_freq_min[x]} > /sys/devices/system/cpu/cpu$x/cpufreq/scaling_min_freq
echo ${cpu_freq_max[x]} > /sys/devices/system/cpu/cpu$x/cpufreq/scaling_max_freq
}

echo "Done"

cpu_limiter_plain.sh


#!/bin/bash

# cpu_limiter_plain.sh is a bash script to limit the cpu power to specified values
# Copyright (C) 2013 Thomas Hess
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.


# 3 Parameters:
# 1: number of to-be running CPUs
# 2: minimal CPU frequency
# 3: maximal CPU frequency


# checks if value is element in the array
function contains()
{
local n=$#
local value=${!n}
for ((i=1;i < $#;i++))
{
if [ "${!i}" == "${value}" ]; then
return 0
fi
}
return 1
}

#gather information needed to restore things
num_cpu_in_system=$(grep processor /proc/cpuinfo | wc -l)
for((x=0; x<$num_cpu_in_system;x++))
{
cpu_freq_max[x]=$(cat /sys/devices/system/cpu/cpu$x/cpufreq/cpuinfo_max_freq)
cpu_freq_min[x]=$(cat /sys/devices/system/cpu/cpu$x/cpufreq/cpuinfo_min_freq)
cpu_freq_avail[x]=$(cat /sys/devices/system/cpu/cpu$x/cpufreq/scaling_available_frequencies)
}
cpu_frequencies=(${cpu_freq_avail[0]})

if [ $# -eq "3" ]; then
echo "Number of CPUs in your System: $num_cpu_in_system, will be set to $1"
echo "Available CPU frequencies (First CPU, in kHz): ${cpu_freq_avail[0]}"
echo "Maximal CPU frequency(First CPU, in kHz): ${cpu_freq_max[0]}, will be set to $3"
echo "Minimal CPU frequency(First CPU, in kHz): ${cpu_freq_min[0]}, will be set to $2"

num_requested_cpus="$1"
use_minimal_cpu_freq="$2"
use_maximal_cpu_freq=" $3"

for((x=$num_requested_cpus; x < num_cpu_in_system; x++))
{
echo ${cpu_freq_min[x]} > /sys/devices/system/cpu/cpu$x/cpufreq/scaling_max_freq
echo 0 > /sys/devices/system/cpu/cpu$x/online
}
for((x=0; x<$num_requested_cpus; x++))
{
echo $use_minimal_cpu_freq > /sys/devices/system/cpu/cpu$x/cpufreq/scaling_min_freq
echo $use_maximal_cpu_freq > /sys/devices/system/cpu/cpu$x/cpufreq/scaling_max_freq
}

echo "Press [Return] to restore your CPU configuration and exit"
read

for((x=$num_requested_cpus; x < num_cpu_in_system; x++))
{
echo 1 > /sys/devices/system/cpu/cpu$x/online
}

for((x=0; x < num_cpu_in_system; x++))
{
echo ${cpu_freq_min[x]} > /sys/devices/system/cpu/cpu$x/cpufreq/scaling_min_freq
echo ${cpu_freq_max[x]} > /sys/devices/system/cpu/cpu$x/cpufreq/scaling_max_freq
}
echo "Done"
else
echo "invoke this script with 3 Parameters"
echo "1: number of to-be running CPUs"
echo "2: minimal CPU frequency(in kHz)"
echo "3: maximal CPU frequency(in kHz)"
echo "Allowed values on your system:"
echo "CPU-number: 1 to $num_cpu_in_system"
echo "frequencies(both maximum and minimum): one of ${cpu_frequencies[@]}"
echo "Example: $0 1 ${cpu_frequencies[0]} ${cpu_frequencies[0]}"
fi

I hope that it will be useful for someone

Link to comment
Share on other sites

Thanks, this sounds useful for testing the threaded stuff. Do you know roughly how dangerous would it be to feed bad values into the script?

I’ve written it for exactly this purpose :wink2:

I’ve tested it:(that happens with my AMD CPU, with vendors it should be the same)

  • you cannot disable cpu 0; trying to do so gives a file-not-found error
  • you cannot use too low values as clock speed; "bad argument"
  • you can use too high values as clock speed; nothing happens, it does not overclock, but simply uses your maximum cpu clock speed
    at least my system monitor told me that, be careful with this one
  • using minimum_frequency>maximum_frequency gives a "bad argument" error

so it should be safe to use, but i recommend using proper values (the script prints them out when calling it without arguments)

other than that:

if you really cut your cpu down, your system will get really slow!

I can reduce my cpu power from 6*2,8GHz to 1*800Mhz. You can feel the effect immediately :wink2:

with 1*800MHz, the rendering in 0ad(latest dev ppa build) completely freezes (but hey, music continues nicely!)

Edited by luziferius
Link to comment
Share on other sites

I can reduce my cpu power from 6*2,8GHz to 1*800Mhz. You can feel the effect immediately :wink2:

with 1*800MHz, the rendering in 0ad(latest dev ppa build) completely freezes (but hey, music continues nicely!)

Are you using the latest svn trunk? I was hoping the fixes in there made the music less obtrusive. If you are we can adjust the sleep parameters to tone it down even more.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...