181 lines
3.9 KiB
C
181 lines
3.9 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.
|
|
typedef struct mt_random_t {
|
|
uint32_t mt[N];
|
|
int index;
|
|
off_t begin;
|
|
size_t consumed;
|
|
char overflow[4];
|
|
int overflow_len;
|
|
} mt_random_t;
|
|
|
|
|
|
static void twist(mt_random_t *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(mt_random_t *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(mt_random_t *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 file_state *state = malloc(sizeof(struct file_state));
|
|
mt_random_t rng;
|
|
mt_init(&rng, 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));
|
|
|
|
// FIXME this is wrong.
|
|
mt_random_t *state = (mt_random_t *)(fi->fh);
|
|
float buf_ratio = (float)sizeof(char)/(float)sizeof(uint32_t);
|
|
if(offset != state->consumed * buf_ratio) {
|
|
printf("wrong offset, discarding state\n");
|
|
}
|
|
// TODO got distracted, never actually did this.
|
|
|
|
uint32_t *tmp = malloc(n * sizeof(char));
|
|
printf("allocated %i\n", sizeof(char) * n);
|
|
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;
|
|
}
|