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