1
0
Fork 0

Initial commit of version in blog post

master
Gavin Howard 2 years ago
commit b719225fe8
Signed by: gavin
GPG Key ID: C08038BDF280D33E
  1. 17
      Makefile
  2. 287
      test.c

@ -0,0 +1,17 @@
all: shmem kernel
run: run_shmem run_kernel
shmem:
$(CC) -DSHMEM $(CFLAGS) -o shmem test.c
run_shmem: shmem
./shmem
kernel:
$(CC) -DKERNEL $(CFLAGS) -o kernel test.c
run_kernel: kernel
./kernel
clean:
rm -rf shmem kernel

287
test.c

@ -0,0 +1,287 @@
#define _GNU_SOURCE
#define _XOPEN_SOURCE (700)
#include <stdlib.h>
#include <sched.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "../time.c"
#ifndef KERNEL
#ifndef SHMEM
#error Must define one of SHMEM or KERNEL
#endif // SHMEM
#else //KERNEL
#ifdef SHMEM
#error Must define only one of SHMEM or KERNEL
#endif // SHMEM
#endif // KERNEL
#define LIMIT ((size_t) 100000000)
#define CONSUMER(p) ((p) == 0)
#define SIZE ((1 << 12) / sizeof(size_t))
#define MASK (SIZE - 1)
#ifdef SHMEM
typedef struct shmem
{
size_t* a;
volatile sig_atomic_t* sent;
volatile sig_atomic_t* read;
} Shmem;
Shmem s;
#else // SHMEM
int in;
int out;
typedef union size
{
size_t s;
char a[sizeof(size_t)];
} Size;
#endif // SHMEM
void err(char* msg, int exit_code)
{
fprintf(stderr, "error: %s\n", msg);
exit(exit_code);
}
#ifdef SHMEM
Shmem setup_shmem(void)
{
Shmem s;
// Our memory buffer will be readable and writable:
int protection = PROT_READ | PROT_WRITE;
// The buffer will be shared (meaning other processes can access it), but
// anonymous (meaning third-party processes cannot obtain an address for
// it), so only this process and its children will be able to use it:
int visibility = MAP_SHARED | MAP_ANONYMOUS;
// The remaining parameters to `mmap()` are not important for this use case,
// but the manpage for `mmap` explains their purpose.
s.a = mmap(NULL, 1 << 12, protection, visibility, -1, 0);
if (s.a == NULL) err("mmap of array failed", 5);
s.sent = mmap(NULL, sizeof(size_t), protection, visibility, -1, 0);
if (s.sent == NULL) err("mmap of sent failed", 6);
s.read = mmap(NULL, sizeof(size_t), protection, visibility, -1, 0);
if (s.read == NULL) err("mmap of read failed", 7);
return s;
}
size_t get_val(volatile sig_atomic_t* v)
{
sig_atomic_t val1, val2;
do {
val1 = *v;
val2 = *v;
} while (val1 != val2);
return val1;
}
#endif // SHMEM
size_t receive(sig_atomic_t* rd)
{
size_t idx;
#ifdef KERNEL
Size s;
ssize_t r;
r = read(in, s.a, sizeof(size_t));
/*fprintf(stderr, "r: %zd\n", r);*/
if (r != sizeof(size_t) && r != 0) err("could not read", 13);
idx = s.s;
#else // KERNEL
sig_atomic_t val;
do {
val = get_val(s.sent);
} while ((*rd & MASK) == (val & MASK));
idx = s.a[(*rd) & MASK];
*rd += 1;
*s.read = *rd;
#endif // KERNEL
return idx;
}
void send(size_t idx, sig_atomic_t* st)
{
*st += 1;
#ifdef KERNEL
Size s;
ssize_t w;
s.s = idx;
errno = 0;
w = write(out, s.a, sizeof(size_t));
if (w != sizeof(size_t)) err("could not write", 14);
#else // KERNEL
sig_atomic_t val;
do {
val = get_val(s.read);
} while ((*st & MASK) == (val & MASK));
s.a[(*st - 1) & MASK] = idx;
*s.sent = *st;
#endif // KERNEL
}
int main(int argc, char* argv[])
{
size_t i, sum = 0;
sig_atomic_t processed = 0;
cpu_set_t set;
pid_t pid;
int pipefds[2];
TimeSpec start, end, diff;
int status;
nice(-20);
ts_time(&start);
#ifdef SHMEM
s = setup_shmem();
#else
signal(SIGPIPE, SIG_IGN);
if (pipe2(pipefds, 0) < 0)
{
err("couldn't create pipe", 8);
}
#endif // SHMEM
pid = fork();
if (pid < 0)
{
err("fork failed", 1);
}
#ifdef KERNEL
if (pid == 0)
{
close(pipefds[1]);
in = pipefds[0];
}
else
{
close(pipefds[0]);
out = pipefds[1];
}
#endif // KERNEL
#ifdef SHMEM
CPU_ZERO(&set);
if (CONSUMER(pid)) CPU_SET(1, &set);
else CPU_SET(0, &set);
if (sched_setaffinity(0, sizeof(cpu_set_t), &set) < 0)
{
err("could not set cpu affinity", 2);
}
#endif // SHMEM
if (CONSUMER(pid))
{
for (i = 0; i <= LIMIT; ++i)
{
sum += receive(&processed);
}
if (sum != ((LIMIT * (LIMIT + 1)) / 2)) err("wrong sum", 15);
#ifndef NDEBUG
#ifdef KERNEL
printf("KERNEL Sum: %zu\n", sum);
#else // KERNEL
printf("SHMEM Sum: %zu\n", sum);
#endif // KERNEL
#endif // NDEBUG
}
else
{
for (i = 0; i <= LIMIT; ++i)
{
send(i, &processed);
}
}
if (!CONSUMER(pid))
{
waitpid(pid, &status, 0);
if (WEXITSTATUS(status) != 0) err("child exited bad", 11);
ts_time(&end);
diff = ts_diff(end, start);
#ifdef KERNEL
printf("KERNEL Time: ");
#else // KERNEL
printf("SHMEM Time: ");
#endif
ts_print(diff, LIMIT);
printf("\n");
}
#ifdef KERNEL
if (CONSUMER(pid)) close(in);
else close(out);
#endif // KERNEL
return 0;
}
Loading…
Cancel
Save