Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'lkmm-scripting.2023.04.07a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu

Pull Linux Kernel Memory Model scripting updates from Paul McKenney:
"This improves litmus-test documentation and improves the ability to do
before/after tests on the https://github.com/paulmckrcu/litmus repo"

* tag 'lkmm-scripting.2023.04.07a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: (32 commits)
tools/memory-model: Remove out-of-date SRCU documentation
tools/memory-model: Document LKMM test procedure
tools/memory-model: Use "grep -E" instead of "egrep"
tools/memory-model: Use "-unroll 0" to keep --hw runs finite
tools/memory-model: Make judgelitmus.sh handle scripted Result: tag
tools/memory-model: Add data-race capabilities to judgelitmus.sh
tools/memory-model: Add checktheselitmus.sh to run specified litmus tests
tools/memory-model: Repair parseargs.sh header comment
tools/memory-model: Add "--" to parseargs.sh for additional arguments
tools/memory-model: Make history-check scripts use mselect7
tools/memory-model: Make checkghlitmus.sh use mselect7
tools/memory-model: Fix scripting --jobs argument
tools/memory-model: Implement --hw support for checkghlitmus.sh
tools/memory-model: Add -v flag to jingle7 runs
tools/memory-model: Make runlitmus.sh check for jingle errors
tools/memory-model: Allow herd to deduce CPU type
tools/memory-model: Keep assembly-language litmus tests
tools/memory-model: Move from .AArch64.litmus.out to .litmus.AArch.out
tools/memory-model: Make runlitmus.sh generate .litmus.out for --hw
tools/memory-model: Split runlitmus.sh out of checklitmus.sh
...

+924 -116
+54
Documentation/litmus-tests/locking/DCL-broken.litmus
··· 1 + C DCL-broken 2 + 3 + (* 4 + * Result: Sometimes 5 + * 6 + * This litmus test demonstrates more than just locking is required to 7 + * correctly implement double-checked locking. 8 + *) 9 + 10 + { 11 + int flag; 12 + int data; 13 + } 14 + 15 + P0(int *flag, int *data, spinlock_t *lck) 16 + { 17 + int r0; 18 + int r1; 19 + int r2; 20 + 21 + r0 = READ_ONCE(*flag); 22 + if (r0 == 0) { 23 + spin_lock(lck); 24 + r1 = READ_ONCE(*flag); 25 + if (r1 == 0) { 26 + WRITE_ONCE(*data, 1); 27 + WRITE_ONCE(*flag, 1); 28 + } 29 + spin_unlock(lck); 30 + } 31 + r2 = READ_ONCE(*data); 32 + } 33 + 34 + P1(int *flag, int *data, spinlock_t *lck) 35 + { 36 + int r0; 37 + int r1; 38 + int r2; 39 + 40 + r0 = READ_ONCE(*flag); 41 + if (r0 == 0) { 42 + spin_lock(lck); 43 + r1 = READ_ONCE(*flag); 44 + if (r1 == 0) { 45 + WRITE_ONCE(*data, 1); 46 + WRITE_ONCE(*flag, 1); 47 + } 48 + spin_unlock(lck); 49 + } 50 + r2 = READ_ONCE(*data); 51 + } 52 + 53 + locations [flag;data;0:r0;0:r1;1:r0;1:r1] 54 + exists (0:r2=0 \/ 1:r2=0)
+55
Documentation/litmus-tests/locking/DCL-fixed.litmus
··· 1 + C DCL-fixed 2 + 3 + (* 4 + * Result: Never 5 + * 6 + * This litmus test demonstrates that double-checked locking can be 7 + * reliable given proper use of smp_load_acquire() and smp_store_release() 8 + * in addition to the locking. 9 + *) 10 + 11 + { 12 + int flag; 13 + int data; 14 + } 15 + 16 + P0(int *flag, int *data, spinlock_t *lck) 17 + { 18 + int r0; 19 + int r1; 20 + int r2; 21 + 22 + r0 = smp_load_acquire(flag); 23 + if (r0 == 0) { 24 + spin_lock(lck); 25 + r1 = READ_ONCE(*flag); 26 + if (r1 == 0) { 27 + WRITE_ONCE(*data, 1); 28 + smp_store_release(flag, 1); 29 + } 30 + spin_unlock(lck); 31 + } 32 + r2 = READ_ONCE(*data); 33 + } 34 + 35 + P1(int *flag, int *data, spinlock_t *lck) 36 + { 37 + int r0; 38 + int r1; 39 + int r2; 40 + 41 + r0 = smp_load_acquire(flag); 42 + if (r0 == 0) { 43 + spin_lock(lck); 44 + r1 = READ_ONCE(*flag); 45 + if (r1 == 0) { 46 + WRITE_ONCE(*data, 1); 47 + smp_store_release(flag, 1); 48 + } 49 + spin_unlock(lck); 50 + } 51 + r2 = READ_ONCE(*data); 52 + } 53 + 54 + locations [flag;data;0:r0;0:r1;1:r0;1:r1] 55 + exists (0:r2=0 \/ 1:r2=0)
+41
Documentation/litmus-tests/locking/RM-broken.litmus
··· 1 + C RM-broken 2 + 3 + (* 4 + * Result: DEADLOCK 5 + * 6 + * This litmus test demonstrates that the old "roach motel" approach 7 + * to locking, where code can be freely moved into critical sections, 8 + * cannot be used in the Linux kernel. 9 + *) 10 + 11 + { 12 + int x; 13 + atomic_t y; 14 + } 15 + 16 + P0(int *x, atomic_t *y, spinlock_t *lck) 17 + { 18 + int r2; 19 + 20 + spin_lock(lck); 21 + r2 = atomic_inc_return(y); 22 + WRITE_ONCE(*x, 1); 23 + spin_unlock(lck); 24 + } 25 + 26 + P1(int *x, atomic_t *y, spinlock_t *lck) 27 + { 28 + int r0; 29 + int r1; 30 + int r2; 31 + 32 + spin_lock(lck); 33 + r0 = READ_ONCE(*x); 34 + r1 = READ_ONCE(*x); 35 + r2 = atomic_inc_return(y); 36 + spin_unlock(lck); 37 + } 38 + 39 + locations [x;0:r2;1:r0;1:r1;1:r2] 40 + filter (1:r0=0 /\ 1:r1=1) 41 + exists (1:r2=1)
+41
Documentation/litmus-tests/locking/RM-fixed.litmus
··· 1 + C RM-fixed 2 + 3 + (* 4 + * Result: Never 5 + * 6 + * This litmus test demonstrates that the old "roach motel" approach 7 + * to locking, where code can be freely moved into critical sections, 8 + * cannot be used in the Linux kernel. 9 + *) 10 + 11 + { 12 + int x; 13 + atomic_t y; 14 + } 15 + 16 + P0(int *x, atomic_t *y, spinlock_t *lck) 17 + { 18 + int r2; 19 + 20 + spin_lock(lck); 21 + r2 = atomic_inc_return(y); 22 + WRITE_ONCE(*x, 1); 23 + spin_unlock(lck); 24 + } 25 + 26 + P1(int *x, atomic_t *y, spinlock_t *lck) 27 + { 28 + int r0; 29 + int r1; 30 + int r2; 31 + 32 + r0 = READ_ONCE(*x); 33 + r1 = READ_ONCE(*x); 34 + spin_lock(lck); 35 + r2 = atomic_inc_return(y); 36 + spin_unlock(lck); 37 + } 38 + 39 + locations [x;0:r2;1:r0;1:r1;1:r2] 40 + filter (1:r0=0 /\ 1:r1=1) 41 + exists (1:r2=1)
+1 -26
tools/memory-model/Documentation/litmus-tests.txt
··· 1028 1028 additional call_rcu() process to the site of the 1029 1029 emulated rcu-barrier(). 1030 1030 1031 - e. Although sleepable RCU (SRCU) is now modeled, there 1032 - are some subtle differences between its semantics and 1033 - those in the Linux kernel. For example, the kernel 1034 - might interpret the following sequence as two partially 1035 - overlapping SRCU read-side critical sections: 1036 - 1037 - 1 r1 = srcu_read_lock(&my_srcu); 1038 - 2 do_something_1(); 1039 - 3 r2 = srcu_read_lock(&my_srcu); 1040 - 4 do_something_2(); 1041 - 5 srcu_read_unlock(&my_srcu, r1); 1042 - 6 do_something_3(); 1043 - 7 srcu_read_unlock(&my_srcu, r2); 1044 - 1045 - In contrast, LKMM will interpret this as a nested pair of 1046 - SRCU read-side critical sections, with the outer critical 1047 - section spanning lines 1-7 and the inner critical section 1048 - spanning lines 3-5. 1049 - 1050 - This difference would be more of a concern had anyone 1051 - identified a reasonable use case for partially overlapping 1052 - SRCU read-side critical sections. For more information 1053 - on the trickiness of such overlapping, please see: 1054 - https://paulmck.livejournal.com/40593.html 1055 - 1056 - f. Reader-writer locking is not modeled. It can be 1031 + e. Reader-writer locking is not modeled. It can be 1057 1032 emulated in litmus tests using atomic read-modify-write 1058 1033 operations. 1059 1034
+298
tools/memory-model/Documentation/locking.txt
··· 1 + Locking 2 + ======= 3 + 4 + Locking is well-known and the common use cases are straightforward: Any 5 + CPU holding a given lock sees any changes previously seen or made by any 6 + CPU before it previously released that same lock. This last sentence 7 + is the only part of this document that most developers will need to read. 8 + 9 + However, developers who would like to also access lock-protected shared 10 + variables outside of their corresponding locks should continue reading. 11 + 12 + 13 + Locking and Prior Accesses 14 + -------------------------- 15 + 16 + The basic rule of locking is worth repeating: 17 + 18 + Any CPU holding a given lock sees any changes previously seen 19 + or made by any CPU before it previously released that same lock. 20 + 21 + Note that this statement is a bit stronger than "Any CPU holding a 22 + given lock sees all changes made by any CPU during the time that CPU was 23 + previously holding this same lock". For example, consider the following 24 + pair of code fragments: 25 + 26 + /* See MP+polocks.litmus. */ 27 + void CPU0(void) 28 + { 29 + WRITE_ONCE(x, 1); 30 + spin_lock(&mylock); 31 + WRITE_ONCE(y, 1); 32 + spin_unlock(&mylock); 33 + } 34 + 35 + void CPU1(void) 36 + { 37 + spin_lock(&mylock); 38 + r0 = READ_ONCE(y); 39 + spin_unlock(&mylock); 40 + r1 = READ_ONCE(x); 41 + } 42 + 43 + The basic rule guarantees that if CPU0() acquires mylock before CPU1(), 44 + then both r0 and r1 must be set to the value 1. This also has the 45 + consequence that if the final value of r0 is equal to 1, then the final 46 + value of r1 must also be equal to 1. In contrast, the weaker rule would 47 + say nothing about the final value of r1. 48 + 49 + 50 + Locking and Subsequent Accesses 51 + ------------------------------- 52 + 53 + The converse to the basic rule also holds: Any CPU holding a given 54 + lock will not see any changes that will be made by any CPU after it 55 + subsequently acquires this same lock. This converse statement is 56 + illustrated by the following litmus test: 57 + 58 + /* See MP+porevlocks.litmus. */ 59 + void CPU0(void) 60 + { 61 + r0 = READ_ONCE(y); 62 + spin_lock(&mylock); 63 + r1 = READ_ONCE(x); 64 + spin_unlock(&mylock); 65 + } 66 + 67 + void CPU1(void) 68 + { 69 + spin_lock(&mylock); 70 + WRITE_ONCE(x, 1); 71 + spin_unlock(&mylock); 72 + WRITE_ONCE(y, 1); 73 + } 74 + 75 + This converse to the basic rule guarantees that if CPU0() acquires 76 + mylock before CPU1(), then both r0 and r1 must be set to the value 0. 77 + This also has the consequence that if the final value of r1 is equal 78 + to 0, then the final value of r0 must also be equal to 0. In contrast, 79 + the weaker rule would say nothing about the final value of r0. 80 + 81 + These examples show only a single pair of CPUs, but the effects of the 82 + locking basic rule extend across multiple acquisitions of a given lock 83 + across multiple CPUs. 84 + 85 + 86 + Double-Checked Locking 87 + ---------------------- 88 + 89 + It is well known that more than just a lock is required to make 90 + double-checked locking work correctly, This litmus test illustrates 91 + one incorrect approach: 92 + 93 + /* See Documentation/litmus-tests/locking/DCL-broken.litmus. */ 94 + void CPU0(void) 95 + { 96 + r0 = READ_ONCE(flag); 97 + if (r0 == 0) { 98 + spin_lock(&lck); 99 + r1 = READ_ONCE(flag); 100 + if (r1 == 0) { 101 + WRITE_ONCE(data, 1); 102 + WRITE_ONCE(flag, 1); 103 + } 104 + spin_unlock(&lck); 105 + } 106 + r2 = READ_ONCE(data); 107 + } 108 + /* CPU1() is the exactly the same as CPU0(). */ 109 + 110 + There are two problems. First, there is no ordering between the first 111 + READ_ONCE() of "flag" and the READ_ONCE() of "data". Second, there is 112 + no ordering between the two WRITE_ONCE() calls. It should therefore be 113 + no surprise that "r2" can be zero, and a quick herd7 run confirms this. 114 + 115 + One way to fix this is to use smp_load_acquire() and smp_store_release() 116 + as shown in this corrected version: 117 + 118 + /* See Documentation/litmus-tests/locking/DCL-fixed.litmus. */ 119 + void CPU0(void) 120 + { 121 + r0 = smp_load_acquire(&flag); 122 + if (r0 == 0) { 123 + spin_lock(&lck); 124 + r1 = READ_ONCE(flag); 125 + if (r1 == 0) { 126 + WRITE_ONCE(data, 1); 127 + smp_store_release(&flag, 1); 128 + } 129 + spin_unlock(&lck); 130 + } 131 + r2 = READ_ONCE(data); 132 + } 133 + /* CPU1() is the exactly the same as CPU0(). */ 134 + 135 + The smp_load_acquire() guarantees that its load from "flags" will 136 + be ordered before the READ_ONCE() from data, thus solving the first 137 + problem. The smp_store_release() guarantees that its store will be 138 + ordered after the WRITE_ONCE() to "data", solving the second problem. 139 + The smp_store_release() pairs with the smp_load_acquire(), thus ensuring 140 + that the ordering provided by each actually takes effect. Again, a 141 + quick herd7 run confirms this. 142 + 143 + In short, if you access a lock-protected variable without holding the 144 + corresponding lock, you will need to provide additional ordering, in 145 + this case, via the smp_load_acquire() and the smp_store_release(). 146 + 147 + 148 + Ordering Provided by a Lock to CPUs Not Holding That Lock 149 + --------------------------------------------------------- 150 + 151 + It is not necessarily the case that accesses ordered by locking will be 152 + seen as ordered by CPUs not holding that lock. Consider this example: 153 + 154 + /* See Z6.0+pooncelock+pooncelock+pombonce.litmus. */ 155 + void CPU0(void) 156 + { 157 + spin_lock(&mylock); 158 + WRITE_ONCE(x, 1); 159 + WRITE_ONCE(y, 1); 160 + spin_unlock(&mylock); 161 + } 162 + 163 + void CPU1(void) 164 + { 165 + spin_lock(&mylock); 166 + r0 = READ_ONCE(y); 167 + WRITE_ONCE(z, 1); 168 + spin_unlock(&mylock); 169 + } 170 + 171 + void CPU2(void) 172 + { 173 + WRITE_ONCE(z, 2); 174 + smp_mb(); 175 + r1 = READ_ONCE(x); 176 + } 177 + 178 + Counter-intuitive though it might be, it is quite possible to have 179 + the final value of r0 be 1, the final value of z be 2, and the final 180 + value of r1 be 0. The reason for this surprising outcome is that CPU2() 181 + never acquired the lock, and thus did not fully benefit from the lock's 182 + ordering properties. 183 + 184 + Ordering can be extended to CPUs not holding the lock by careful use 185 + of smp_mb__after_spinlock(): 186 + 187 + /* See Z6.0+pooncelock+poonceLock+pombonce.litmus. */ 188 + void CPU0(void) 189 + { 190 + spin_lock(&mylock); 191 + WRITE_ONCE(x, 1); 192 + WRITE_ONCE(y, 1); 193 + spin_unlock(&mylock); 194 + } 195 + 196 + void CPU1(void) 197 + { 198 + spin_lock(&mylock); 199 + smp_mb__after_spinlock(); 200 + r0 = READ_ONCE(y); 201 + WRITE_ONCE(z, 1); 202 + spin_unlock(&mylock); 203 + } 204 + 205 + void CPU2(void) 206 + { 207 + WRITE_ONCE(z, 2); 208 + smp_mb(); 209 + r1 = READ_ONCE(x); 210 + } 211 + 212 + This addition of smp_mb__after_spinlock() strengthens the lock 213 + acquisition sufficiently to rule out the counter-intuitive outcome. 214 + In other words, the addition of the smp_mb__after_spinlock() prohibits 215 + the counter-intuitive result where the final value of r0 is 1, the final 216 + value of z is 2, and the final value of r1 is 0. 217 + 218 + 219 + No Roach-Motel Locking! 220 + ----------------------- 221 + 222 + This example requires familiarity with the herd7 "filter" clause, so 223 + please read up on that topic in litmus-tests.txt. 224 + 225 + It is tempting to allow memory-reference instructions to be pulled 226 + into a critical section, but this cannot be allowed in the general case. 227 + For example, consider a spin loop preceding a lock-based critical section. 228 + Now, herd7 does not model spin loops, but we can emulate one with two 229 + loads, with a "filter" clause to constrain the first to return the 230 + initial value and the second to return the updated value, as shown below: 231 + 232 + /* See Documentation/litmus-tests/locking/RM-fixed.litmus. */ 233 + void CPU0(void) 234 + { 235 + spin_lock(&lck); 236 + r2 = atomic_inc_return(&y); 237 + WRITE_ONCE(x, 1); 238 + spin_unlock(&lck); 239 + } 240 + 241 + void CPU1(void) 242 + { 243 + r0 = READ_ONCE(x); 244 + r1 = READ_ONCE(x); 245 + spin_lock(&lck); 246 + r2 = atomic_inc_return(&y); 247 + spin_unlock(&lck); 248 + } 249 + 250 + filter (1:r0=0 /\ 1:r1=1) 251 + exists (1:r2=1) 252 + 253 + The variable "x" is the control variable for the emulated spin loop. 254 + CPU0() sets it to "1" while holding the lock, and CPU1() emulates the 255 + spin loop by reading it twice, first into "1:r0" (which should get the 256 + initial value "0") and then into "1:r1" (which should get the updated 257 + value "1"). 258 + 259 + The "filter" clause takes this into account, constraining "1:r0" to 260 + equal "0" and "1:r1" to equal 1. 261 + 262 + Then the "exists" clause checks to see if CPU1() acquired its lock first, 263 + which should not happen given the filter clause because CPU0() updates 264 + "x" while holding the lock. And herd7 confirms this. 265 + 266 + But suppose that the compiler was permitted to reorder the spin loop 267 + into CPU1()'s critical section, like this: 268 + 269 + /* See Documentation/litmus-tests/locking/RM-broken.litmus. */ 270 + void CPU0(void) 271 + { 272 + int r2; 273 + 274 + spin_lock(&lck); 275 + r2 = atomic_inc_return(&y); 276 + WRITE_ONCE(x, 1); 277 + spin_unlock(&lck); 278 + } 279 + 280 + void CPU1(void) 281 + { 282 + spin_lock(&lck); 283 + r0 = READ_ONCE(x); 284 + r1 = READ_ONCE(x); 285 + r2 = atomic_inc_return(&y); 286 + spin_unlock(&lck); 287 + } 288 + 289 + filter (1:r0=0 /\ 1:r1=1) 290 + exists (1:r2=1) 291 + 292 + If "1:r0" is equal to "0", "1:r1" can never equal "1" because CPU0() 293 + cannot update "x" while CPU1() holds the lock. And herd7 confirms this, 294 + showing zero executions matching the "filter" criteria. 295 + 296 + And this is why Linux-kernel lock and unlock primitives must prevent 297 + code from entering critical sections. It is not sufficient to only 298 + prevent code from leaving them.
+1 -1
tools/memory-model/litmus-tests/.gitignore
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 - *.litmus.out 2 + *.litmus.*
+44 -4
tools/memory-model/scripts/README
··· 27 27 checklitmus.sh 28 28 29 29 Check a single litmus test against its "Result:" expected result. 30 + Not intended to for manual use. 31 + 32 + checktheselitmus.sh 33 + 34 + Check the specified list of litmus tests against their "Result:" 35 + expected results. This takes optional parseargs.sh arguments, 36 + followed by "--" followed by pathnames starting from the current 37 + directory. 30 38 31 39 cmplitmushist.sh 32 40 ··· 51 43 52 44 judgelitmus.sh 53 45 54 - Given a .litmus file and its .litmus.out herd7 output, check the 55 - .litmus.out file against the .litmus file's "Result:" comment to 56 - judge whether the test ran correctly. Not normally run manually, 57 - provided instead for use by other scripts. 46 + Given a .litmus file and its herd7 output, check the output file 47 + against the .litmus file's "Result:" comment to judge whether 48 + the test ran correctly. Not normally run manually, provided 49 + instead for use by other scripts. 58 50 59 51 newlitmushist.sh 60 52 ··· 76 68 README 77 69 78 70 This file 71 + 72 + Testing a change to LKMM might go as follows: 73 + 74 + # Populate expected results without that change, and 75 + # runs for about an hour on an 8-CPU x86 system: 76 + scripts/initlitmushist.sh --timeout 10m --procs 10 77 + # Incorporate the change: 78 + git am -s -3 /path/to/patch # Or whatever it takes. 79 + 80 + # Test the new version of LKMM as follows... 81 + 82 + # Runs in seconds, good smoke test: 83 + scripts/checkalllitmus.sh 84 + 85 + # Compares results to those produced by initlitmushist.sh, 86 + # and runs for about an hour on an 8-CPU x86 system: 87 + scripts/checklitmushist.sh --timeout 10m --procs 10 88 + 89 + # Checks results against Result tags, runs in minutes: 90 + scripts/checkghlitmus.sh --timeout 10m --procs 10 91 + 92 + The checkghlitmus.sh should not report errors in cases where the 93 + checklitmushist.sh script did not also report a change. However, 94 + this check is nevertheless valuable because it can find errors in the 95 + original version of LKMM. Note however, that given the above procedure, 96 + an error in the original LKMM version that is fixed by the patch will 97 + be reported both as a mismatch by checklitmushist.sh and as an error 98 + by checkghlitmus.sh. One exception to this rule of thumb is when the 99 + test fails completely on the original version of LKMM and passes on the 100 + new version. In this case, checklitmushist.sh will report a mismatch 101 + and checkghlitmus.sh will report success. This happens when the change 102 + to LKMM introduces a new primitive for which litmus tests already existed.
+14 -15
tools/memory-model/scripts/checkalllitmus.sh
··· 1 - #!/bin/sh 1 + #!/bin/bash 2 2 # SPDX-License-Identifier: GPL-2.0+ 3 3 # 4 4 # Run herd7 tests on all .litmus files in the litmus-tests directory ··· 7 7 # in the litmus test, this script prints an error message prefixed with 8 8 # "^^^". It also outputs verification results to a file whose name is 9 9 # that of the specified litmus test, but with ".out" appended. 10 + # 11 + # If the --hw argument is specified, this script translates the .litmus 12 + # C-language file to the specified type of assembly and verifies that. 13 + # But in this case, litmus tests using complex synchronization (such as 14 + # locking, RCU, and SRCU) are cheerfully ignored. 10 15 # 11 16 # Usage: 12 17 # checkalllitmus.sh ··· 22 17 # 23 18 # Copyright IBM Corporation, 2018 24 19 # 25 - # Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 20 + # Author: Paul E. McKenney <paulmck@linux.ibm.com> 26 21 27 22 . scripts/parseargs.sh 28 23 ··· 35 30 exit 255 36 31 fi 37 32 38 - # Create any new directories that have appeared in the github litmus 39 - # repo since the last run. 33 + # Create any new directories that have appeared in the litmus-tests 34 + # directory since the last run. 40 35 if test "$LKMM_DESTDIR" != "." 41 36 then 42 37 find $litmusdir -type d -print | 43 38 ( cd "$LKMM_DESTDIR"; sed -e 's/^/mkdir -p /' | sh ) 44 39 fi 45 40 46 - # Find the checklitmus script. If it is not where we expect it, then 47 - # assume that the caller has the PATH environment variable set 48 - # appropriately. 49 - if test -x scripts/checklitmus.sh 50 - then 51 - clscript=scripts/checklitmus.sh 52 - else 53 - clscript=checklitmus.sh 54 - fi 55 - 56 41 # Run the script on all the litmus tests in the specified directory 57 42 ret=0 58 43 for i in $litmusdir/*.litmus 59 44 do 60 - if ! $clscript $i 45 + if test -n "$LKMM_HW_MAP_FILE" && ! scripts/simpletest.sh $i 46 + then 47 + continue 48 + fi 49 + if ! scripts/checklitmus.sh $i 61 50 then 62 51 ret=1 63 52 fi
+8 -7
tools/memory-model/scripts/checkghlitmus.sh
··· 10 10 # parseargs.sh scripts for arguments. 11 11 12 12 . scripts/parseargs.sh 13 + . scripts/hwfnseg.sh 13 14 14 15 T=/tmp/checkghlitmus.sh.$$ 15 16 trap 'rm -rf $T' 0 ··· 33 32 ( cd "$LKMM_DESTDIR"; sed -e 's/^/mkdir -p /' | sh ) 34 33 fi 35 34 36 - # Create a list of the C-language litmus tests previously run. 37 - ( cd $LKMM_DESTDIR; find litmus -name '*.litmus.out' -print ) | 38 - sed -e 's/\.out$//' | 39 - xargs -r egrep -l '^ \* Result: (Never|Sometimes|Always|DEADLOCK)' | 35 + # Create a list of the specified litmus tests previously run. 36 + ( cd $LKMM_DESTDIR; find litmus -name "*.litmus${hwfnseg}.out" -print ) | 37 + sed -e "s/${hwfnseg}"'\.out$//' | 38 + xargs -r grep -E -l '^ \* Result: (Never|Sometimes|Always|DEADLOCK)' | 40 39 xargs -r grep -L "^P${LKMM_PROCS}"> $T/list-C-already 41 40 42 41 # Create a list of C-language litmus tests with "Result:" commands and 43 42 # no more than the specified number of processes. 44 - find litmus -name '*.litmus' -exec grep -l -m 1 "^C " {} \; > $T/list-C 45 - xargs < $T/list-C -r egrep -l '^ \* Result: (Never|Sometimes|Always|DEADLOCK)' > $T/list-C-result 43 + find litmus -name '*.litmus' -print | mselect7 -arch C > $T/list-C 44 + xargs < $T/list-C -r grep -E -l '^ \* Result: (Never|Sometimes|Always|DEADLOCK)' > $T/list-C-result 46 45 xargs < $T/list-C-result -r grep -L "^P${LKMM_PROCS}" > $T/list-C-result-short 47 46 48 - # Form list of tests without corresponding .litmus.out files 47 + # Form list of tests without corresponding .out files 49 48 sort $T/list-C-already $T/list-C-result-short | uniq -u > $T/list-C-needed 50 49 51 50 # Run any needed tests.
+5 -20
tools/memory-model/scripts/checklitmus.sh
··· 1 1 #!/bin/sh 2 2 # SPDX-License-Identifier: GPL-2.0+ 3 3 # 4 - # Run a herd7 test and invokes judgelitmus.sh to check the result against 5 - # a "Result:" comment within the litmus test. It also outputs verification 6 - # results to a file whose name is that of the specified litmus test, but 7 - # with ".out" appended. 4 + # Invokes runlitmus.sh and judgelitmus.sh on its arguments to run the 5 + # specified litmus test and pass judgment on the results. 8 6 # 9 7 # Usage: 10 8 # checklitmus.sh file.litmus ··· 13 15 # 14 16 # Copyright IBM Corporation, 2018 15 17 # 16 - # Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 18 + # Author: Paul E. McKenney <paulmck@linux.ibm.com> 17 19 18 - litmus=$1 19 - herdoptions=${LKMM_HERD_OPTIONS--conf linux-kernel.cfg} 20 - 21 - if test -f "$litmus" -a -r "$litmus" 22 - then 23 - : 24 - else 25 - echo ' --- ' error: \"$litmus\" is not a readable file 26 - exit 255 27 - fi 28 - 29 - echo Herd options: $herdoptions > $LKMM_DESTDIR/$litmus.out 30 - /usr/bin/time $LKMM_TIMEOUT_CMD herd7 $herdoptions $litmus >> $LKMM_DESTDIR/$litmus.out 2>&1 31 - 32 - scripts/judgelitmus.sh $litmus 20 + scripts/runlitmus.sh $1 21 + scripts/judgelitmus.sh $1
+1 -1
tools/memory-model/scripts/checklitmushist.sh
··· 12 12 # 13 13 # Copyright IBM Corporation, 2018 14 14 # 15 - # Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 15 + # Author: Paul E. McKenney <paulmck@linux.ibm.com> 16 16 17 17 . scripts/parseargs.sh 18 18
+43
tools/memory-model/scripts/checktheselitmus.sh
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0+ 3 + # 4 + # Invokes checklitmus.sh on its arguments to run the specified litmus 5 + # test and pass judgment on the results. 6 + # 7 + # Usage: 8 + # checktheselitmus.sh -- [ file1.litmus [ file2.litmus ... ] ] 9 + # 10 + # Run this in the directory containing the memory model, specifying the 11 + # pathname of the litmus test to check. The usual parseargs.sh arguments 12 + # can be specified prior to the "--". 13 + # 14 + # This script is intended for use with pathnames that start from the 15 + # tools/memory-model directory. If some of the pathnames instead start at 16 + # the root directory, they all must do so and the "--destdir /" parseargs.sh 17 + # argument must be specified prior to the "--". Alternatively, some other 18 + # "--destdir" argument can be supplied as long as the needed subdirectories 19 + # are populated. 20 + # 21 + # Copyright IBM Corporation, 2018 22 + # 23 + # Author: Paul E. McKenney <paulmck@linux.ibm.com> 24 + 25 + . scripts/parseargs.sh 26 + 27 + ret=0 28 + for i in "$@" 29 + do 30 + if scripts/checklitmus.sh $i 31 + then 32 + : 33 + else 34 + ret=1 35 + fi 36 + done 37 + if test "$ret" -ne 0 38 + then 39 + echo " ^^^ VERIFICATION MISMATCHES" 1>&2 40 + else 41 + echo All litmus tests verified as was expected. 1>&2 42 + fi 43 + exit $ret
+47 -2
tools/memory-model/scripts/cmplitmushist.sh
··· 12 12 mkdir $T 13 13 14 14 # comparetest oldpath newpath 15 + badmacnam=0 16 + timedout=0 15 17 perfect=0 16 18 obsline=0 17 19 noobsline=0 18 20 obsresult=0 19 21 badcompare=0 20 22 comparetest () { 23 + if grep -q ': Unknown macro ' $1 || grep -q ': Unknown macro ' $2 24 + then 25 + if grep -q ': Unknown macro ' $1 26 + then 27 + badname=`grep ': Unknown macro ' $1 | 28 + sed -e 's/^.*: Unknown macro //' | 29 + sed -e 's/ (User error).*$//'` 30 + echo 'Current LKMM version does not know "'$badname'"' $1 31 + fi 32 + if grep -q ': Unknown macro ' $2 33 + then 34 + badname=`grep ': Unknown macro ' $2 | 35 + sed -e 's/^.*: Unknown macro //' | 36 + sed -e 's/ (User error).*$//'` 37 + echo 'Current LKMM version does not know "'$badname'"' $2 38 + fi 39 + badmacnam=`expr "$badmacnam" + 1` 40 + return 0 41 + elif grep -q '^Command exited with non-zero status 124' $1 || 42 + grep -q '^Command exited with non-zero status 124' $2 43 + then 44 + if grep -q '^Command exited with non-zero status 124' $1 && 45 + grep -q '^Command exited with non-zero status 124' $2 46 + then 47 + echo Both runs timed out: $2 48 + elif grep -q '^Command exited with non-zero status 124' $1 49 + then 50 + echo Old run timed out: $2 51 + elif grep -q '^Command exited with non-zero status 124' $2 52 + then 53 + echo New run timed out: $2 54 + fi 55 + timedout=`expr "$timedout" + 1` 56 + return 0 57 + fi 21 58 grep -v 'maxresident)k\|minor)pagefaults\|^Time' $1 > $T/oldout 22 59 grep -v 'maxresident)k\|minor)pagefaults\|^Time' $2 > $T/newout 23 60 if cmp -s $T/oldout $T/newout && grep -q '^Observation' $1 ··· 75 38 return 0 76 39 fi 77 40 else 78 - echo Missing Observation line "(e.g., herd7 timeout)": $2 41 + echo Missing Observation line "(e.g., syntax error)": $2 79 42 noobsline=`expr "$noobsline" + 1` 80 43 return 0 81 44 fi ··· 109 72 fi 110 73 if test "$noobsline" -ne 0 111 74 then 112 - echo Missing Observation line "(e.g., herd7 timeout)": $noobsline 1>&2 75 + echo Missing Observation line "(e.g., syntax error)": $noobsline 1>&2 113 76 fi 114 77 if test "$obsresult" -ne 0 115 78 then 116 79 echo Matching Observation Always/Sometimes/Never result: $obsresult 1>&2 80 + fi 81 + if test "$timedout" -ne 0 82 + then 83 + echo "!!!" Timed out: $timedout 1>&2 84 + fi 85 + if test "$badmacnam" -ne 0 86 + then 87 + echo "!!!" Unknown primitive: $badmacnam 1>&2 117 88 fi 118 89 if test "$badcompare" -ne 0 119 90 then
+20
tools/memory-model/scripts/hwfnseg.sh
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0+ 3 + # 4 + # Generate the hardware extension to the litmus-test filename, or the 5 + # empty string if this is an LKMM run. The extension is placed in 6 + # the shell variable hwfnseg. 7 + # 8 + # Usage: 9 + # . hwfnseg.sh 10 + # 11 + # Copyright IBM Corporation, 2019 12 + # 13 + # Author: Paul E. McKenney <paulmck@linux.ibm.com> 14 + 15 + if test -z "$LKMM_HW_MAP_FILE" 16 + then 17 + hwfnseg= 18 + else 19 + hwfnseg=".$LKMM_HW_MAP_FILE" 20 + fi
+1 -1
tools/memory-model/scripts/initlitmushist.sh
··· 60 60 61 61 # Create a list of the C-language litmus tests with no more than the 62 62 # specified number of processes (per the --procs argument). 63 - find litmus -name '*.litmus' -exec grep -l -m 1 "^C " {} \; > $T/list-C 63 + find litmus -name '*.litmus' -print | mselect7 -arch C > $T/list-C 64 64 xargs < $T/list-C -r grep -L "^P${LKMM_PROCS}" > $T/list-C-short 65 65 66 66 scripts/runlitmushist.sh < $T/list-C-short
+99 -21
tools/memory-model/scripts/judgelitmus.sh
··· 1 1 #!/bin/sh 2 2 # SPDX-License-Identifier: GPL-2.0+ 3 3 # 4 - # Given a .litmus test and the corresponding .litmus.out file, check 5 - # the .litmus.out file against the "Result:" comment to judge whether 6 - # the test ran correctly. 4 + # Given a .litmus test and the corresponding litmus output file, check 5 + # the .litmus.out file against the "Result:" comment to judge whether the 6 + # test ran correctly. If the --hw argument is omitted, check against the 7 + # LKMM output, which is assumed to be in file.litmus.out. If either a 8 + # "DATARACE" marker in the "Result:" comment or a "Flag data-race" marker 9 + # in the LKMM output is present, the other must also be as well, at least 10 + # for litmus tests having a "Result:" comment. In this case, a failure of 11 + # the Always/Sometimes/Never portion of the "Result:" prediction will be 12 + # noted, but forgiven. 13 + # 14 + # If the --hw argument is provided, this is assumed to be a hardware 15 + # test, and the output is assumed to be in file.litmus.HW.out, where 16 + # "HW" is the --hw argument. In addition, non-Sometimes verification 17 + # results will be noted, but forgiven. Furthermore, if there is no 18 + # "Result:" comment but there is an LKMM .litmus.out file, the observation 19 + # in that file will be used to judge the assembly-language verification. 7 20 # 8 21 # Usage: 9 22 # judgelitmus.sh file.litmus ··· 26 13 # 27 14 # Copyright IBM Corporation, 2018 28 15 # 29 - # Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 16 + # Author: Paul E. McKenney <paulmck@linux.ibm.com> 30 17 31 18 litmus=$1 32 19 ··· 37 24 echo ' --- ' error: \"$litmus\" is not a readable file 38 25 exit 255 39 26 fi 40 - if test -f "$LKMM_DESTDIR/$litmus".out -a -r "$LKMM_DESTDIR/$litmus".out 27 + if test -z "$LKMM_HW_MAP_FILE" 28 + then 29 + litmusout=$litmus.out 30 + lkmmout= 31 + else 32 + litmusout="`echo $litmus | 33 + sed -e 's/\.litmus$/.litmus.'${LKMM_HW_MAP_FILE}'/'`.out" 34 + lkmmout=$litmus.out 35 + fi 36 + if test -f "$LKMM_DESTDIR/$litmusout" -a -r "$LKMM_DESTDIR/$litmusout" 41 37 then 42 38 : 43 39 else 44 - echo ' --- ' error: \"$LKMM_DESTDIR/$litmus\".out is not a readable file 40 + echo ' --- ' error: \"$LKMM_DESTDIR/$litmusout is not a readable file 45 41 exit 255 46 42 fi 47 - if grep -q '^ \* Result: ' $litmus 43 + if grep -q '^Flag data-race$' "$LKMM_DESTDIR/$litmusout" 48 44 then 49 - outcome=`grep -m 1 '^ \* Result: ' $litmus | awk '{ print $3 }'` 45 + datarace_modeled=1 46 + fi 47 + if grep -q '^[( ]\* Result: ' $litmus 48 + then 49 + outcome=`grep -m 1 '^[( ]\* Result: ' $litmus | awk '{ print $3 }'` 50 + if grep -m1 '^[( ]\* Result: .* DATARACE' $litmus 51 + then 52 + datarace_predicted=1 53 + fi 54 + if test -n "$datarace_predicted" -a -z "$datarace_modeled" -a -z "$LKMM_HW_MAP_FILE" 55 + then 56 + echo '!!! Predicted data race not modeled' $litmus 57 + exit 252 58 + elif test -z "$datarace_predicted" -a -n "$datarace_modeled" 59 + then 60 + # Note that hardware models currently don't model data races 61 + echo '!!! Unexpected data race modeled' $litmus 62 + exit 253 63 + fi 64 + elif test -n "$LKMM_HW_MAP_FILE" && grep -q '^Observation' $LKMM_DESTDIR/$lkmmout > /dev/null 2>&1 65 + then 66 + outcome=`grep -m 1 '^Observation ' $LKMM_DESTDIR/$lkmmout | awk '{ print $3 }'` 50 67 else 51 68 outcome=specified 52 69 fi 53 70 54 - grep '^Observation' $LKMM_DESTDIR/$litmus.out 55 - if grep -q '^Observation' $LKMM_DESTDIR/$litmus.out 71 + grep '^Observation' $LKMM_DESTDIR/$litmusout 72 + if grep -q '^Observation' $LKMM_DESTDIR/$litmusout 56 73 then 57 74 : 75 + elif grep ': Unknown macro ' $LKMM_DESTDIR/$litmusout 76 + then 77 + badname=`grep ': Unknown macro ' $LKMM_DESTDIR/$litmusout | 78 + sed -e 's/^.*: Unknown macro //' | 79 + sed -e 's/ (User error).*$//'` 80 + badmsg=' !!! Current LKMM version does not know "'$badname'"'" $litmus" 81 + echo $badmsg 82 + if ! grep -q '!!!' $LKMM_DESTDIR/$litmusout 83 + then 84 + echo ' !!! '$badmsg >> $LKMM_DESTDIR/$litmusout 2>&1 85 + fi 86 + exit 254 87 + elif grep '^Command exited with non-zero status 124' $LKMM_DESTDIR/$litmusout 88 + then 89 + echo ' !!! Timeout' $litmus 90 + if ! grep -q '!!!' $LKMM_DESTDIR/$litmusout 91 + then 92 + echo ' !!! Timeout' >> $LKMM_DESTDIR/$litmusout 2>&1 93 + fi 94 + exit 124 58 95 else 59 96 echo ' !!! Verification error' $litmus 60 - if ! grep -q '!!!' $LKMM_DESTDIR/$litmus.out 97 + if ! grep -q '!!!' $LKMM_DESTDIR/$litmusout 61 98 then 62 - echo ' !!! Verification error' >> $LKMM_DESTDIR/$litmus.out 2>&1 99 + echo ' !!! Verification error' >> $LKMM_DESTDIR/$litmusout 2>&1 63 100 fi 64 101 exit 255 65 102 fi 66 103 if test "$outcome" = DEADLOCK 67 104 then 68 - if grep '^Observation' $LKMM_DESTDIR/$litmus.out | grep -q 'Never 0 0$' 105 + if grep '^Observation' $LKMM_DESTDIR/$litmusout | grep -q 'Never 0 0$' 69 106 then 70 107 ret=0 71 108 else 72 109 echo " !!! Unexpected non-$outcome verification" $litmus 73 - if ! grep -q '!!!' $LKMM_DESTDIR/$litmus.out 110 + if ! grep -q '!!!' $LKMM_DESTDIR/$litmusout 74 111 then 75 - echo " !!! Unexpected non-$outcome verification" >> $LKMM_DESTDIR/$litmus.out 2>&1 112 + echo " !!! Unexpected non-$outcome verification" >> $LKMM_DESTDIR/$litmusout 2>&1 76 113 fi 77 114 ret=1 78 115 fi 79 - elif grep '^Observation' $LKMM_DESTDIR/$litmus.out | grep -q $outcome || test "$outcome" = Maybe 116 + elif grep '^Observation' $LKMM_DESTDIR/$litmusout | grep -q 'Never 0 0$' 117 + then 118 + echo " !!! Unexpected non-$outcome deadlock" $litmus 119 + if ! grep -q '!!!' $LKMM_DESTDIR/$litmusout 120 + then 121 + echo " !!! Unexpected non-$outcome deadlock" $litmus >> $LKMM_DESTDIR/$litmusout 2>&1 122 + fi 123 + ret=1 124 + elif grep '^Observation' $LKMM_DESTDIR/$litmusout | grep -q $outcome || test "$outcome" = Maybe 80 125 then 81 126 ret=0 82 127 else 83 - echo " !!! Unexpected non-$outcome verification" $litmus 84 - if ! grep -q '!!!' $LKMM_DESTDIR/$litmus.out 128 + if test \( -n "$LKMM_HW_MAP_FILE" -a "$outcome" = Sometimes \) -o -n "$datarace_modeled" 85 129 then 86 - echo " !!! Unexpected non-$outcome verification" >> $LKMM_DESTDIR/$litmus.out 2>&1 130 + flag="--- Forgiven" 131 + ret=0 132 + else 133 + flag="!!! Unexpected" 134 + ret=1 87 135 fi 88 - ret=1 136 + echo " $flag non-$outcome verification" $litmus 137 + if ! grep -qe "$flag" $LKMM_DESTDIR/$litmusout 138 + then 139 + echo " $flag non-$outcome verification" >> $LKMM_DESTDIR/$litmusout 2>&1 140 + fi 89 141 fi 90 - tail -2 $LKMM_DESTDIR/$litmus.out | head -1 142 + tail -2 $LKMM_DESTDIR/$litmusout | head -1 91 143 exit $ret
+2 -2
tools/memory-model/scripts/newlitmushist.sh
··· 12 12 # 13 13 # Copyright IBM Corporation, 2018 14 14 # 15 - # Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 15 + # Author: Paul E. McKenney <paulmck@linux.ibm.com> 16 16 17 17 . scripts/parseargs.sh 18 18 ··· 43 43 44 44 # Form full list of litmus tests with no more than the specified 45 45 # number of processes (per the --procs argument). 46 - find litmus -name '*.litmus' -exec grep -l -m 1 "^C " {} \; > $T/list-C-all 46 + find litmus -name '*.litmus' -print | mselect7 -arch C > $T/list-C-all 47 47 xargs < $T/list-C-all -r grep -L "^P${LKMM_PROCS}" > $T/list-C-short 48 48 49 49 # Form list of new tests. Note: This does not handle litmus-test deletion!
+16 -5
tools/memory-model/scripts/parseargs.sh
··· 1 1 #!/bin/sh 2 2 # SPDX-License-Identifier: GPL-2.0+ 3 3 # 4 - # the corresponding .litmus.out file, and does not judge the result. 4 + # Parse arguments common to the various scripts. 5 5 # 6 6 # . scripts/parseargs.sh 7 7 # ··· 9 9 # 10 10 # Copyright IBM Corporation, 2018 11 11 # 12 - # Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 12 + # Author: Paul E. McKenney <paulmck@linux.ibm.com> 13 13 14 14 T=/tmp/parseargs.sh.$$ 15 15 mkdir $T ··· 27 27 28 28 initparam LKMM_DESTDIR "." 29 29 initparam LKMM_HERD_OPTIONS "-conf linux-kernel.cfg" 30 + initparam LKMM_HW_MAP_FILE "" 30 31 initparam LKMM_JOBS `getconf _NPROCESSORS_ONLN` 31 32 initparam LKMM_PROCS "3" 32 33 initparam LKMM_TIMEOUT "1m" ··· 38 37 echo "Usage $scriptname [ arguments ]" 39 38 echo " --destdir path (place for .litmus.out, default by .litmus)" 40 39 echo " --herdopts -conf linux-kernel.cfg ..." 40 + echo " --hw AArch64" 41 41 echo " --jobs N (number of jobs, default one per CPU)" 42 42 echo " --procs N (litmus tests with at most this many processes)" 43 43 echo " --timeout N (herd7 timeout (e.g., 10s, 1m, 2hr, 1d, '')" 44 - echo "Defaults: --destdir '$LKMM_DESTDIR_DEF' --herdopts '$LKMM_HERD_OPTIONS_DEF' --jobs '$LKMM_JOBS_DEF' --procs '$LKMM_PROCS_DEF' --timeout '$LKMM_TIMEOUT_DEF'" 44 + echo "Defaults: --destdir '$LKMM_DESTDIR_DEF' --herdopts '$LKMM_HERD_OPTIONS_DEF' --hw '$LKMM_HW_MAP_FILE' --jobs '$LKMM_JOBS_DEF' --procs '$LKMM_PROCS_DEF' --timeout '$LKMM_TIMEOUT_DEF'" 45 45 exit 1 46 46 } 47 47 ··· 83 81 echo "Cannot create directory --destdir '$LKMM_DESTDIR'" 84 82 usage 85 83 fi 86 - if test -d "$LKMM_DESTDIR" -a -w "$LKMM_DESTDIR" -a -x "$LKMM_DESTDIR" 84 + if test -d "$LKMM_DESTDIR" -a -x "$LKMM_DESTDIR" 87 85 then 88 86 : 89 87 else ··· 97 95 LKMM_HERD_OPTIONS="$2" 98 96 shift 99 97 ;; 98 + --hw) 99 + checkarg --hw "(.map file architecture name)" "$#" "$2" '^[A-Za-z0-9_-]\+' '^--' 100 + LKMM_HW_MAP_FILE="$2" 101 + shift 102 + ;; 100 103 -j[1-9]*) 101 104 njobs="`echo $1 | sed -e 's/^-j//'`" 102 105 trailchars="`echo $njobs | sed -e 's/[0-9]\+\(.*\)$/\1/'`" ··· 113 106 LKMM_JOBS="`echo $njobs | sed -e 's/^\([0-9]\+\).*$/\1/'`" 114 107 ;; 115 108 --jobs|--job|-j) 116 - checkarg --jobs "(number)" "$#" "$2" '^[1-9][0-9]\+$' '^--' 109 + checkarg --jobs "(number)" "$#" "$2" '^[1-9][0-9]*$' '^--' 117 110 LKMM_JOBS="$2" 118 111 shift 119 112 ;; ··· 126 119 checkarg --timeout "(timeout spec)" "$#" "$2" '^\([0-9]\+[smhd]\?\|\)$' '^--' 127 120 LKMM_TIMEOUT="$2" 128 121 shift 122 + ;; 123 + --) 124 + shift 125 + break 129 126 ;; 130 127 *) 131 128 echo Unknown argument $1
+80
tools/memory-model/scripts/runlitmus.sh
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0+ 3 + # 4 + # Without the -hw argument, runs a herd7 test and outputs verification 5 + # results to a file whose name is that of the specified litmus test, 6 + # but with ".out" appended. 7 + # 8 + # If the --hw argument is specified, this script translates the .litmus 9 + # C-language file to the specified type of assembly and verifies that. 10 + # But in this case, litmus tests using complex synchronization (such as 11 + # locking, RCU, and SRCU) are cheerfully ignored. 12 + # 13 + # Either way, return the status of the herd7 command. 14 + # 15 + # Usage: 16 + # runlitmus.sh file.litmus 17 + # 18 + # Run this in the directory containing the memory model, specifying the 19 + # pathname of the litmus test to check. The caller is expected to have 20 + # properly set up the LKMM environment variables. 21 + # 22 + # Copyright IBM Corporation, 2019 23 + # 24 + # Author: Paul E. McKenney <paulmck@linux.ibm.com> 25 + 26 + litmus=$1 27 + if test -f "$litmus" -a -r "$litmus" 28 + then 29 + : 30 + else 31 + echo ' !!! ' error: \"$litmus\" is not a readable file 32 + exit 255 33 + fi 34 + 35 + if test -z "$LKMM_HW_MAP_FILE" -o ! -e $LKMM_DESTDIR/$litmus.out 36 + then 37 + # LKMM run 38 + herdoptions=${LKMM_HERD_OPTIONS--conf linux-kernel.cfg} 39 + echo Herd options: $herdoptions > $LKMM_DESTDIR/$litmus.out 40 + /usr/bin/time $LKMM_TIMEOUT_CMD herd7 $herdoptions $litmus >> $LKMM_DESTDIR/$litmus.out 2>&1 41 + ret=$? 42 + if test -z "$LKMM_HW_MAP_FILE" 43 + then 44 + exit $ret 45 + fi 46 + echo " --- " Automatically generated LKMM output for '"'--hw $LKMM_HW_MAP_FILE'"' run 47 + fi 48 + 49 + # Hardware run 50 + 51 + T=/tmp/checklitmushw.sh.$$ 52 + trap 'rm -rf $T' 0 2 53 + mkdir $T 54 + 55 + # Generate filenames 56 + mapfile="Linux2${LKMM_HW_MAP_FILE}.map" 57 + themefile="$T/${LKMM_HW_MAP_FILE}.theme" 58 + herdoptions="-model $LKMM_HW_CAT_FILE" 59 + hwlitmus=`echo $litmus | sed -e 's/\.litmus$/.litmus.'${LKMM_HW_MAP_FILE}'/'` 60 + hwlitmusfile=`echo $hwlitmus | sed -e 's,^.*/,,'` 61 + 62 + # Don't run on litmus tests with complex synchronization 63 + if ! scripts/simpletest.sh $litmus 64 + then 65 + echo ' --- ' error: \"$litmus\" contains locking, RCU, or SRCU 66 + exit 254 67 + fi 68 + 69 + # Generate the assembly code and run herd7 on it. 70 + gen_theme7 -n 10 -map $mapfile -call Linux.call > $themefile 71 + jingle7 -v -theme $themefile $litmus > $LKMM_DESTDIR/$hwlitmus 2> $T/$hwlitmusfile.jingle7.out 72 + if grep -q "Generated 0 tests" $T/$hwlitmusfile.jingle7.out 73 + then 74 + echo ' !!! ' jingle7 failed, errors in $hwlitmus.err 75 + cp $T/$hwlitmusfile.jingle7.out $LKMM_DESTDIR/$hwlitmus.err 76 + exit 253 77 + fi 78 + /usr/bin/time $LKMM_TIMEOUT_CMD herd7 -unroll 0 $LKMM_DESTDIR/$hwlitmus > $LKMM_DESTDIR/$hwlitmus.out 2>&1 79 + 80 + exit $?
+18 -11
tools/memory-model/scripts/runlitmushist.sh
··· 13 13 # 14 14 # Copyright IBM Corporation, 2018 15 15 # 16 - # Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com> 16 + # Author: Paul E. McKenney <paulmck@linux.ibm.com> 17 + 18 + . scripts/hwfnseg.sh 17 19 18 20 T=/tmp/runlitmushist.sh.$$ 19 21 trap 'rm -rf $T' 0 ··· 32 30 # Prefixes for per-CPU scripts 33 31 for ((i=0;i<$LKMM_JOBS;i++)) 34 32 do 35 - echo dir="$LKMM_DESTDIR" > $T/$i.sh 36 33 echo T=$T >> $T/$i.sh 37 - echo herdoptions=\"$LKMM_HERD_OPTIONS\" >> $T/$i.sh 38 34 cat << '___EOF___' >> $T/$i.sh 39 35 runtest () { 40 - echo ' ... ' /usr/bin/time $LKMM_TIMEOUT_CMD herd7 $herdoptions $1 '>' $dir/$1.out '2>&1' 41 - if /usr/bin/time $LKMM_TIMEOUT_CMD herd7 $herdoptions $1 > $dir/$1.out 2>&1 36 + if scripts/runlitmus.sh $1 42 37 then 43 - if ! grep -q '^Observation ' $dir/$1.out 38 + if ! grep -q '^Observation ' $LKMM_DESTDIR/$1$2.out 44 39 then 45 40 echo ' !!! Herd failed, no Observation:' $1 46 41 fi ··· 46 47 if test "$exitcode" -eq 124 47 48 then 48 49 exitmsg="timed out" 50 + elif test "$exitcode" -eq 253 51 + then 52 + exitmsg= 49 53 else 50 54 exitmsg="failed, exit code $exitcode" 51 55 fi 52 - echo ' !!! Herd' ${exitmsg}: $1 56 + if test -n "$exitmsg" 57 + then 58 + echo ' !!! Herd' ${exitmsg}: $1 59 + fi 53 60 fi 54 61 } 55 62 ___EOF___ ··· 64 59 awk -v q="'" -v b='\\' ' 65 60 { 66 61 print "echo `grep " q "^P[0-9]" b "+(" q " " $0 " | tail -1 | sed -e " q "s/^P" b "([0-9]" b "+" b ")(.*$/" b "1/" q "` " $0 67 - }' | bash | 68 - sort -k1n | 69 - awk -v ncpu=$LKMM_JOBS -v t=$T ' 62 + }' | sh | sort -k1n | 63 + awk -v dq='"' -v hwfnseg="$hwfnseg" -v ncpu="$LKMM_JOBS" -v t="$T" ' 70 64 { 71 - print "runtest " $2 >> t "/" NR % ncpu ".sh"; 65 + print "if test -z " dq hwfnseg dq " || scripts/simpletest.sh " dq $2 dq 66 + print "then" 67 + print "\techo runtest " dq $2 dq " " hwfnseg " >> " t "/" NR % ncpu ".sh"; 68 + print "fi" 72 69 } 73 70 74 71 END {
+35
tools/memory-model/scripts/simpletest.sh
··· 1 + #!/bin/sh 2 + # SPDX-License-Identifier: GPL-2.0+ 3 + # 4 + # Give zero status if this is a simple test and non-zero otherwise. 5 + # Simple tests do not contain locking, RCU, or SRCU. 6 + # 7 + # Usage: 8 + # simpletest.sh file.litmus 9 + # 10 + # Copyright IBM Corporation, 2019 11 + # 12 + # Author: Paul E. McKenney <paulmck@linux.ibm.com> 13 + 14 + 15 + litmus=$1 16 + 17 + if test -f "$litmus" -a -r "$litmus" 18 + then 19 + : 20 + else 21 + echo ' --- ' error: \"$litmus\" is not a readable file 22 + exit 255 23 + fi 24 + exclude="^[[:space:]]*\(" 25 + exclude="${exclude}spin_lock(\|spin_unlock(\|spin_trylock(\|spin_is_locked(" 26 + exclude="${exclude}\|rcu_read_lock(\|rcu_read_unlock(" 27 + exclude="${exclude}\|synchronize_rcu(\|synchronize_rcu_expedited(" 28 + exclude="${exclude}\|srcu_read_lock(\|srcu_read_unlock(" 29 + exclude="${exclude}\|synchronize_srcu(\|synchronize_srcu_expedited(" 30 + exclude="${exclude}\)" 31 + if grep -q $exclude $litmus 32 + then 33 + exit 255 34 + fi 35 + exit 0