LKMM scripting updates for v6.4
This update improves litmus-test documentation and improves the ability to do before/after tests on the https://github.com/paulmckrcu/litmus repo. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEbK7UrM+RBIrCoViJnr8S83LZ+4wFAmQwtAMTHHBhdWxtY2tA a2VybmVsLm9yZwAKCRCevxLzctn7jE9AD/4pdoS4w+XmGTkOaSYWVKz0B822+FnZ 822s/Z+4sA7ngoDEx4NSno299mSjONMS/HS8oTDXQQgGL7xXZNJc1phD1oP17dwa 3Ic6RKqWlYLOtFLfGLZF+wvVo6Z0WLnyh4KDeA31AVcb/Cdzzb30RZTO9oz1WDZH ueD4egvl6ECyZPh2HfjcQ7Y2hH00Ohi1igY+WPCBiMM1FrTbPmaLrAwsRrEbhsqx PwnrbMdGrTvT62sgnm9LHGr/P2YKDdYxs8wUyWRg876KitdUPmZb8uy2gZ0Bpp5+ mMB6h54mjVtDnpVtPHm8u4Viq2ir3zSlbWGmI24JxFCn3FTRFQwYQMCPBm7tlpqB n+08OGtWDRM3b+aLa5gYo1MogMayWtZN/vL6/9BSTF6mvjMbKLu2esi6JttU1tOV o4LvG+b6lO+L1ZvQctnDmzCPjmVB4QuFZvcNdRwHIVFtlG2v2ffaZ5ogaM+3uN4u vUeW5pOmAaD3aO0g7xJVdTwHfBasxrXfYazjYPdpvuoIXHbOeEC+LVfCaQVJRFGf 20w0lB6hZqsE8qnaKAvHzupDi7nz3X0Ge/PAvu54o9PgOP1XKDNH+p6fCxefCx1T M8VnQHdgR29kuyrVy9XbQjRDgEXSPrQXrItl2B8MAoXVhaCDt6LOQ/LyGnKL3Q7w 4sEBieegEnqLQQ== =kQ01 -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
Коммит
60eb450742
|
@ -0,0 +1,54 @@
|
||||||
|
C DCL-broken
|
||||||
|
|
||||||
|
(*
|
||||||
|
* Result: Sometimes
|
||||||
|
*
|
||||||
|
* This litmus test demonstrates more than just locking is required to
|
||||||
|
* correctly implement double-checked locking.
|
||||||
|
*)
|
||||||
|
|
||||||
|
{
|
||||||
|
int flag;
|
||||||
|
int data;
|
||||||
|
}
|
||||||
|
|
||||||
|
P0(int *flag, int *data, spinlock_t *lck)
|
||||||
|
{
|
||||||
|
int r0;
|
||||||
|
int r1;
|
||||||
|
int r2;
|
||||||
|
|
||||||
|
r0 = READ_ONCE(*flag);
|
||||||
|
if (r0 == 0) {
|
||||||
|
spin_lock(lck);
|
||||||
|
r1 = READ_ONCE(*flag);
|
||||||
|
if (r1 == 0) {
|
||||||
|
WRITE_ONCE(*data, 1);
|
||||||
|
WRITE_ONCE(*flag, 1);
|
||||||
|
}
|
||||||
|
spin_unlock(lck);
|
||||||
|
}
|
||||||
|
r2 = READ_ONCE(*data);
|
||||||
|
}
|
||||||
|
|
||||||
|
P1(int *flag, int *data, spinlock_t *lck)
|
||||||
|
{
|
||||||
|
int r0;
|
||||||
|
int r1;
|
||||||
|
int r2;
|
||||||
|
|
||||||
|
r0 = READ_ONCE(*flag);
|
||||||
|
if (r0 == 0) {
|
||||||
|
spin_lock(lck);
|
||||||
|
r1 = READ_ONCE(*flag);
|
||||||
|
if (r1 == 0) {
|
||||||
|
WRITE_ONCE(*data, 1);
|
||||||
|
WRITE_ONCE(*flag, 1);
|
||||||
|
}
|
||||||
|
spin_unlock(lck);
|
||||||
|
}
|
||||||
|
r2 = READ_ONCE(*data);
|
||||||
|
}
|
||||||
|
|
||||||
|
locations [flag;data;0:r0;0:r1;1:r0;1:r1]
|
||||||
|
exists (0:r2=0 \/ 1:r2=0)
|
|
@ -0,0 +1,55 @@
|
||||||
|
C DCL-fixed
|
||||||
|
|
||||||
|
(*
|
||||||
|
* Result: Never
|
||||||
|
*
|
||||||
|
* This litmus test demonstrates that double-checked locking can be
|
||||||
|
* reliable given proper use of smp_load_acquire() and smp_store_release()
|
||||||
|
* in addition to the locking.
|
||||||
|
*)
|
||||||
|
|
||||||
|
{
|
||||||
|
int flag;
|
||||||
|
int data;
|
||||||
|
}
|
||||||
|
|
||||||
|
P0(int *flag, int *data, spinlock_t *lck)
|
||||||
|
{
|
||||||
|
int r0;
|
||||||
|
int r1;
|
||||||
|
int r2;
|
||||||
|
|
||||||
|
r0 = smp_load_acquire(flag);
|
||||||
|
if (r0 == 0) {
|
||||||
|
spin_lock(lck);
|
||||||
|
r1 = READ_ONCE(*flag);
|
||||||
|
if (r1 == 0) {
|
||||||
|
WRITE_ONCE(*data, 1);
|
||||||
|
smp_store_release(flag, 1);
|
||||||
|
}
|
||||||
|
spin_unlock(lck);
|
||||||
|
}
|
||||||
|
r2 = READ_ONCE(*data);
|
||||||
|
}
|
||||||
|
|
||||||
|
P1(int *flag, int *data, spinlock_t *lck)
|
||||||
|
{
|
||||||
|
int r0;
|
||||||
|
int r1;
|
||||||
|
int r2;
|
||||||
|
|
||||||
|
r0 = smp_load_acquire(flag);
|
||||||
|
if (r0 == 0) {
|
||||||
|
spin_lock(lck);
|
||||||
|
r1 = READ_ONCE(*flag);
|
||||||
|
if (r1 == 0) {
|
||||||
|
WRITE_ONCE(*data, 1);
|
||||||
|
smp_store_release(flag, 1);
|
||||||
|
}
|
||||||
|
spin_unlock(lck);
|
||||||
|
}
|
||||||
|
r2 = READ_ONCE(*data);
|
||||||
|
}
|
||||||
|
|
||||||
|
locations [flag;data;0:r0;0:r1;1:r0;1:r1]
|
||||||
|
exists (0:r2=0 \/ 1:r2=0)
|
|
@ -0,0 +1,41 @@
|
||||||
|
C RM-broken
|
||||||
|
|
||||||
|
(*
|
||||||
|
* Result: DEADLOCK
|
||||||
|
*
|
||||||
|
* This litmus test demonstrates that the old "roach motel" approach
|
||||||
|
* to locking, where code can be freely moved into critical sections,
|
||||||
|
* cannot be used in the Linux kernel.
|
||||||
|
*)
|
||||||
|
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
atomic_t y;
|
||||||
|
}
|
||||||
|
|
||||||
|
P0(int *x, atomic_t *y, spinlock_t *lck)
|
||||||
|
{
|
||||||
|
int r2;
|
||||||
|
|
||||||
|
spin_lock(lck);
|
||||||
|
r2 = atomic_inc_return(y);
|
||||||
|
WRITE_ONCE(*x, 1);
|
||||||
|
spin_unlock(lck);
|
||||||
|
}
|
||||||
|
|
||||||
|
P1(int *x, atomic_t *y, spinlock_t *lck)
|
||||||
|
{
|
||||||
|
int r0;
|
||||||
|
int r1;
|
||||||
|
int r2;
|
||||||
|
|
||||||
|
spin_lock(lck);
|
||||||
|
r0 = READ_ONCE(*x);
|
||||||
|
r1 = READ_ONCE(*x);
|
||||||
|
r2 = atomic_inc_return(y);
|
||||||
|
spin_unlock(lck);
|
||||||
|
}
|
||||||
|
|
||||||
|
locations [x;0:r2;1:r0;1:r1;1:r2]
|
||||||
|
filter (1:r0=0 /\ 1:r1=1)
|
||||||
|
exists (1:r2=1)
|
|
@ -0,0 +1,41 @@
|
||||||
|
C RM-fixed
|
||||||
|
|
||||||
|
(*
|
||||||
|
* Result: Never
|
||||||
|
*
|
||||||
|
* This litmus test demonstrates that the old "roach motel" approach
|
||||||
|
* to locking, where code can be freely moved into critical sections,
|
||||||
|
* cannot be used in the Linux kernel.
|
||||||
|
*)
|
||||||
|
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
atomic_t y;
|
||||||
|
}
|
||||||
|
|
||||||
|
P0(int *x, atomic_t *y, spinlock_t *lck)
|
||||||
|
{
|
||||||
|
int r2;
|
||||||
|
|
||||||
|
spin_lock(lck);
|
||||||
|
r2 = atomic_inc_return(y);
|
||||||
|
WRITE_ONCE(*x, 1);
|
||||||
|
spin_unlock(lck);
|
||||||
|
}
|
||||||
|
|
||||||
|
P1(int *x, atomic_t *y, spinlock_t *lck)
|
||||||
|
{
|
||||||
|
int r0;
|
||||||
|
int r1;
|
||||||
|
int r2;
|
||||||
|
|
||||||
|
r0 = READ_ONCE(*x);
|
||||||
|
r1 = READ_ONCE(*x);
|
||||||
|
spin_lock(lck);
|
||||||
|
r2 = atomic_inc_return(y);
|
||||||
|
spin_unlock(lck);
|
||||||
|
}
|
||||||
|
|
||||||
|
locations [x;0:r2;1:r0;1:r1;1:r2]
|
||||||
|
filter (1:r0=0 /\ 1:r1=1)
|
||||||
|
exists (1:r2=1)
|
|
@ -1028,32 +1028,7 @@ Limitations of the Linux-kernel memory model (LKMM) include:
|
||||||
additional call_rcu() process to the site of the
|
additional call_rcu() process to the site of the
|
||||||
emulated rcu-barrier().
|
emulated rcu-barrier().
|
||||||
|
|
||||||
e. Although sleepable RCU (SRCU) is now modeled, there
|
e. Reader-writer locking is not modeled. It can be
|
||||||
are some subtle differences between its semantics and
|
|
||||||
those in the Linux kernel. For example, the kernel
|
|
||||||
might interpret the following sequence as two partially
|
|
||||||
overlapping SRCU read-side critical sections:
|
|
||||||
|
|
||||||
1 r1 = srcu_read_lock(&my_srcu);
|
|
||||||
2 do_something_1();
|
|
||||||
3 r2 = srcu_read_lock(&my_srcu);
|
|
||||||
4 do_something_2();
|
|
||||||
5 srcu_read_unlock(&my_srcu, r1);
|
|
||||||
6 do_something_3();
|
|
||||||
7 srcu_read_unlock(&my_srcu, r2);
|
|
||||||
|
|
||||||
In contrast, LKMM will interpret this as a nested pair of
|
|
||||||
SRCU read-side critical sections, with the outer critical
|
|
||||||
section spanning lines 1-7 and the inner critical section
|
|
||||||
spanning lines 3-5.
|
|
||||||
|
|
||||||
This difference would be more of a concern had anyone
|
|
||||||
identified a reasonable use case for partially overlapping
|
|
||||||
SRCU read-side critical sections. For more information
|
|
||||||
on the trickiness of such overlapping, please see:
|
|
||||||
https://paulmck.livejournal.com/40593.html
|
|
||||||
|
|
||||||
f. Reader-writer locking is not modeled. It can be
|
|
||||||
emulated in litmus tests using atomic read-modify-write
|
emulated in litmus tests using atomic read-modify-write
|
||||||
operations.
|
operations.
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,298 @@
|
||||||
|
Locking
|
||||||
|
=======
|
||||||
|
|
||||||
|
Locking is well-known and the common use cases are straightforward: Any
|
||||||
|
CPU holding a given lock sees any changes previously seen or made by any
|
||||||
|
CPU before it previously released that same lock. This last sentence
|
||||||
|
is the only part of this document that most developers will need to read.
|
||||||
|
|
||||||
|
However, developers who would like to also access lock-protected shared
|
||||||
|
variables outside of their corresponding locks should continue reading.
|
||||||
|
|
||||||
|
|
||||||
|
Locking and Prior Accesses
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
The basic rule of locking is worth repeating:
|
||||||
|
|
||||||
|
Any CPU holding a given lock sees any changes previously seen
|
||||||
|
or made by any CPU before it previously released that same lock.
|
||||||
|
|
||||||
|
Note that this statement is a bit stronger than "Any CPU holding a
|
||||||
|
given lock sees all changes made by any CPU during the time that CPU was
|
||||||
|
previously holding this same lock". For example, consider the following
|
||||||
|
pair of code fragments:
|
||||||
|
|
||||||
|
/* See MP+polocks.litmus. */
|
||||||
|
void CPU0(void)
|
||||||
|
{
|
||||||
|
WRITE_ONCE(x, 1);
|
||||||
|
spin_lock(&mylock);
|
||||||
|
WRITE_ONCE(y, 1);
|
||||||
|
spin_unlock(&mylock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU1(void)
|
||||||
|
{
|
||||||
|
spin_lock(&mylock);
|
||||||
|
r0 = READ_ONCE(y);
|
||||||
|
spin_unlock(&mylock);
|
||||||
|
r1 = READ_ONCE(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
The basic rule guarantees that if CPU0() acquires mylock before CPU1(),
|
||||||
|
then both r0 and r1 must be set to the value 1. This also has the
|
||||||
|
consequence that if the final value of r0 is equal to 1, then the final
|
||||||
|
value of r1 must also be equal to 1. In contrast, the weaker rule would
|
||||||
|
say nothing about the final value of r1.
|
||||||
|
|
||||||
|
|
||||||
|
Locking and Subsequent Accesses
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
The converse to the basic rule also holds: Any CPU holding a given
|
||||||
|
lock will not see any changes that will be made by any CPU after it
|
||||||
|
subsequently acquires this same lock. This converse statement is
|
||||||
|
illustrated by the following litmus test:
|
||||||
|
|
||||||
|
/* See MP+porevlocks.litmus. */
|
||||||
|
void CPU0(void)
|
||||||
|
{
|
||||||
|
r0 = READ_ONCE(y);
|
||||||
|
spin_lock(&mylock);
|
||||||
|
r1 = READ_ONCE(x);
|
||||||
|
spin_unlock(&mylock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU1(void)
|
||||||
|
{
|
||||||
|
spin_lock(&mylock);
|
||||||
|
WRITE_ONCE(x, 1);
|
||||||
|
spin_unlock(&mylock);
|
||||||
|
WRITE_ONCE(y, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
This converse to the basic rule guarantees that if CPU0() acquires
|
||||||
|
mylock before CPU1(), then both r0 and r1 must be set to the value 0.
|
||||||
|
This also has the consequence that if the final value of r1 is equal
|
||||||
|
to 0, then the final value of r0 must also be equal to 0. In contrast,
|
||||||
|
the weaker rule would say nothing about the final value of r0.
|
||||||
|
|
||||||
|
These examples show only a single pair of CPUs, but the effects of the
|
||||||
|
locking basic rule extend across multiple acquisitions of a given lock
|
||||||
|
across multiple CPUs.
|
||||||
|
|
||||||
|
|
||||||
|
Double-Checked Locking
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
It is well known that more than just a lock is required to make
|
||||||
|
double-checked locking work correctly, This litmus test illustrates
|
||||||
|
one incorrect approach:
|
||||||
|
|
||||||
|
/* See Documentation/litmus-tests/locking/DCL-broken.litmus. */
|
||||||
|
void CPU0(void)
|
||||||
|
{
|
||||||
|
r0 = READ_ONCE(flag);
|
||||||
|
if (r0 == 0) {
|
||||||
|
spin_lock(&lck);
|
||||||
|
r1 = READ_ONCE(flag);
|
||||||
|
if (r1 == 0) {
|
||||||
|
WRITE_ONCE(data, 1);
|
||||||
|
WRITE_ONCE(flag, 1);
|
||||||
|
}
|
||||||
|
spin_unlock(&lck);
|
||||||
|
}
|
||||||
|
r2 = READ_ONCE(data);
|
||||||
|
}
|
||||||
|
/* CPU1() is the exactly the same as CPU0(). */
|
||||||
|
|
||||||
|
There are two problems. First, there is no ordering between the first
|
||||||
|
READ_ONCE() of "flag" and the READ_ONCE() of "data". Second, there is
|
||||||
|
no ordering between the two WRITE_ONCE() calls. It should therefore be
|
||||||
|
no surprise that "r2" can be zero, and a quick herd7 run confirms this.
|
||||||
|
|
||||||
|
One way to fix this is to use smp_load_acquire() and smp_store_release()
|
||||||
|
as shown in this corrected version:
|
||||||
|
|
||||||
|
/* See Documentation/litmus-tests/locking/DCL-fixed.litmus. */
|
||||||
|
void CPU0(void)
|
||||||
|
{
|
||||||
|
r0 = smp_load_acquire(&flag);
|
||||||
|
if (r0 == 0) {
|
||||||
|
spin_lock(&lck);
|
||||||
|
r1 = READ_ONCE(flag);
|
||||||
|
if (r1 == 0) {
|
||||||
|
WRITE_ONCE(data, 1);
|
||||||
|
smp_store_release(&flag, 1);
|
||||||
|
}
|
||||||
|
spin_unlock(&lck);
|
||||||
|
}
|
||||||
|
r2 = READ_ONCE(data);
|
||||||
|
}
|
||||||
|
/* CPU1() is the exactly the same as CPU0(). */
|
||||||
|
|
||||||
|
The smp_load_acquire() guarantees that its load from "flags" will
|
||||||
|
be ordered before the READ_ONCE() from data, thus solving the first
|
||||||
|
problem. The smp_store_release() guarantees that its store will be
|
||||||
|
ordered after the WRITE_ONCE() to "data", solving the second problem.
|
||||||
|
The smp_store_release() pairs with the smp_load_acquire(), thus ensuring
|
||||||
|
that the ordering provided by each actually takes effect. Again, a
|
||||||
|
quick herd7 run confirms this.
|
||||||
|
|
||||||
|
In short, if you access a lock-protected variable without holding the
|
||||||
|
corresponding lock, you will need to provide additional ordering, in
|
||||||
|
this case, via the smp_load_acquire() and the smp_store_release().
|
||||||
|
|
||||||
|
|
||||||
|
Ordering Provided by a Lock to CPUs Not Holding That Lock
|
||||||
|
---------------------------------------------------------
|
||||||
|
|
||||||
|
It is not necessarily the case that accesses ordered by locking will be
|
||||||
|
seen as ordered by CPUs not holding that lock. Consider this example:
|
||||||
|
|
||||||
|
/* See Z6.0+pooncelock+pooncelock+pombonce.litmus. */
|
||||||
|
void CPU0(void)
|
||||||
|
{
|
||||||
|
spin_lock(&mylock);
|
||||||
|
WRITE_ONCE(x, 1);
|
||||||
|
WRITE_ONCE(y, 1);
|
||||||
|
spin_unlock(&mylock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU1(void)
|
||||||
|
{
|
||||||
|
spin_lock(&mylock);
|
||||||
|
r0 = READ_ONCE(y);
|
||||||
|
WRITE_ONCE(z, 1);
|
||||||
|
spin_unlock(&mylock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU2(void)
|
||||||
|
{
|
||||||
|
WRITE_ONCE(z, 2);
|
||||||
|
smp_mb();
|
||||||
|
r1 = READ_ONCE(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
Counter-intuitive though it might be, it is quite possible to have
|
||||||
|
the final value of r0 be 1, the final value of z be 2, and the final
|
||||||
|
value of r1 be 0. The reason for this surprising outcome is that CPU2()
|
||||||
|
never acquired the lock, and thus did not fully benefit from the lock's
|
||||||
|
ordering properties.
|
||||||
|
|
||||||
|
Ordering can be extended to CPUs not holding the lock by careful use
|
||||||
|
of smp_mb__after_spinlock():
|
||||||
|
|
||||||
|
/* See Z6.0+pooncelock+poonceLock+pombonce.litmus. */
|
||||||
|
void CPU0(void)
|
||||||
|
{
|
||||||
|
spin_lock(&mylock);
|
||||||
|
WRITE_ONCE(x, 1);
|
||||||
|
WRITE_ONCE(y, 1);
|
||||||
|
spin_unlock(&mylock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU1(void)
|
||||||
|
{
|
||||||
|
spin_lock(&mylock);
|
||||||
|
smp_mb__after_spinlock();
|
||||||
|
r0 = READ_ONCE(y);
|
||||||
|
WRITE_ONCE(z, 1);
|
||||||
|
spin_unlock(&mylock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU2(void)
|
||||||
|
{
|
||||||
|
WRITE_ONCE(z, 2);
|
||||||
|
smp_mb();
|
||||||
|
r1 = READ_ONCE(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
This addition of smp_mb__after_spinlock() strengthens the lock
|
||||||
|
acquisition sufficiently to rule out the counter-intuitive outcome.
|
||||||
|
In other words, the addition of the smp_mb__after_spinlock() prohibits
|
||||||
|
the counter-intuitive result where the final value of r0 is 1, the final
|
||||||
|
value of z is 2, and the final value of r1 is 0.
|
||||||
|
|
||||||
|
|
||||||
|
No Roach-Motel Locking!
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
This example requires familiarity with the herd7 "filter" clause, so
|
||||||
|
please read up on that topic in litmus-tests.txt.
|
||||||
|
|
||||||
|
It is tempting to allow memory-reference instructions to be pulled
|
||||||
|
into a critical section, but this cannot be allowed in the general case.
|
||||||
|
For example, consider a spin loop preceding a lock-based critical section.
|
||||||
|
Now, herd7 does not model spin loops, but we can emulate one with two
|
||||||
|
loads, with a "filter" clause to constrain the first to return the
|
||||||
|
initial value and the second to return the updated value, as shown below:
|
||||||
|
|
||||||
|
/* See Documentation/litmus-tests/locking/RM-fixed.litmus. */
|
||||||
|
void CPU0(void)
|
||||||
|
{
|
||||||
|
spin_lock(&lck);
|
||||||
|
r2 = atomic_inc_return(&y);
|
||||||
|
WRITE_ONCE(x, 1);
|
||||||
|
spin_unlock(&lck);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU1(void)
|
||||||
|
{
|
||||||
|
r0 = READ_ONCE(x);
|
||||||
|
r1 = READ_ONCE(x);
|
||||||
|
spin_lock(&lck);
|
||||||
|
r2 = atomic_inc_return(&y);
|
||||||
|
spin_unlock(&lck);
|
||||||
|
}
|
||||||
|
|
||||||
|
filter (1:r0=0 /\ 1:r1=1)
|
||||||
|
exists (1:r2=1)
|
||||||
|
|
||||||
|
The variable "x" is the control variable for the emulated spin loop.
|
||||||
|
CPU0() sets it to "1" while holding the lock, and CPU1() emulates the
|
||||||
|
spin loop by reading it twice, first into "1:r0" (which should get the
|
||||||
|
initial value "0") and then into "1:r1" (which should get the updated
|
||||||
|
value "1").
|
||||||
|
|
||||||
|
The "filter" clause takes this into account, constraining "1:r0" to
|
||||||
|
equal "0" and "1:r1" to equal 1.
|
||||||
|
|
||||||
|
Then the "exists" clause checks to see if CPU1() acquired its lock first,
|
||||||
|
which should not happen given the filter clause because CPU0() updates
|
||||||
|
"x" while holding the lock. And herd7 confirms this.
|
||||||
|
|
||||||
|
But suppose that the compiler was permitted to reorder the spin loop
|
||||||
|
into CPU1()'s critical section, like this:
|
||||||
|
|
||||||
|
/* See Documentation/litmus-tests/locking/RM-broken.litmus. */
|
||||||
|
void CPU0(void)
|
||||||
|
{
|
||||||
|
int r2;
|
||||||
|
|
||||||
|
spin_lock(&lck);
|
||||||
|
r2 = atomic_inc_return(&y);
|
||||||
|
WRITE_ONCE(x, 1);
|
||||||
|
spin_unlock(&lck);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPU1(void)
|
||||||
|
{
|
||||||
|
spin_lock(&lck);
|
||||||
|
r0 = READ_ONCE(x);
|
||||||
|
r1 = READ_ONCE(x);
|
||||||
|
r2 = atomic_inc_return(&y);
|
||||||
|
spin_unlock(&lck);
|
||||||
|
}
|
||||||
|
|
||||||
|
filter (1:r0=0 /\ 1:r1=1)
|
||||||
|
exists (1:r2=1)
|
||||||
|
|
||||||
|
If "1:r0" is equal to "0", "1:r1" can never equal "1" because CPU0()
|
||||||
|
cannot update "x" while CPU1() holds the lock. And herd7 confirms this,
|
||||||
|
showing zero executions matching the "filter" criteria.
|
||||||
|
|
||||||
|
And this is why Linux-kernel lock and unlock primitives must prevent
|
||||||
|
code from entering critical sections. It is not sufficient to only
|
||||||
|
prevent code from leaving them.
|
|
@ -1,2 +1,2 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
*.litmus.out
|
*.litmus.*
|
||||||
|
|
|
@ -27,6 +27,14 @@ checklitmushist.sh
|
||||||
checklitmus.sh
|
checklitmus.sh
|
||||||
|
|
||||||
Check a single litmus test against its "Result:" expected result.
|
Check a single litmus test against its "Result:" expected result.
|
||||||
|
Not intended to for manual use.
|
||||||
|
|
||||||
|
checktheselitmus.sh
|
||||||
|
|
||||||
|
Check the specified list of litmus tests against their "Result:"
|
||||||
|
expected results. This takes optional parseargs.sh arguments,
|
||||||
|
followed by "--" followed by pathnames starting from the current
|
||||||
|
directory.
|
||||||
|
|
||||||
cmplitmushist.sh
|
cmplitmushist.sh
|
||||||
|
|
||||||
|
@ -43,10 +51,10 @@ initlitmushist.sh
|
||||||
|
|
||||||
judgelitmus.sh
|
judgelitmus.sh
|
||||||
|
|
||||||
Given a .litmus file and its .litmus.out herd7 output, check the
|
Given a .litmus file and its herd7 output, check the output file
|
||||||
.litmus.out file against the .litmus file's "Result:" comment to
|
against the .litmus file's "Result:" comment to judge whether
|
||||||
judge whether the test ran correctly. Not normally run manually,
|
the test ran correctly. Not normally run manually, provided
|
||||||
provided instead for use by other scripts.
|
instead for use by other scripts.
|
||||||
|
|
||||||
newlitmushist.sh
|
newlitmushist.sh
|
||||||
|
|
||||||
|
@ -68,3 +76,35 @@ runlitmushist.sh
|
||||||
README
|
README
|
||||||
|
|
||||||
This file
|
This file
|
||||||
|
|
||||||
|
Testing a change to LKMM might go as follows:
|
||||||
|
|
||||||
|
# Populate expected results without that change, and
|
||||||
|
# runs for about an hour on an 8-CPU x86 system:
|
||||||
|
scripts/initlitmushist.sh --timeout 10m --procs 10
|
||||||
|
# Incorporate the change:
|
||||||
|
git am -s -3 /path/to/patch # Or whatever it takes.
|
||||||
|
|
||||||
|
# Test the new version of LKMM as follows...
|
||||||
|
|
||||||
|
# Runs in seconds, good smoke test:
|
||||||
|
scripts/checkalllitmus.sh
|
||||||
|
|
||||||
|
# Compares results to those produced by initlitmushist.sh,
|
||||||
|
# and runs for about an hour on an 8-CPU x86 system:
|
||||||
|
scripts/checklitmushist.sh --timeout 10m --procs 10
|
||||||
|
|
||||||
|
# Checks results against Result tags, runs in minutes:
|
||||||
|
scripts/checkghlitmus.sh --timeout 10m --procs 10
|
||||||
|
|
||||||
|
The checkghlitmus.sh should not report errors in cases where the
|
||||||
|
checklitmushist.sh script did not also report a change. However,
|
||||||
|
this check is nevertheless valuable because it can find errors in the
|
||||||
|
original version of LKMM. Note however, that given the above procedure,
|
||||||
|
an error in the original LKMM version that is fixed by the patch will
|
||||||
|
be reported both as a mismatch by checklitmushist.sh and as an error
|
||||||
|
by checkghlitmus.sh. One exception to this rule of thumb is when the
|
||||||
|
test fails completely on the original version of LKMM and passes on the
|
||||||
|
new version. In this case, checklitmushist.sh will report a mismatch
|
||||||
|
and checkghlitmus.sh will report success. This happens when the change
|
||||||
|
to LKMM introduces a new primitive for which litmus tests already existed.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
# SPDX-License-Identifier: GPL-2.0+
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
#
|
#
|
||||||
# Run herd7 tests on all .litmus files in the litmus-tests directory
|
# Run herd7 tests on all .litmus files in the litmus-tests directory
|
||||||
|
@ -8,6 +8,11 @@
|
||||||
# "^^^". It also outputs verification results to a file whose name is
|
# "^^^". It also outputs verification results to a file whose name is
|
||||||
# that of the specified litmus test, but with ".out" appended.
|
# that of the specified litmus test, but with ".out" appended.
|
||||||
#
|
#
|
||||||
|
# If the --hw argument is specified, this script translates the .litmus
|
||||||
|
# C-language file to the specified type of assembly and verifies that.
|
||||||
|
# But in this case, litmus tests using complex synchronization (such as
|
||||||
|
# locking, RCU, and SRCU) are cheerfully ignored.
|
||||||
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# checkalllitmus.sh
|
# checkalllitmus.sh
|
||||||
#
|
#
|
||||||
|
@ -17,7 +22,7 @@
|
||||||
#
|
#
|
||||||
# Copyright IBM Corporation, 2018
|
# Copyright IBM Corporation, 2018
|
||||||
#
|
#
|
||||||
# Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
|
# Author: Paul E. McKenney <paulmck@linux.ibm.com>
|
||||||
|
|
||||||
. scripts/parseargs.sh
|
. scripts/parseargs.sh
|
||||||
|
|
||||||
|
@ -30,29 +35,23 @@ else
|
||||||
exit 255
|
exit 255
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create any new directories that have appeared in the github litmus
|
# Create any new directories that have appeared in the litmus-tests
|
||||||
# repo since the last run.
|
# directory since the last run.
|
||||||
if test "$LKMM_DESTDIR" != "."
|
if test "$LKMM_DESTDIR" != "."
|
||||||
then
|
then
|
||||||
find $litmusdir -type d -print |
|
find $litmusdir -type d -print |
|
||||||
( cd "$LKMM_DESTDIR"; sed -e 's/^/mkdir -p /' | sh )
|
( cd "$LKMM_DESTDIR"; sed -e 's/^/mkdir -p /' | sh )
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Find the checklitmus script. If it is not where we expect it, then
|
|
||||||
# assume that the caller has the PATH environment variable set
|
|
||||||
# appropriately.
|
|
||||||
if test -x scripts/checklitmus.sh
|
|
||||||
then
|
|
||||||
clscript=scripts/checklitmus.sh
|
|
||||||
else
|
|
||||||
clscript=checklitmus.sh
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Run the script on all the litmus tests in the specified directory
|
# Run the script on all the litmus tests in the specified directory
|
||||||
ret=0
|
ret=0
|
||||||
for i in $litmusdir/*.litmus
|
for i in $litmusdir/*.litmus
|
||||||
do
|
do
|
||||||
if ! $clscript $i
|
if test -n "$LKMM_HW_MAP_FILE" && ! scripts/simpletest.sh $i
|
||||||
|
then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if ! scripts/checklitmus.sh $i
|
||||||
then
|
then
|
||||||
ret=1
|
ret=1
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
# parseargs.sh scripts for arguments.
|
# parseargs.sh scripts for arguments.
|
||||||
|
|
||||||
. scripts/parseargs.sh
|
. scripts/parseargs.sh
|
||||||
|
. scripts/hwfnseg.sh
|
||||||
|
|
||||||
T=/tmp/checkghlitmus.sh.$$
|
T=/tmp/checkghlitmus.sh.$$
|
||||||
trap 'rm -rf $T' 0
|
trap 'rm -rf $T' 0
|
||||||
|
@ -32,19 +33,19 @@ then
|
||||||
( cd "$LKMM_DESTDIR"; sed -e 's/^/mkdir -p /' | sh )
|
( cd "$LKMM_DESTDIR"; sed -e 's/^/mkdir -p /' | sh )
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create a list of the C-language litmus tests previously run.
|
# Create a list of the specified litmus tests previously run.
|
||||||
( cd $LKMM_DESTDIR; find litmus -name '*.litmus.out' -print ) |
|
( cd $LKMM_DESTDIR; find litmus -name "*.litmus${hwfnseg}.out" -print ) |
|
||||||
sed -e 's/\.out$//' |
|
sed -e "s/${hwfnseg}"'\.out$//' |
|
||||||
xargs -r egrep -l '^ \* Result: (Never|Sometimes|Always|DEADLOCK)' |
|
xargs -r grep -E -l '^ \* Result: (Never|Sometimes|Always|DEADLOCK)' |
|
||||||
xargs -r grep -L "^P${LKMM_PROCS}"> $T/list-C-already
|
xargs -r grep -L "^P${LKMM_PROCS}"> $T/list-C-already
|
||||||
|
|
||||||
# Create a list of C-language litmus tests with "Result:" commands and
|
# Create a list of C-language litmus tests with "Result:" commands and
|
||||||
# no more than the specified number of processes.
|
# no more than the specified number of processes.
|
||||||
find litmus -name '*.litmus' -exec grep -l -m 1 "^C " {} \; > $T/list-C
|
find litmus -name '*.litmus' -print | mselect7 -arch C > $T/list-C
|
||||||
xargs < $T/list-C -r egrep -l '^ \* Result: (Never|Sometimes|Always|DEADLOCK)' > $T/list-C-result
|
xargs < $T/list-C -r grep -E -l '^ \* Result: (Never|Sometimes|Always|DEADLOCK)' > $T/list-C-result
|
||||||
xargs < $T/list-C-result -r grep -L "^P${LKMM_PROCS}" > $T/list-C-result-short
|
xargs < $T/list-C-result -r grep -L "^P${LKMM_PROCS}" > $T/list-C-result-short
|
||||||
|
|
||||||
# Form list of tests without corresponding .litmus.out files
|
# Form list of tests without corresponding .out files
|
||||||
sort $T/list-C-already $T/list-C-result-short | uniq -u > $T/list-C-needed
|
sort $T/list-C-already $T/list-C-result-short | uniq -u > $T/list-C-needed
|
||||||
|
|
||||||
# Run any needed tests.
|
# Run any needed tests.
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# SPDX-License-Identifier: GPL-2.0+
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
#
|
#
|
||||||
# Run a herd7 test and invokes judgelitmus.sh to check the result against
|
# Invokes runlitmus.sh and judgelitmus.sh on its arguments to run the
|
||||||
# a "Result:" comment within the litmus test. It also outputs verification
|
# specified litmus test and pass judgment on the results.
|
||||||
# results to a file whose name is that of the specified litmus test, but
|
|
||||||
# with ".out" appended.
|
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# checklitmus.sh file.litmus
|
# checklitmus.sh file.litmus
|
||||||
|
@ -15,20 +13,7 @@
|
||||||
#
|
#
|
||||||
# Copyright IBM Corporation, 2018
|
# Copyright IBM Corporation, 2018
|
||||||
#
|
#
|
||||||
# Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
|
# Author: Paul E. McKenney <paulmck@linux.ibm.com>
|
||||||
|
|
||||||
litmus=$1
|
scripts/runlitmus.sh $1
|
||||||
herdoptions=${LKMM_HERD_OPTIONS--conf linux-kernel.cfg}
|
scripts/judgelitmus.sh $1
|
||||||
|
|
||||||
if test -f "$litmus" -a -r "$litmus"
|
|
||||||
then
|
|
||||||
:
|
|
||||||
else
|
|
||||||
echo ' --- ' error: \"$litmus\" is not a readable file
|
|
||||||
exit 255
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo Herd options: $herdoptions > $LKMM_DESTDIR/$litmus.out
|
|
||||||
/usr/bin/time $LKMM_TIMEOUT_CMD herd7 $herdoptions $litmus >> $LKMM_DESTDIR/$litmus.out 2>&1
|
|
||||||
|
|
||||||
scripts/judgelitmus.sh $litmus
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#
|
#
|
||||||
# Copyright IBM Corporation, 2018
|
# Copyright IBM Corporation, 2018
|
||||||
#
|
#
|
||||||
# Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
|
# Author: Paul E. McKenney <paulmck@linux.ibm.com>
|
||||||
|
|
||||||
. scripts/parseargs.sh
|
. scripts/parseargs.sh
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
#
|
||||||
|
# Invokes checklitmus.sh on its arguments to run the specified litmus
|
||||||
|
# test and pass judgment on the results.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# checktheselitmus.sh -- [ file1.litmus [ file2.litmus ... ] ]
|
||||||
|
#
|
||||||
|
# Run this in the directory containing the memory model, specifying the
|
||||||
|
# pathname of the litmus test to check. The usual parseargs.sh arguments
|
||||||
|
# can be specified prior to the "--".
|
||||||
|
#
|
||||||
|
# This script is intended for use with pathnames that start from the
|
||||||
|
# tools/memory-model directory. If some of the pathnames instead start at
|
||||||
|
# the root directory, they all must do so and the "--destdir /" parseargs.sh
|
||||||
|
# argument must be specified prior to the "--". Alternatively, some other
|
||||||
|
# "--destdir" argument can be supplied as long as the needed subdirectories
|
||||||
|
# are populated.
|
||||||
|
#
|
||||||
|
# Copyright IBM Corporation, 2018
|
||||||
|
#
|
||||||
|
# Author: Paul E. McKenney <paulmck@linux.ibm.com>
|
||||||
|
|
||||||
|
. scripts/parseargs.sh
|
||||||
|
|
||||||
|
ret=0
|
||||||
|
for i in "$@"
|
||||||
|
do
|
||||||
|
if scripts/checklitmus.sh $i
|
||||||
|
then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
ret=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if test "$ret" -ne 0
|
||||||
|
then
|
||||||
|
echo " ^^^ VERIFICATION MISMATCHES" 1>&2
|
||||||
|
else
|
||||||
|
echo All litmus tests verified as was expected. 1>&2
|
||||||
|
fi
|
||||||
|
exit $ret
|
|
@ -12,12 +12,49 @@ trap 'rm -rf $T' 0
|
||||||
mkdir $T
|
mkdir $T
|
||||||
|
|
||||||
# comparetest oldpath newpath
|
# comparetest oldpath newpath
|
||||||
|
badmacnam=0
|
||||||
|
timedout=0
|
||||||
perfect=0
|
perfect=0
|
||||||
obsline=0
|
obsline=0
|
||||||
noobsline=0
|
noobsline=0
|
||||||
obsresult=0
|
obsresult=0
|
||||||
badcompare=0
|
badcompare=0
|
||||||
comparetest () {
|
comparetest () {
|
||||||
|
if grep -q ': Unknown macro ' $1 || grep -q ': Unknown macro ' $2
|
||||||
|
then
|
||||||
|
if grep -q ': Unknown macro ' $1
|
||||||
|
then
|
||||||
|
badname=`grep ': Unknown macro ' $1 |
|
||||||
|
sed -e 's/^.*: Unknown macro //' |
|
||||||
|
sed -e 's/ (User error).*$//'`
|
||||||
|
echo 'Current LKMM version does not know "'$badname'"' $1
|
||||||
|
fi
|
||||||
|
if grep -q ': Unknown macro ' $2
|
||||||
|
then
|
||||||
|
badname=`grep ': Unknown macro ' $2 |
|
||||||
|
sed -e 's/^.*: Unknown macro //' |
|
||||||
|
sed -e 's/ (User error).*$//'`
|
||||||
|
echo 'Current LKMM version does not know "'$badname'"' $2
|
||||||
|
fi
|
||||||
|
badmacnam=`expr "$badmacnam" + 1`
|
||||||
|
return 0
|
||||||
|
elif grep -q '^Command exited with non-zero status 124' $1 ||
|
||||||
|
grep -q '^Command exited with non-zero status 124' $2
|
||||||
|
then
|
||||||
|
if grep -q '^Command exited with non-zero status 124' $1 &&
|
||||||
|
grep -q '^Command exited with non-zero status 124' $2
|
||||||
|
then
|
||||||
|
echo Both runs timed out: $2
|
||||||
|
elif grep -q '^Command exited with non-zero status 124' $1
|
||||||
|
then
|
||||||
|
echo Old run timed out: $2
|
||||||
|
elif grep -q '^Command exited with non-zero status 124' $2
|
||||||
|
then
|
||||||
|
echo New run timed out: $2
|
||||||
|
fi
|
||||||
|
timedout=`expr "$timedout" + 1`
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
grep -v 'maxresident)k\|minor)pagefaults\|^Time' $1 > $T/oldout
|
grep -v 'maxresident)k\|minor)pagefaults\|^Time' $1 > $T/oldout
|
||||||
grep -v 'maxresident)k\|minor)pagefaults\|^Time' $2 > $T/newout
|
grep -v 'maxresident)k\|minor)pagefaults\|^Time' $2 > $T/newout
|
||||||
if cmp -s $T/oldout $T/newout && grep -q '^Observation' $1
|
if cmp -s $T/oldout $T/newout && grep -q '^Observation' $1
|
||||||
|
@ -38,7 +75,7 @@ comparetest () {
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo Missing Observation line "(e.g., herd7 timeout)": $2
|
echo Missing Observation line "(e.g., syntax error)": $2
|
||||||
noobsline=`expr "$noobsline" + 1`
|
noobsline=`expr "$noobsline" + 1`
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
@ -72,12 +109,20 @@ then
|
||||||
fi
|
fi
|
||||||
if test "$noobsline" -ne 0
|
if test "$noobsline" -ne 0
|
||||||
then
|
then
|
||||||
echo Missing Observation line "(e.g., herd7 timeout)": $noobsline 1>&2
|
echo Missing Observation line "(e.g., syntax error)": $noobsline 1>&2
|
||||||
fi
|
fi
|
||||||
if test "$obsresult" -ne 0
|
if test "$obsresult" -ne 0
|
||||||
then
|
then
|
||||||
echo Matching Observation Always/Sometimes/Never result: $obsresult 1>&2
|
echo Matching Observation Always/Sometimes/Never result: $obsresult 1>&2
|
||||||
fi
|
fi
|
||||||
|
if test "$timedout" -ne 0
|
||||||
|
then
|
||||||
|
echo "!!!" Timed out: $timedout 1>&2
|
||||||
|
fi
|
||||||
|
if test "$badmacnam" -ne 0
|
||||||
|
then
|
||||||
|
echo "!!!" Unknown primitive: $badmacnam 1>&2
|
||||||
|
fi
|
||||||
if test "$badcompare" -ne 0
|
if test "$badcompare" -ne 0
|
||||||
then
|
then
|
||||||
echo "!!!" Result changed: $badcompare 1>&2
|
echo "!!!" Result changed: $badcompare 1>&2
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
#
|
||||||
|
# Generate the hardware extension to the litmus-test filename, or the
|
||||||
|
# empty string if this is an LKMM run. The extension is placed in
|
||||||
|
# the shell variable hwfnseg.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# . hwfnseg.sh
|
||||||
|
#
|
||||||
|
# Copyright IBM Corporation, 2019
|
||||||
|
#
|
||||||
|
# Author: Paul E. McKenney <paulmck@linux.ibm.com>
|
||||||
|
|
||||||
|
if test -z "$LKMM_HW_MAP_FILE"
|
||||||
|
then
|
||||||
|
hwfnseg=
|
||||||
|
else
|
||||||
|
hwfnseg=".$LKMM_HW_MAP_FILE"
|
||||||
|
fi
|
|
@ -60,7 +60,7 @@ fi
|
||||||
|
|
||||||
# Create a list of the C-language litmus tests with no more than the
|
# Create a list of the C-language litmus tests with no more than the
|
||||||
# specified number of processes (per the --procs argument).
|
# specified number of processes (per the --procs argument).
|
||||||
find litmus -name '*.litmus' -exec grep -l -m 1 "^C " {} \; > $T/list-C
|
find litmus -name '*.litmus' -print | mselect7 -arch C > $T/list-C
|
||||||
xargs < $T/list-C -r grep -L "^P${LKMM_PROCS}" > $T/list-C-short
|
xargs < $T/list-C -r grep -L "^P${LKMM_PROCS}" > $T/list-C-short
|
||||||
|
|
||||||
scripts/runlitmushist.sh < $T/list-C-short
|
scripts/runlitmushist.sh < $T/list-C-short
|
||||||
|
|
|
@ -1,9 +1,22 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# SPDX-License-Identifier: GPL-2.0+
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
#
|
#
|
||||||
# Given a .litmus test and the corresponding .litmus.out file, check
|
# Given a .litmus test and the corresponding litmus output file, check
|
||||||
# the .litmus.out file against the "Result:" comment to judge whether
|
# the .litmus.out file against the "Result:" comment to judge whether the
|
||||||
# the test ran correctly.
|
# test ran correctly. If the --hw argument is omitted, check against the
|
||||||
|
# LKMM output, which is assumed to be in file.litmus.out. If either a
|
||||||
|
# "DATARACE" marker in the "Result:" comment or a "Flag data-race" marker
|
||||||
|
# in the LKMM output is present, the other must also be as well, at least
|
||||||
|
# for litmus tests having a "Result:" comment. In this case, a failure of
|
||||||
|
# the Always/Sometimes/Never portion of the "Result:" prediction will be
|
||||||
|
# noted, but forgiven.
|
||||||
|
#
|
||||||
|
# If the --hw argument is provided, this is assumed to be a hardware
|
||||||
|
# test, and the output is assumed to be in file.litmus.HW.out, where
|
||||||
|
# "HW" is the --hw argument. In addition, non-Sometimes verification
|
||||||
|
# results will be noted, but forgiven. Furthermore, if there is no
|
||||||
|
# "Result:" comment but there is an LKMM .litmus.out file, the observation
|
||||||
|
# in that file will be used to judge the assembly-language verification.
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# judgelitmus.sh file.litmus
|
# judgelitmus.sh file.litmus
|
||||||
|
@ -13,7 +26,7 @@
|
||||||
#
|
#
|
||||||
# Copyright IBM Corporation, 2018
|
# Copyright IBM Corporation, 2018
|
||||||
#
|
#
|
||||||
# Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
|
# Author: Paul E. McKenney <paulmck@linux.ibm.com>
|
||||||
|
|
||||||
litmus=$1
|
litmus=$1
|
||||||
|
|
||||||
|
@ -24,55 +37,120 @@ else
|
||||||
echo ' --- ' error: \"$litmus\" is not a readable file
|
echo ' --- ' error: \"$litmus\" is not a readable file
|
||||||
exit 255
|
exit 255
|
||||||
fi
|
fi
|
||||||
if test -f "$LKMM_DESTDIR/$litmus".out -a -r "$LKMM_DESTDIR/$litmus".out
|
if test -z "$LKMM_HW_MAP_FILE"
|
||||||
|
then
|
||||||
|
litmusout=$litmus.out
|
||||||
|
lkmmout=
|
||||||
|
else
|
||||||
|
litmusout="`echo $litmus |
|
||||||
|
sed -e 's/\.litmus$/.litmus.'${LKMM_HW_MAP_FILE}'/'`.out"
|
||||||
|
lkmmout=$litmus.out
|
||||||
|
fi
|
||||||
|
if test -f "$LKMM_DESTDIR/$litmusout" -a -r "$LKMM_DESTDIR/$litmusout"
|
||||||
then
|
then
|
||||||
:
|
:
|
||||||
else
|
else
|
||||||
echo ' --- ' error: \"$LKMM_DESTDIR/$litmus\".out is not a readable file
|
echo ' --- ' error: \"$LKMM_DESTDIR/$litmusout is not a readable file
|
||||||
exit 255
|
exit 255
|
||||||
fi
|
fi
|
||||||
if grep -q '^ \* Result: ' $litmus
|
if grep -q '^Flag data-race$' "$LKMM_DESTDIR/$litmusout"
|
||||||
then
|
then
|
||||||
outcome=`grep -m 1 '^ \* Result: ' $litmus | awk '{ print $3 }'`
|
datarace_modeled=1
|
||||||
|
fi
|
||||||
|
if grep -q '^[( ]\* Result: ' $litmus
|
||||||
|
then
|
||||||
|
outcome=`grep -m 1 '^[( ]\* Result: ' $litmus | awk '{ print $3 }'`
|
||||||
|
if grep -m1 '^[( ]\* Result: .* DATARACE' $litmus
|
||||||
|
then
|
||||||
|
datarace_predicted=1
|
||||||
|
fi
|
||||||
|
if test -n "$datarace_predicted" -a -z "$datarace_modeled" -a -z "$LKMM_HW_MAP_FILE"
|
||||||
|
then
|
||||||
|
echo '!!! Predicted data race not modeled' $litmus
|
||||||
|
exit 252
|
||||||
|
elif test -z "$datarace_predicted" -a -n "$datarace_modeled"
|
||||||
|
then
|
||||||
|
# Note that hardware models currently don't model data races
|
||||||
|
echo '!!! Unexpected data race modeled' $litmus
|
||||||
|
exit 253
|
||||||
|
fi
|
||||||
|
elif test -n "$LKMM_HW_MAP_FILE" && grep -q '^Observation' $LKMM_DESTDIR/$lkmmout > /dev/null 2>&1
|
||||||
|
then
|
||||||
|
outcome=`grep -m 1 '^Observation ' $LKMM_DESTDIR/$lkmmout | awk '{ print $3 }'`
|
||||||
else
|
else
|
||||||
outcome=specified
|
outcome=specified
|
||||||
fi
|
fi
|
||||||
|
|
||||||
grep '^Observation' $LKMM_DESTDIR/$litmus.out
|
grep '^Observation' $LKMM_DESTDIR/$litmusout
|
||||||
if grep -q '^Observation' $LKMM_DESTDIR/$litmus.out
|
if grep -q '^Observation' $LKMM_DESTDIR/$litmusout
|
||||||
then
|
then
|
||||||
:
|
:
|
||||||
|
elif grep ': Unknown macro ' $LKMM_DESTDIR/$litmusout
|
||||||
|
then
|
||||||
|
badname=`grep ': Unknown macro ' $LKMM_DESTDIR/$litmusout |
|
||||||
|
sed -e 's/^.*: Unknown macro //' |
|
||||||
|
sed -e 's/ (User error).*$//'`
|
||||||
|
badmsg=' !!! Current LKMM version does not know "'$badname'"'" $litmus"
|
||||||
|
echo $badmsg
|
||||||
|
if ! grep -q '!!!' $LKMM_DESTDIR/$litmusout
|
||||||
|
then
|
||||||
|
echo ' !!! '$badmsg >> $LKMM_DESTDIR/$litmusout 2>&1
|
||||||
|
fi
|
||||||
|
exit 254
|
||||||
|
elif grep '^Command exited with non-zero status 124' $LKMM_DESTDIR/$litmusout
|
||||||
|
then
|
||||||
|
echo ' !!! Timeout' $litmus
|
||||||
|
if ! grep -q '!!!' $LKMM_DESTDIR/$litmusout
|
||||||
|
then
|
||||||
|
echo ' !!! Timeout' >> $LKMM_DESTDIR/$litmusout 2>&1
|
||||||
|
fi
|
||||||
|
exit 124
|
||||||
else
|
else
|
||||||
echo ' !!! Verification error' $litmus
|
echo ' !!! Verification error' $litmus
|
||||||
if ! grep -q '!!!' $LKMM_DESTDIR/$litmus.out
|
if ! grep -q '!!!' $LKMM_DESTDIR/$litmusout
|
||||||
then
|
then
|
||||||
echo ' !!! Verification error' >> $LKMM_DESTDIR/$litmus.out 2>&1
|
echo ' !!! Verification error' >> $LKMM_DESTDIR/$litmusout 2>&1
|
||||||
fi
|
fi
|
||||||
exit 255
|
exit 255
|
||||||
fi
|
fi
|
||||||
if test "$outcome" = DEADLOCK
|
if test "$outcome" = DEADLOCK
|
||||||
then
|
then
|
||||||
if grep '^Observation' $LKMM_DESTDIR/$litmus.out | grep -q 'Never 0 0$'
|
if grep '^Observation' $LKMM_DESTDIR/$litmusout | grep -q 'Never 0 0$'
|
||||||
then
|
then
|
||||||
ret=0
|
ret=0
|
||||||
else
|
else
|
||||||
echo " !!! Unexpected non-$outcome verification" $litmus
|
echo " !!! Unexpected non-$outcome verification" $litmus
|
||||||
if ! grep -q '!!!' $LKMM_DESTDIR/$litmus.out
|
if ! grep -q '!!!' $LKMM_DESTDIR/$litmusout
|
||||||
then
|
then
|
||||||
echo " !!! Unexpected non-$outcome verification" >> $LKMM_DESTDIR/$litmus.out 2>&1
|
echo " !!! Unexpected non-$outcome verification" >> $LKMM_DESTDIR/$litmusout 2>&1
|
||||||
fi
|
fi
|
||||||
ret=1
|
ret=1
|
||||||
fi
|
fi
|
||||||
elif grep '^Observation' $LKMM_DESTDIR/$litmus.out | grep -q $outcome || test "$outcome" = Maybe
|
elif grep '^Observation' $LKMM_DESTDIR/$litmusout | grep -q 'Never 0 0$'
|
||||||
|
then
|
||||||
|
echo " !!! Unexpected non-$outcome deadlock" $litmus
|
||||||
|
if ! grep -q '!!!' $LKMM_DESTDIR/$litmusout
|
||||||
|
then
|
||||||
|
echo " !!! Unexpected non-$outcome deadlock" $litmus >> $LKMM_DESTDIR/$litmusout 2>&1
|
||||||
|
fi
|
||||||
|
ret=1
|
||||||
|
elif grep '^Observation' $LKMM_DESTDIR/$litmusout | grep -q $outcome || test "$outcome" = Maybe
|
||||||
then
|
then
|
||||||
ret=0
|
ret=0
|
||||||
else
|
else
|
||||||
echo " !!! Unexpected non-$outcome verification" $litmus
|
if test \( -n "$LKMM_HW_MAP_FILE" -a "$outcome" = Sometimes \) -o -n "$datarace_modeled"
|
||||||
if ! grep -q '!!!' $LKMM_DESTDIR/$litmus.out
|
|
||||||
then
|
then
|
||||||
echo " !!! Unexpected non-$outcome verification" >> $LKMM_DESTDIR/$litmus.out 2>&1
|
flag="--- Forgiven"
|
||||||
|
ret=0
|
||||||
|
else
|
||||||
|
flag="!!! Unexpected"
|
||||||
|
ret=1
|
||||||
|
fi
|
||||||
|
echo " $flag non-$outcome verification" $litmus
|
||||||
|
if ! grep -qe "$flag" $LKMM_DESTDIR/$litmusout
|
||||||
|
then
|
||||||
|
echo " $flag non-$outcome verification" >> $LKMM_DESTDIR/$litmusout 2>&1
|
||||||
fi
|
fi
|
||||||
ret=1
|
|
||||||
fi
|
fi
|
||||||
tail -2 $LKMM_DESTDIR/$litmus.out | head -1
|
tail -2 $LKMM_DESTDIR/$litmusout | head -1
|
||||||
exit $ret
|
exit $ret
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#
|
#
|
||||||
# Copyright IBM Corporation, 2018
|
# Copyright IBM Corporation, 2018
|
||||||
#
|
#
|
||||||
# Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
|
# Author: Paul E. McKenney <paulmck@linux.ibm.com>
|
||||||
|
|
||||||
. scripts/parseargs.sh
|
. scripts/parseargs.sh
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ fi
|
||||||
|
|
||||||
# Form full list of litmus tests with no more than the specified
|
# Form full list of litmus tests with no more than the specified
|
||||||
# number of processes (per the --procs argument).
|
# number of processes (per the --procs argument).
|
||||||
find litmus -name '*.litmus' -exec grep -l -m 1 "^C " {} \; > $T/list-C-all
|
find litmus -name '*.litmus' -print | mselect7 -arch C > $T/list-C-all
|
||||||
xargs < $T/list-C-all -r grep -L "^P${LKMM_PROCS}" > $T/list-C-short
|
xargs < $T/list-C-all -r grep -L "^P${LKMM_PROCS}" > $T/list-C-short
|
||||||
|
|
||||||
# Form list of new tests. Note: This does not handle litmus-test deletion!
|
# Form list of new tests. Note: This does not handle litmus-test deletion!
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# SPDX-License-Identifier: GPL-2.0+
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
#
|
#
|
||||||
# the corresponding .litmus.out file, and does not judge the result.
|
# Parse arguments common to the various scripts.
|
||||||
#
|
#
|
||||||
# . scripts/parseargs.sh
|
# . scripts/parseargs.sh
|
||||||
#
|
#
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
#
|
#
|
||||||
# Copyright IBM Corporation, 2018
|
# Copyright IBM Corporation, 2018
|
||||||
#
|
#
|
||||||
# Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
|
# Author: Paul E. McKenney <paulmck@linux.ibm.com>
|
||||||
|
|
||||||
T=/tmp/parseargs.sh.$$
|
T=/tmp/parseargs.sh.$$
|
||||||
mkdir $T
|
mkdir $T
|
||||||
|
@ -27,6 +27,7 @@ initparam () {
|
||||||
|
|
||||||
initparam LKMM_DESTDIR "."
|
initparam LKMM_DESTDIR "."
|
||||||
initparam LKMM_HERD_OPTIONS "-conf linux-kernel.cfg"
|
initparam LKMM_HERD_OPTIONS "-conf linux-kernel.cfg"
|
||||||
|
initparam LKMM_HW_MAP_FILE ""
|
||||||
initparam LKMM_JOBS `getconf _NPROCESSORS_ONLN`
|
initparam LKMM_JOBS `getconf _NPROCESSORS_ONLN`
|
||||||
initparam LKMM_PROCS "3"
|
initparam LKMM_PROCS "3"
|
||||||
initparam LKMM_TIMEOUT "1m"
|
initparam LKMM_TIMEOUT "1m"
|
||||||
|
@ -37,10 +38,11 @@ usagehelp () {
|
||||||
echo "Usage $scriptname [ arguments ]"
|
echo "Usage $scriptname [ arguments ]"
|
||||||
echo " --destdir path (place for .litmus.out, default by .litmus)"
|
echo " --destdir path (place for .litmus.out, default by .litmus)"
|
||||||
echo " --herdopts -conf linux-kernel.cfg ..."
|
echo " --herdopts -conf linux-kernel.cfg ..."
|
||||||
|
echo " --hw AArch64"
|
||||||
echo " --jobs N (number of jobs, default one per CPU)"
|
echo " --jobs N (number of jobs, default one per CPU)"
|
||||||
echo " --procs N (litmus tests with at most this many processes)"
|
echo " --procs N (litmus tests with at most this many processes)"
|
||||||
echo " --timeout N (herd7 timeout (e.g., 10s, 1m, 2hr, 1d, '')"
|
echo " --timeout N (herd7 timeout (e.g., 10s, 1m, 2hr, 1d, '')"
|
||||||
echo "Defaults: --destdir '$LKMM_DESTDIR_DEF' --herdopts '$LKMM_HERD_OPTIONS_DEF' --jobs '$LKMM_JOBS_DEF' --procs '$LKMM_PROCS_DEF' --timeout '$LKMM_TIMEOUT_DEF'"
|
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'"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +83,7 @@ do
|
||||||
echo "Cannot create directory --destdir '$LKMM_DESTDIR'"
|
echo "Cannot create directory --destdir '$LKMM_DESTDIR'"
|
||||||
usage
|
usage
|
||||||
fi
|
fi
|
||||||
if test -d "$LKMM_DESTDIR" -a -w "$LKMM_DESTDIR" -a -x "$LKMM_DESTDIR"
|
if test -d "$LKMM_DESTDIR" -a -x "$LKMM_DESTDIR"
|
||||||
then
|
then
|
||||||
:
|
:
|
||||||
else
|
else
|
||||||
|
@ -95,6 +97,11 @@ do
|
||||||
LKMM_HERD_OPTIONS="$2"
|
LKMM_HERD_OPTIONS="$2"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
--hw)
|
||||||
|
checkarg --hw "(.map file architecture name)" "$#" "$2" '^[A-Za-z0-9_-]\+' '^--'
|
||||||
|
LKMM_HW_MAP_FILE="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
-j[1-9]*)
|
-j[1-9]*)
|
||||||
njobs="`echo $1 | sed -e 's/^-j//'`"
|
njobs="`echo $1 | sed -e 's/^-j//'`"
|
||||||
trailchars="`echo $njobs | sed -e 's/[0-9]\+\(.*\)$/\1/'`"
|
trailchars="`echo $njobs | sed -e 's/[0-9]\+\(.*\)$/\1/'`"
|
||||||
|
@ -106,7 +113,7 @@ do
|
||||||
LKMM_JOBS="`echo $njobs | sed -e 's/^\([0-9]\+\).*$/\1/'`"
|
LKMM_JOBS="`echo $njobs | sed -e 's/^\([0-9]\+\).*$/\1/'`"
|
||||||
;;
|
;;
|
||||||
--jobs|--job|-j)
|
--jobs|--job|-j)
|
||||||
checkarg --jobs "(number)" "$#" "$2" '^[1-9][0-9]\+$' '^--'
|
checkarg --jobs "(number)" "$#" "$2" '^[1-9][0-9]*$' '^--'
|
||||||
LKMM_JOBS="$2"
|
LKMM_JOBS="$2"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
@ -120,6 +127,10 @@ do
|
||||||
LKMM_TIMEOUT="$2"
|
LKMM_TIMEOUT="$2"
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo Unknown argument $1
|
echo Unknown argument $1
|
||||||
usage
|
usage
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
#
|
||||||
|
# Without the -hw argument, runs a herd7 test and outputs verification
|
||||||
|
# results to a file whose name is that of the specified litmus test,
|
||||||
|
# but with ".out" appended.
|
||||||
|
#
|
||||||
|
# If the --hw argument is specified, this script translates the .litmus
|
||||||
|
# C-language file to the specified type of assembly and verifies that.
|
||||||
|
# But in this case, litmus tests using complex synchronization (such as
|
||||||
|
# locking, RCU, and SRCU) are cheerfully ignored.
|
||||||
|
#
|
||||||
|
# Either way, return the status of the herd7 command.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# runlitmus.sh file.litmus
|
||||||
|
#
|
||||||
|
# Run this in the directory containing the memory model, specifying the
|
||||||
|
# pathname of the litmus test to check. The caller is expected to have
|
||||||
|
# properly set up the LKMM environment variables.
|
||||||
|
#
|
||||||
|
# Copyright IBM Corporation, 2019
|
||||||
|
#
|
||||||
|
# Author: Paul E. McKenney <paulmck@linux.ibm.com>
|
||||||
|
|
||||||
|
litmus=$1
|
||||||
|
if test -f "$litmus" -a -r "$litmus"
|
||||||
|
then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
echo ' !!! ' error: \"$litmus\" is not a readable file
|
||||||
|
exit 255
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$LKMM_HW_MAP_FILE" -o ! -e $LKMM_DESTDIR/$litmus.out
|
||||||
|
then
|
||||||
|
# LKMM run
|
||||||
|
herdoptions=${LKMM_HERD_OPTIONS--conf linux-kernel.cfg}
|
||||||
|
echo Herd options: $herdoptions > $LKMM_DESTDIR/$litmus.out
|
||||||
|
/usr/bin/time $LKMM_TIMEOUT_CMD herd7 $herdoptions $litmus >> $LKMM_DESTDIR/$litmus.out 2>&1
|
||||||
|
ret=$?
|
||||||
|
if test -z "$LKMM_HW_MAP_FILE"
|
||||||
|
then
|
||||||
|
exit $ret
|
||||||
|
fi
|
||||||
|
echo " --- " Automatically generated LKMM output for '"'--hw $LKMM_HW_MAP_FILE'"' run
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Hardware run
|
||||||
|
|
||||||
|
T=/tmp/checklitmushw.sh.$$
|
||||||
|
trap 'rm -rf $T' 0 2
|
||||||
|
mkdir $T
|
||||||
|
|
||||||
|
# Generate filenames
|
||||||
|
mapfile="Linux2${LKMM_HW_MAP_FILE}.map"
|
||||||
|
themefile="$T/${LKMM_HW_MAP_FILE}.theme"
|
||||||
|
herdoptions="-model $LKMM_HW_CAT_FILE"
|
||||||
|
hwlitmus=`echo $litmus | sed -e 's/\.litmus$/.litmus.'${LKMM_HW_MAP_FILE}'/'`
|
||||||
|
hwlitmusfile=`echo $hwlitmus | sed -e 's,^.*/,,'`
|
||||||
|
|
||||||
|
# Don't run on litmus tests with complex synchronization
|
||||||
|
if ! scripts/simpletest.sh $litmus
|
||||||
|
then
|
||||||
|
echo ' --- ' error: \"$litmus\" contains locking, RCU, or SRCU
|
||||||
|
exit 254
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate the assembly code and run herd7 on it.
|
||||||
|
gen_theme7 -n 10 -map $mapfile -call Linux.call > $themefile
|
||||||
|
jingle7 -v -theme $themefile $litmus > $LKMM_DESTDIR/$hwlitmus 2> $T/$hwlitmusfile.jingle7.out
|
||||||
|
if grep -q "Generated 0 tests" $T/$hwlitmusfile.jingle7.out
|
||||||
|
then
|
||||||
|
echo ' !!! ' jingle7 failed, errors in $hwlitmus.err
|
||||||
|
cp $T/$hwlitmusfile.jingle7.out $LKMM_DESTDIR/$hwlitmus.err
|
||||||
|
exit 253
|
||||||
|
fi
|
||||||
|
/usr/bin/time $LKMM_TIMEOUT_CMD herd7 -unroll 0 $LKMM_DESTDIR/$hwlitmus > $LKMM_DESTDIR/$hwlitmus.out 2>&1
|
||||||
|
|
||||||
|
exit $?
|
|
@ -13,7 +13,9 @@
|
||||||
#
|
#
|
||||||
# Copyright IBM Corporation, 2018
|
# Copyright IBM Corporation, 2018
|
||||||
#
|
#
|
||||||
# Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
|
# Author: Paul E. McKenney <paulmck@linux.ibm.com>
|
||||||
|
|
||||||
|
. scripts/hwfnseg.sh
|
||||||
|
|
||||||
T=/tmp/runlitmushist.sh.$$
|
T=/tmp/runlitmushist.sh.$$
|
||||||
trap 'rm -rf $T' 0
|
trap 'rm -rf $T' 0
|
||||||
|
@ -30,15 +32,12 @@ fi
|
||||||
# Prefixes for per-CPU scripts
|
# Prefixes for per-CPU scripts
|
||||||
for ((i=0;i<$LKMM_JOBS;i++))
|
for ((i=0;i<$LKMM_JOBS;i++))
|
||||||
do
|
do
|
||||||
echo dir="$LKMM_DESTDIR" > $T/$i.sh
|
|
||||||
echo T=$T >> $T/$i.sh
|
echo T=$T >> $T/$i.sh
|
||||||
echo herdoptions=\"$LKMM_HERD_OPTIONS\" >> $T/$i.sh
|
|
||||||
cat << '___EOF___' >> $T/$i.sh
|
cat << '___EOF___' >> $T/$i.sh
|
||||||
runtest () {
|
runtest () {
|
||||||
echo ' ... ' /usr/bin/time $LKMM_TIMEOUT_CMD herd7 $herdoptions $1 '>' $dir/$1.out '2>&1'
|
if scripts/runlitmus.sh $1
|
||||||
if /usr/bin/time $LKMM_TIMEOUT_CMD herd7 $herdoptions $1 > $dir/$1.out 2>&1
|
|
||||||
then
|
then
|
||||||
if ! grep -q '^Observation ' $dir/$1.out
|
if ! grep -q '^Observation ' $LKMM_DESTDIR/$1$2.out
|
||||||
then
|
then
|
||||||
echo ' !!! Herd failed, no Observation:' $1
|
echo ' !!! Herd failed, no Observation:' $1
|
||||||
fi
|
fi
|
||||||
|
@ -47,10 +46,16 @@ do
|
||||||
if test "$exitcode" -eq 124
|
if test "$exitcode" -eq 124
|
||||||
then
|
then
|
||||||
exitmsg="timed out"
|
exitmsg="timed out"
|
||||||
|
elif test "$exitcode" -eq 253
|
||||||
|
then
|
||||||
|
exitmsg=
|
||||||
else
|
else
|
||||||
exitmsg="failed, exit code $exitcode"
|
exitmsg="failed, exit code $exitcode"
|
||||||
fi
|
fi
|
||||||
echo ' !!! Herd' ${exitmsg}: $1
|
if test -n "$exitmsg"
|
||||||
|
then
|
||||||
|
echo ' !!! Herd' ${exitmsg}: $1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
___EOF___
|
___EOF___
|
||||||
|
@ -59,11 +64,13 @@ done
|
||||||
awk -v q="'" -v b='\\' '
|
awk -v q="'" -v b='\\' '
|
||||||
{
|
{
|
||||||
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
|
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
|
||||||
}' | bash |
|
}' | sh | sort -k1n |
|
||||||
sort -k1n |
|
awk -v dq='"' -v hwfnseg="$hwfnseg" -v ncpu="$LKMM_JOBS" -v t="$T" '
|
||||||
awk -v ncpu=$LKMM_JOBS -v t=$T '
|
|
||||||
{
|
{
|
||||||
print "runtest " $2 >> t "/" NR % ncpu ".sh";
|
print "if test -z " dq hwfnseg dq " || scripts/simpletest.sh " dq $2 dq
|
||||||
|
print "then"
|
||||||
|
print "\techo runtest " dq $2 dq " " hwfnseg " >> " t "/" NR % ncpu ".sh";
|
||||||
|
print "fi"
|
||||||
}
|
}
|
||||||
|
|
||||||
END {
|
END {
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
#
|
||||||
|
# Give zero status if this is a simple test and non-zero otherwise.
|
||||||
|
# Simple tests do not contain locking, RCU, or SRCU.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# simpletest.sh file.litmus
|
||||||
|
#
|
||||||
|
# Copyright IBM Corporation, 2019
|
||||||
|
#
|
||||||
|
# Author: Paul E. McKenney <paulmck@linux.ibm.com>
|
||||||
|
|
||||||
|
|
||||||
|
litmus=$1
|
||||||
|
|
||||||
|
if test -f "$litmus" -a -r "$litmus"
|
||||||
|
then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
echo ' --- ' error: \"$litmus\" is not a readable file
|
||||||
|
exit 255
|
||||||
|
fi
|
||||||
|
exclude="^[[:space:]]*\("
|
||||||
|
exclude="${exclude}spin_lock(\|spin_unlock(\|spin_trylock(\|spin_is_locked("
|
||||||
|
exclude="${exclude}\|rcu_read_lock(\|rcu_read_unlock("
|
||||||
|
exclude="${exclude}\|synchronize_rcu(\|synchronize_rcu_expedited("
|
||||||
|
exclude="${exclude}\|srcu_read_lock(\|srcu_read_unlock("
|
||||||
|
exclude="${exclude}\|synchronize_srcu(\|synchronize_srcu_expedited("
|
||||||
|
exclude="${exclude}\)"
|
||||||
|
if grep -q $exclude $litmus
|
||||||
|
then
|
||||||
|
exit 255
|
||||||
|
fi
|
||||||
|
exit 0
|
Загрузка…
Ссылка в новой задаче