noisebox/mersenne.c

175 lines
3.7 KiB
C

/*
* mersenne.c -- component to provide random numbers on demand.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "noisebox.h"
enum {
// assumes W = 32
N = 624,
M = 397,
R = 31,
A = 0x9908B0DF,
F = 1812433253,
U = 11,
// assumes D = 0xFFFFFFFF
S = 7,
B = 0x9D2C5680,
T = 15,
C = 0xEFC60000,
L = 18,
MASK_LOWER = (1ull << R) -1,
MASK_UPPER = (1ull << R),
};
// state for single generator.
struct mt_state {
uint32_t mt[N];
int index;
off_t begin;
size_t consumed;
char overflow[4];
int overflow_len;
};
static void twist(struct mt_state *state) {
uint32_t i, x, xA;
uint32_t *mt = state->mt;
for(i=0; i<N; i++) {
x = (mt[i] & MASK_UPPER) + (mt[(i+1) % N] & MASK_LOWER);
xA = x >> 1;
if(x & 0x1) xA ^= A;
mt[i] = mt[(i+M) % N] ^ xA;
}
state->index = 0;
}
static void mt_init(struct mt_state *state, const uint32_t seed) {
uint32_t i;
uint32_t *mt = state->mt;
mt[0] = seed;
for(i=1; i<N; i++) {
mt[i] = (F * (mt[i-1] ^ (mt[i-1] >> 30)) + i);
}
twist(state);
}
static uint32_t extract_u32(struct mt_state *state) {
uint32_t y;
if(state->index >= N) {
twist(state);
}
int i = state->index;
y = state->mt[i];
state->index++;
y ^= (y >> U);
y ^= (y << S) & B;
y ^= (y << T) & C;
y ^= (y >> L);
return y;
}
static int do_open(const char *path, struct fuse_file_info *fi) {
struct mt_state *state = malloc(sizeof(struct mt_state));
mt_init(state, 0);
fi->fh = (uint64_t)state;
return 0;
}
static int do_getattr(const char *path, struct stat *st) {
}
static int get_noise(size_t n, off_t offset, char* buf,
struct fuse_file_info *fi) {
printf("getting random bits: %i@%i (%i)\n", n, offset, n*sizeof(char));
uint32_t *tmp = malloc(n * sizeof(char));
printf("allocated %i\n", sizeof(char) * n);
struct mt_state *state = (struct mt_state *)(fi->fh);
float buf_ratio = (float)sizeof(char)/(float)sizeof(uint32_t);
int count = n * buf_ratio;
printf("calling extract_u32 %i times (%i * %f)\n", count, n, buf_ratio);
for(int i=0; i<count; i++) {
tmp[i] = extract_u32(state);
}
// consumed is always in uint32_t.
printf("advancing consumed: %i + %i\n", state->consumed, count);
state->consumed += count;
printf("wrote buf\n");
memcpy(buf, tmp, n);
free(tmp);
return n;
}
Noiser* mersenne_init(void) {
Noiser* n = malloc(sizeof(Noiser));
n->name = "mersenne";
n->get_noise = get_noise;
n->do_open = do_open;
n->noisefile_count = 8;
n->files = malloc(sizeof(NoiseFile *) * n->noisefile_count);
n->files[0] = malloc(sizeof(NoiseFile));
n->files[0]->name = "1M";
n->files[0]->size = 1ULL<<20;
n->files[1] = malloc(sizeof(NoiseFile));
n->files[1]->name = "1GiB";
n->files[1]->size = 1ULL<<30;
n->files[2] = malloc(sizeof(NoiseFile));
n->files[2]->name = "100GiB";
n->files[2]->size = 100 * (1ULL<<30);
n->files[3] = malloc(sizeof(NoiseFile));
n->files[3]->name = "200GiB";
n->files[3]->size = 200 * (1ULL<<30);
n->files[4] = malloc(sizeof(NoiseFile));
n->files[4]->name = "400GiB";
n->files[4]->size = 400 * (1ULL<<30);
n->files[5] = malloc(sizeof(NoiseFile));
n->files[5]->name = "1GB";
n->files[5]->size = 1000000000;
n->files[6] = malloc(sizeof(NoiseFile));
n->files[6]->name = "100GB";
n->files[6]->size = 100000000000;
n->files[7] = malloc(sizeof(NoiseFile));
n->files[7]->name = "200GB";
n->files[7]->size = 200000000000;
return n;
}