Messages in this thread | | | Date | Fri, 26 Nov 1999 23:47:46 +0100 (CET) | From | Ingo Molnar <> | Subject | Re: spin_unlock optimization(i386) |
| |
On Fri, 26 Nov 1999, Erich Boleyn wrote:
> So, as I said before, IA32 isn't reordering anything in a visible way, > it's effectively "shielding" the address on cpu1 because it hasn't > gotten out of it's store queue yet.
hm, then why does causal.c trigger a causality violation on a 8-way box? Interestingly it's getting triggered if there are two copies (4 threads total) running. [which could be simply just randomness added to the system bus load and thus statistically finds the window]
the basic causality test is what was analyzed yesterday:
CPU0 CPU1
for (;;) { for (;;) { i++; a = j; j++; b = i; } if (a < b) BUG() }
i've extended this to do the same thing in a 'symmetric' way, still two threads on two CPUs, but now both are doing loads and stores and the above causality test:
CPU0 CPU1
for (;;) { for (;;) { i1++; i2++; j1++; j2++; a = j2; a = j1; b = i2; b = i1; if (a < b) if (a < b) BUG(); BUG(); } }
(i've attached the code again. i1, j1, i2, j2 are shared global, a, b are private local variables.)
note that this cannot be reproduced on Andrea's dual-PII box (neither on my dual-PIII box), but can be reproduced on my 8-way Xeon box, if two copies of the above are running. [maybe if i added delay timings to the above then we could trigger it on dual boxes too] 'two copies' means two independent pairs of the above.
the code is simple and obvious enough extension of the most trivial causality test, but it doesnt work.
Ingo
/* * Linux SMP memory model and SMP causality tester, Ingo Molnar * * Copyright (C) 1999, Ingo Molnar <mingo@redhat.com> */
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <sys/wait.h> #include <linux/unistd.h>
volatile static int started = 0; static int numthreads; int lock = 0;
#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") #define inc(x) __asm__ __volatile__ ("incl %0": "=m"(x): :"memory") #define lock_inc(x) __asm__ __volatile__ ("lock; incl %0": "=m"(x): :"memory")
volatile int data1 = 0, data2 = 0; volatile int data3 = 0, data4 = 0;
static int test_locking(int cpu) { int a, b, i = 0;
switch (cpu) { case 0: for (;;) { i++; if (lock) { lock_inc(data3); lock_inc(data4); } else { inc(data3); inc(data4); } if (i > 1000000000) { data4 = 0; data3 = 0; i = 0; } b = data2; a = data1; if (a < b) { printf("<%d> %d %d\n", i, a, b); return 1; } } case 1: for (;;) { i++; if (lock) { lock_inc(data1); lock_inc(data2); } else { inc(data1); inc(data2); } if (i > 1000000000) { data2 = 0; data1 = 0; i = 0; } b = data4; a = data3; if (a < b) { printf("<%d> %d %d\n", i, a, b); return 1; } } default: return 1; } }
void test_causality (int cpu) { asm volatile ("lock; incl %0":"=m"(started)); while (numthreads != started) mb();
test_locking(cpu);
printf("<thread%d> BROKE causality! Weakly ordered memory?\n", cpu); exit(0); }
static void start_thread(int cpu) { char *newstack = (char *) malloc(10000) + 5000;
*newstack = cpu; __asm__ __volatile__( "int $0x80 \n\t" /* Linux/i386 system call */ "testl %0,%0 \n\t" /* check return value */ "jne 1f \n\t" /* jump if parent */ "call *%2 \n\t" /* start subthread function */ "movl %1,%0 \n\t" "int $0x80 \n\t" /* exit system call: exit subthread */ "1: \n\t" : :"a" (__NR_clone),"i" (__NR_exit), "r" (test_causality), "b" (0xaf00 | SIGCHLD), "c" (newstack)); return; }
int main (int argc, char * * argv) { int i;
if (argc != 3) { printf("usage: causal <LOCK:0/1> <kids:3-8>\n"); exit(0); } lock = atol(argv[1]); numthreads = atol(argv[2]);
for (i = 0; i < numthreads; i++) { start_thread(i); } return (0); }
| |