jitter.sh 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0+
  3. #
  4. # Alternate sleeping and spinning on randomly selected CPUs. The purpose
  5. # of this script is to inflict random OS jitter on a concurrently running
  6. # test.
  7. #
  8. # Usage: jitter.sh me jittering-path duration [ sleepmax [ spinmax ] ]
  9. #
  10. # me: Random-number-generator seed salt.
  11. # duration: Time to run in seconds.
  12. # jittering-path: Path to file whose removal will stop this script.
  13. # sleepmax: Maximum microseconds to sleep, defaults to one second.
  14. # spinmax: Maximum microseconds to spin, defaults to one millisecond.
  15. #
  16. # Copyright (C) IBM Corporation, 2016
  17. #
  18. # Authors: Paul E. McKenney <paulmck@linux.ibm.com>
  19. me=$(($1 * 1000))
  20. jittering=$2
  21. duration=$3
  22. sleepmax=${4-1000000}
  23. spinmax=${5-1000}
  24. n=1
  25. starttime=`gawk 'BEGIN { print systime(); }' < /dev/null`
  26. nohotplugcpus=
  27. for i in /sys/devices/system/cpu/cpu[0-9]*
  28. do
  29. if test -f $i/online
  30. then
  31. :
  32. else
  33. curcpu=`echo $i | sed -e 's/^[^0-9]*//'`
  34. nohotplugcpus="$nohotplugcpus $curcpu"
  35. fi
  36. done
  37. # Uses global variables startsecs, startns, endsecs, endns, and limit.
  38. # Exit code is success for time not yet elapsed and failure otherwise.
  39. function timecheck {
  40. local done=`awk -v limit=$limit \
  41. -v startsecs=$startsecs \
  42. -v startns=$startns \
  43. -v endsecs=$endsecs \
  44. -v endns=$endns < /dev/null '
  45. BEGIN {
  46. delta = (endsecs - startsecs) * 1000 * 1000;
  47. delta += int((endns - startns) / 1000);
  48. print delta >= limit;
  49. }'`
  50. return $done
  51. }
  52. while :
  53. do
  54. # Check for done.
  55. t=`gawk -v s=$starttime 'BEGIN { print systime() - s; }' < /dev/null`
  56. if test "$t" -gt "$duration"
  57. then
  58. exit 0;
  59. fi
  60. # Check for stop request.
  61. if ! test -f "$jittering"
  62. then
  63. exit 1;
  64. fi
  65. # Set affinity to randomly selected online CPU
  66. if cpus=`grep 1 /sys/devices/system/cpu/*/online 2>&1 |
  67. sed -e 's,/[^/]*$,,' -e 's/^[^0-9]*//'`
  68. then
  69. :
  70. else
  71. cpus=
  72. fi
  73. # Do not leave out non-hot-pluggable CPUs
  74. cpus="$cpus $nohotplugcpus"
  75. cpumask=`awk -v cpus="$cpus" -v me=$me -v n=$n 'BEGIN {
  76. srand(n + me + systime());
  77. ncpus = split(cpus, ca);
  78. print ca[int(rand() * ncpus + 1)];
  79. }' < /dev/null`
  80. n=$(($n+1))
  81. if ! taskset -c -p $cpumask $$ > /dev/null 2>&1
  82. then
  83. echo taskset failure: '"taskset -c -p ' $cpumask $$ '"'
  84. exit 1
  85. fi
  86. # Sleep a random duration
  87. sleeptime=`awk -v me=$me -v n=$n -v sleepmax=$sleepmax 'BEGIN {
  88. srand(n + me + systime());
  89. printf("%06d", int(rand() * sleepmax));
  90. }' < /dev/null`
  91. n=$(($n+1))
  92. sleep .$sleeptime
  93. # Spin a random duration, but with rather coarse granularity.
  94. limit=`awk -v me=$me -v n=$n -v spinmax=$spinmax 'BEGIN {
  95. srand(n + me + systime());
  96. printf("%06d", int(rand() * spinmax));
  97. }' < /dev/null`
  98. n=$(($n+1))
  99. startsecs=`date +%s`
  100. startns=`date +%N`
  101. endsecs=$startns
  102. endns=$endns
  103. while timecheck
  104. do
  105. endsecs=`date +%s`
  106. endns=`date +%N`
  107. done
  108. done
  109. exit 1