Subject: Re: [PATCH] Power5,Power6 BSR driver

From: Sonny Rao <[email-masked]>
Date: Wed, 18 Jun 2008 01:53:46 -0500

On Mon, Jun 16, 2008 at 01:53:44PM -0500, [email-masked] wrote:
> From: Sonny Rao <[email-masked]>
> 
> Adds a character driver for BSR support on IBM POWER systems including 
> Power5 and Power6.  The BSR is an optional processor facility not currently 
> implemented by any other processors.  It's primary purpose is large SMP 
> synchronization.  More details on the BSR are in comments to the code which 
> follows.
> 

Here's a basic, quick n' dirty testcase I have
Remember to link w/ -lpthread

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <pthread.h>

static void rw_test(char *map, unsigned bytes)
{
	unsigned i;
	printf("reading current bsr values\n");
	for (i=0 ; i < bytes;i++) {
		printf("bsr[%u] = 0x%x\n",
		       i, map[i]);
	}
	printf("writing all 1s into bsr\n");
	for (i=0; i< bytes; i++) {
		map[i] = 0xff;
	}
	printf("reading current bsr values\n");
	for (i=0 ; i < bytes;i++) {
		printf("bsr[%u] = 0x%x\n",
		       i, map[i]);
	}
	printf("writing all byte numbers into bsr\n");
	for (i=0; i< bytes; i++) {
		map[i] = i;
	}
	printf("reading current bsr values\n");
	for (i=0 ; i < bytes;i++) {
		printf("bsr[%u] = 0x%x\n",
		       i, map[i]);
	}

}

struct thread_data {
	pthread_t thread;
	volatile char *map;
	unsigned id;
	uint64_t counter;
};

#define be_busy(cycles) do { \
  __asm__ __volatile__ ("1: addic. %0,%0,-1\n" \
			"   bne 1b\n" : :"r" (cycles) : "cr0"); } while(0)
#define  __sync() do { \
  __asm__ __volatile__ ("sync\n" ::: "memory"); } while(0)

static
void * thread_fn(void * data)
{
	struct thread_data *mydata = data;

	__sync();
	mydata->map[mydata->id]++;
	__sync();
	while (mydata->map[0] == 0) {
		/* be_busy(10); */
		mydata->counter++;
	}
	return NULL;
}

static
void pthread_test(volatile char *map, unsigned num)
{
	struct thread_data *pthreads;
	unsigned i;

	pthreads = malloc(sizeof(struct thread_data) * num);
	if (!pthreads) {
		perror("malloc");
		return;
	}
	for (i=0; i<num; i++) {
		map[i] = 0;
	}
	__sync();
	for (i=1; i< num;i++) {
		struct thread_data *cur = &pthreads[i];
		cur->map = map;
		cur->id  = i;
		if (pthread_create(&cur->thread, NULL, thread_fn, cur)) {
			perror("pthread_create");
			exit(1);
		}
	}
	for (i=1; i<num;i++) {
		char status;
		do {
			status = map[i];
		} while(status == 0);
	}
	__sync();
	map[0] = 1;
	__sync();
	for (i=1; i<num;i++) {
		if (pthread_join(pthreads[i].thread, NULL)) {
			perror("pthread_join");
		}
		printf("%03u %llu\n", pthreads[i].id, pthreads[i].counter);
	}
	free(pthreads);
}

int main (int argc, char *argv[])
{
	char *file;
	int fd;
	char *map;
	int pagesize = getpagesize();
	unsigned  bytes;

	if (argc < 3) {
		fprintf(stderr, "usage: <bsr dev> <num bytes>\n");
		return 1;
	}
	file = argv[1];
	bytes = strtoul(argv[2], NULL, 0);
	fd = open(file, O_RDWR);
	if (fd < 0) {
		perror("open");
		return 1;
	}
	map = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	if (!map) {
		perror("mmap");
		close(fd);
		return 1;
	}

	rw_test(map, bytes);
	pthread_test(map, bytes);
	close(fd);
	return 0;
}