#!/bin/bash # # Alternate sleeping and spinning on randomly selected CPUs. The purpose # of this script is to inflict random OS jitter on a concurrently running # test. # # Usage: jitter.sh me duration [ sleepmax [ spinmax ] ] # # me: Random-number-generator seed salt. # duration: Time to run in seconds. # sleepmax: Maximum microseconds to sleep, defaults to one second. # spinmax: Maximum microseconds to spin, defaults to one millisecond. # # 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 2 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, you can access it online at # http://www.gnu.org/licenses/gpl-2.0.html. # # Copyright (C) IBM Corporation, 2016 # # Authors: Paul E. McKenney global me := $($1 * 1000) global duration := $2 global sleepmax := $(3-1000000) global spinmax := $(4-1000) global n := '1' global starttime := $[awk 'BEGIN { print systime(); }' < /dev/null] while : { # Check for done. global t := $[awk -v s=$starttime 'BEGIN { print systime() - s; }' < /dev/null] if test $t -gt $duration { exit 0; } # Set affinity to randomly selected CPU global cpus := $[ls /sys/devices/system/cpu/*/online | sed -e 's,/[^/]*$,,' -e 's/^[^0-9]*//' | grep -v '^0*$] global cpumask := $[awk -v cpus="$cpus" -v me=$me -v n=$n 'BEGIN { srand(n + me + systime()); ncpus = split(cpus, ca); curcpu = ca[int(rand() * ncpus + 1)]; mask = lshift(1, curcpu); if (mask + 0 <= 0) mask = 1; printf("%#x\n", mask); }' < /dev/null] global n := $($n+1) if ! taskset -p $cpumask $Pid > /dev/null !2 > !1 { echo taskset failure: '"taskset -p ' $cpumask $Pid '"' exit 1 } # Sleep a random duration global sleeptime := $[awk -v me=$me -v n=$n -v sleepmax=$sleepmax 'BEGIN { srand(n + me + systime()); printf("%06d", int(rand() * sleepmax)); }' < /dev/null] global n := $($n+1) sleep .$sleeptime # Spin a random duration global limit := $[awk -v me=$me -v n=$n -v spinmax=$spinmax 'BEGIN { srand(n + me + systime()); printf("%06d", int(rand() * spinmax)); }' < /dev/null] global n := $($n+1) for i in [{1..$limit}] { echo > /dev/null } } exit 1 (CommandList children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:me) op: Equal rhs: { (ArithSubPart anode: (ArithBinary op_id: Arith_Star left: (ArithWord w:{($ VSub_Number "$1")}) right: (ArithWord w:{(Lit_Digits 1000)}) ) spids: [92 99] ) } spids: [91] ) ] spids: [91] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:duration) op: Equal rhs: {($ VSub_Number "$2")} spids: [101] ) ] spids: [101] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:sleepmax) op: Equal rhs: { (BracedVarSub token: suffix_op: (StringUnary op_id:VTest_Hyphen arg_word:{(1000000)}) spids: [105 109] ) } spids: [104] ) ] spids: [104] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:spinmax) op: Equal rhs: { (BracedVarSub token: suffix_op: (StringUnary op_id:VTest_Hyphen arg_word:{(1000)}) spids: [112 116] ) } spids: [111] ) ] spids: [111] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:n) op:Equal rhs:{(1)} spids:[119])] spids: [119] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:starttime) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (SimpleCommand words: [{(awk)} {(SQ <"BEGIN { print systime(); }">)}] redirects: [(Redir op_id:Redir_Less fd:-1 arg_word:{(/dev/null)} spids:[131])] ) ] ) left_token: spids: [124 134] ) } spids: [123] ) ] spids: [123] ) (While cond: [(C {(Lit_Other ":")})] body: (DoGroup children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:t) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (SimpleCommand words: [ {(awk)} {(-v)} {(Lit_VarLike "s=") ($ VSub_Name "$starttime")} {(SQ <"BEGIN { print systime() - s; }">)} ] redirects: [ (Redir op_id: Redir_Less fd: -1 arg_word: {(/dev/null)} spids: [161] ) ] ) ] ) left_token: spids: [149 164] ) } spids: [148] ) ] spids: [148] ) (If arms: [ (if_arm cond: [(C {(test)} {(DQ ($ VSub_Name "$t"))} {(-gt)} {(DQ ($ VSub_Name "$duration"))})] action: [(Sentence child:(C {(exit)} {(0)}) terminator:)] spids: [-1 182] ) ] spids: [-1 191] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:cpus) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (Pipeline children: [ (C {(ls)} {(/sys/devices/system/cpu/) (Lit_Other "*") (/online)}) (C {(sed)} {(-e)} {(SQ <"s,/[^/]*$,,">)} {(-e)} {(SQ <"s/^[^0-9]*//">)}) (C {(grep)} {(-v)} {(SQ <"^0*$">)}) ] negated: False ) ] ) left_token: spids: [200 234] ) } spids: [199] ) ] spids: [199] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:cpumask) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (SimpleCommand words: [ {(awk)} {(-v)} {(Lit_VarLike "cpus=") (DQ ($ VSub_Name "$cpus"))} {(-v)} {(Lit_VarLike "me=") ($ VSub_Name "$me")} {(-v)} {(Lit_VarLike "n=") ($ VSub_Name "$n")} { (SQ <"BEGIN {\n"> <"\t\tsrand(n + me + systime());\n"> <"\t\tncpus = split(cpus, ca);\n"> <"\t\tcurcpu = ca[int(rand() * ncpus + 1)];\n"> <"\t\tmask = lshift(1, curcpu);\n"> <"\t\tif (mask + 0 <= 0)\n"> <"\t\t\tmask = 1;\n"> <"\t\tprintf(\"%#x\\n\", mask);\n"> <"\t}"> ) } ] redirects: [ (Redir op_id: Redir_Less fd: -1 arg_word: {(/dev/null)} spids: [270] ) ] ) ] ) left_token: spids: [238 273] ) } spids: [237] ) ] spids: [237] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:n) op: Equal rhs: { (ArithSubPart anode: (ArithBinary op_id: Arith_Plus left: (ArithWord w:{($ VSub_Name "$n")}) right: (ArithWord w:{(Lit_Digits 1)}) ) spids: [277 282] ) } spids: [276] ) ] spids: [276] ) (If arms: [ (if_arm cond: [ (Pipeline children: [ (SimpleCommand words: [{(taskset)} {(-p)} {($ VSub_Name "$cpumask")} {($ VSub_Dollar "$$")}] redirects: [ (Redir op_id: Redir_Great fd: -1 arg_word: {(/dev/null)} spids: [297] ) (Redir op_id: Redir_GreatAnd fd: 2 arg_word: {(1)} spids: [301] ) ] ) ] negated: True ) ] action: [ (C {(echo)} {(taskset)} {(failure) (Lit_Other ":")} {(SQ <"\"taskset -p ">)} {($ VSub_Name "$cpumask")} {($ VSub_Dollar "$$")} {(SQ <"\"">)} ) (C {(exit)} {(1)}) ] spids: [-1 305] ) ] spids: [-1 333] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:sleeptime) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (SimpleCommand words: [ {(awk)} {(-v)} {(Lit_VarLike "me=") ($ VSub_Name "$me")} {(-v)} {(Lit_VarLike "n=") ($ VSub_Name "$n")} {(-v)} {(Lit_VarLike "sleepmax=") ($ VSub_Name "$sleepmax")} { (SQ <"BEGIN {\n"> <"\t\tsrand(n + me + systime());\n"> <"\t\tprintf(\"%06d\", int(rand() * sleepmax));\n"> <"\t}"> ) } ] redirects: [ (Redir op_id: Redir_Less fd: -1 arg_word: {(/dev/null)} spids: [367] ) ] ) ] ) left_token: spids: [342 370] ) } spids: [341] ) ] spids: [341] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:n) op: Equal rhs: { (ArithSubPart anode: (ArithBinary op_id: Arith_Plus left: (ArithWord w:{($ VSub_Name "$n")}) right: (ArithWord w:{(Lit_Digits 1)}) ) spids: [374 379] ) } spids: [373] ) ] spids: [373] ) (C {(sleep)} {(.) ($ VSub_Name "$sleeptime")}) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:limit) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (SimpleCommand words: [ {(awk)} {(-v)} {(Lit_VarLike "me=") ($ VSub_Name "$me")} {(-v)} {(Lit_VarLike "n=") ($ VSub_Name "$n")} {(-v)} {(Lit_VarLike "spinmax=") ($ VSub_Name "$spinmax")} { (SQ <"BEGIN {\n"> <"\t\tsrand(n + me + systime());\n"> <"\t\tprintf(\"%06d\", int(rand() * spinmax));\n"> <"\t}"> ) } ] redirects: [ (Redir op_id: Redir_Less fd: -1 arg_word: {(/dev/null)} spids: [419] ) ] ) ] ) left_token: spids: [394 422] ) } spids: [393] ) ] spids: [393] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:n) op: Equal rhs: { (ArithSubPart anode: (ArithBinary op_id: Arith_Plus left: (ArithWord w:{($ VSub_Name "$n")}) right: (ArithWord w:{(Lit_Digits 1)}) ) spids: [426 431] ) } spids: [425] ) ] spids: [425] ) (ForEach iter_name: i iter_words: [{(Lit_LBrace "{") (1..) ($ VSub_Name "$limit") (Lit_RBrace "}")}] do_arg_iter: False body: (DoGroup children: [ (SimpleCommand words: [{(echo)}] redirects: [(Redir op_id:Redir_Great fd:-1 arg_word:{(/dev/null)} spids:[451])] ) ] spids: [446 456] ) spids: [439 -1] ) ] spids: [141 458] ) ) (C {(exit)} {(1)}) ] )