lkml.org 
[lkml]   [1999]   [Nov]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: 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);
}

\
 
 \ /
  Last update: 2005-03-22 13:55    [W:0.144 / U:0.264 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site