Re: spin_unlock optimization(i386)

Oliver Xymoron (oxymoron@waste.org)
Fri, 26 Nov 1999 12:07:52 -0600 (CST)


On Fri, 26 Nov 1999, Manfred Spraul wrote:

> You you please look at my program?

I took a second look at it and it still looks like reads are getting
reordered. I rewrote it a bit for my own readability, perhaps other people
would like to look at this version:

/*
* movopt: test for Intel memory ordering.
* Copyright (C) 1999 by Manfred Spraul.
* restructuring by oxymoron@waste.org
*
* Redistribution of this file is permitted under the terms of the GNU
* Public License (GPL)
* $Header: /pub/cvs/ms/movopt/movopt.cpp,v 1.3 1999/11/25 23:38:44 manfreds Ex
p $
*/

/*
cc -o foo -lpthreads foo.c

NOTE: this code will run _extremely_ slowly on UP systems

func1 and func2 are the functions that may race with each other

cpu1 and cpu2 are thread functions that synchronize func1 and func2
while adjusting timings
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>

#define USE_MB 0
#define USE_ASM 1

volatile int start = 0;
volatile int current_state = 0;
volatile int lock = 1;
volatile int ready = 0;
volatile int go = 0;

#if USE_ASM == 0 /* doesn't compile, here for explanation */

static inline void func1()
{
set_current_state(1);
if(lock!=1)
while (current_state!=0)
;
}

static inline void func2()
{
lock=0;
current_state=0;
mb();
}

#else
static inline void func1()
{
__asm__ __volatile(
#if USE_MB == 0
"movl $1,%1\n\t" /* set current_state = 1 */
#else
"lock;bts $0,%1\n\t"
#endif
"movl %0,%%eax\n\t" /* lock into %%eax */
"cmpl $1,%%eax\n\t"
"jne dont_sleep\n"
"retry:\n\t"
"movl %1, %%eax\n\t"
"cmpl $0,%%eax\n\t"
"jne retry\n"
"dont_sleep:\n"
: /* no output */
: "m" (lock), "m" (current_state)
: "eax", "cc", "memory");
}

static inline void func2()
{
__asm__ __volatile(
"movl $0,%0\n\t"
"movl $0,%1\n\t"
"lock; addl $0,(%%esp)\n\t" /* flush our write buffers*/
: /* no output */
: "m" (lock), "m" (current_state)
: "memory");
}
#endif

void* cpu1(void* param)
{
/* 1: always sleep
10 000: never sleep
PII/350: lock-up at delay=217
*/
volatile int delay = 1;

int i=0,j;

while(!start)
;

for(;i<50000000;i++) {
lock = 1;
current_state = 0;
go = 0;
while(!ready)
;
go = 1;

for(j=0;j<delay;j++)
;

func1();

if((i%5000)==0) {
printf("delay %d: ok\n",delay);
delay++;
}
}

printf("thread %d finished.\n",(int)param);
exit(0);
}

void* cpu2(void* param)
{
/* increase this value if no lock-up occurs,
eg: 2000
*/
volatile int delay2 = 300;

int i=0,j;

while(!start)
;

for(;;) {
ready = 1;
while(!go)
;
ready = 0;
go = 0;

for(j=0;j<delay2;j++)
;

func2();
}
}

typedef void *threadfunc(void *);

void start_thread(threadfunc *f)
{
pthread_t thread;
int res;

res = pthread_create(&thread,NULL,f,NULL);
if(res != 0)
assert(0);
}

int main()
{
printf("movopt:\n");
start_thread(cpu1);
start_thread(cpu2);
printf(" starting, please wait.\n");
fflush(stdout);
start = 1;
for(;;) sleep(1000);
}

--
 "Love the dolphins," she advised him. "Write by W.A.S.T.E.." 

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/