Re: [PATCH] Power5,Power6 BSR driver
From: Sonny Rao <hidden>
Date: 2008-06-18 07:15:30
On Mon, Jun 16, 2008 at 01:53:44PM -0500, jschopp@austin.ibm.com wrote:
From: Sonny Rao <redacted> 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;
}