1#!/bin/bash 2# 3# Alternate sleeping and spinning on randomly selected CPUs. The purpose 4# of this script is to inflict random OS jitter on a concurrently running 5# test. 6# 7# Usage: jitter.sh me duration [ sleepmax [ spinmax ] ] 8# 9# me: Random-number-generator seed salt. 10# duration: Time to run in seconds. 11# sleepmax: Maximum microseconds to sleep, defaults to one second. 12# spinmax: Maximum microseconds to spin, defaults to one millisecond. 13# 14# This program is free software; you can redistribute it and/or modify 15# it under the terms of the GNU General Public License as published by 16# the Free Software Foundation; either version 2 of the License, or 17# (at your option) any later version. 18# 19# This program is distributed in the hope that it will be useful, 20# but WITHOUT ANY WARRANTY; without even the implied warranty of 21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22# GNU General Public License for more details. 23# 24# You should have received a copy of the GNU General Public License 25# along with this program; if not, you can access it online at 26# http://www.gnu.org/licenses/gpl-2.0.html. 27# 28# Copyright (C) IBM Corporation, 2016 29# 30# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 31 32me=$(($1 * 1000)) 33duration=$2 34sleepmax=${3-1000000} 35spinmax=${4-1000} 36 37n=1 38 39starttime=`awk 'BEGIN { print systime(); }' < /dev/null` 40 41while : 42do 43 # Check for done. 44 t=`awk -v s=$starttime 'BEGIN { print systime() - s; }' < /dev/null` 45 if test "$t" -gt "$duration" 46 then 47 exit 0; 48 fi 49 50 # Set affinity to randomly selected CPU 51 cpus=`ls /sys/devices/system/cpu/*/online | 52 sed -e 's,/[^/]*$,,' -e 's/^[^0-9]*//' | 53 grep -v '^0*$'` 54 cpumask=`awk -v cpus="$cpus" -v me=$me -v n=$n 'BEGIN { 55 srand(n + me + systime()); 56 ncpus = split(cpus, ca); 57 curcpu = ca[int(rand() * ncpus + 1)]; 58 mask = lshift(1, curcpu); 59 if (mask + 0 <= 0) 60 mask = 1; 61 printf("%#x\n", mask); 62 }' < /dev/null` 63 n=$(($n+1)) 64 if ! taskset -p $cpumask $$ > /dev/null 2>&1 65 then 66 echo taskset failure: '"taskset -p ' $cpumask $$ '"' 67 exit 1 68 fi 69 70 # Sleep a random duration 71 sleeptime=`awk -v me=$me -v n=$n -v sleepmax=$sleepmax 'BEGIN { 72 srand(n + me + systime()); 73 printf("%06d", int(rand() * sleepmax)); 74 }' < /dev/null` 75 n=$(($n+1)) 76 sleep .$sleeptime 77 78 # Spin a random duration 79 limit=`awk -v me=$me -v n=$n -v spinmax=$spinmax 'BEGIN { 80 srand(n + me + systime()); 81 printf("%06d", int(rand() * spinmax)); 82 }' < /dev/null` 83 n=$(($n+1)) 84 for i in {1..$limit} 85 do 86 echo > /dev/null 87 done 88done 89 90exit 1 91