Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend (& deprecate) lib_random #4

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
pipeline {
agent {
label 'x86&&macOS&&Apps'
}
environment {
VIEW = 'random'
REPO = 'lib_random'
}
options {
skipDefaultCheckout()
}
stages {
stage('Get view') {
steps {
prepareAppsSandbox("${VIEW}", "${REPO}")
}
}
stage('Library checks') {
steps {
xcoreLibraryChecks("${REPO}")
}
}
stage('Build') {
steps {
dir("${REPO}") {
xcoreAllAppsBuild('examples')
xcoreAllAppNotesBuild('examples')
}
}
}
stage('Test') {
steps {
runXmostest("${REPO}", "tests")
}
}
}
post {
always {
archiveArtifacts artifacts: "${REPO}/**/*.*", fingerprint: true
cleanWs()
}
}
}
10 changes: 10 additions & 0 deletions examples/app_dieharder/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
TARGET = STARTKIT
APP_NAME =
USED_MODULES = lib_random

XCC_FLAGS = -Os -g -fcmdline-buffer-bytes=100
#XCC_FLAGS += -save-temps -v


XMOS_MAKE_PATH ?= ../..
-include $(XMOS_MAKE_PATH)/xcommon/module_xcommon/build/Makefile.common
11 changes: 11 additions & 0 deletions examples/app_dieharder/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
This is a wrapper for testing the quality of the PRNG using dieharder.
http://webhome.phy.duke.edu/~rgb/General/dieharder.php

It is slow as it runs the random_prng.h library code under simulation.

If this is a problem, copy the lfsr57(), lfsr88(), & lfsr113() functions
into a host application and run nativly, viz test just the algorithm!

The expected usage is:
axe --args bin/dieharder.xe -g prng57 -n -1 -o - -B | dieharder -g 200 -a
(see dieharder.xe and dieharder help files for details)
135 changes: 135 additions & 0 deletions examples/app_dieharder/src/gen.xc
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright (c) 2017, XMOS Ltd, All rights reserved

// The expected usage is for validating against 'dieharder'
// axe --args bin/dieharder.xe -g prng57 -n -1 -o - -B | dieharder -g 200 -a

// We want raw stdio.h, not the safe version.
#define UNSAFE_LIBC
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <xs1.h>
#include "random_prng.h"

static const char*unsafe prngString(PrngSize prng) {
unsafe {
switch (prng) {
case prng57: return "prng57";
case prng88: return "prng88";
case prng113: return "prng113";
default: return "prngInvalid";
}
}
}

unsigned readArgs(unsigned argC, char*unsafe argV[],
PrngSize& prng, unsigned& numValues, const char*unsafe& filename, unsigned& binary) {
unsigned found_g = 0;
unsigned found_n = 0;
unsigned found_o = 0;
binary = 0;

if (argC == 7 || argC == 8) {
for(unsigned i=1; i<argC; i+=2) {
if (strcmp(argV[i], "-B") == 0) {
binary = 1;
--i; // Hack the incrementor.
}
if (strcmp(argV[i], "-n") == 0) {
numValues = atoi(argV[i+1]);
found_n = 1;
}
else if (strcmp(argV[i], "-o") == 0) {
filename = argV[i+1];
found_o = 1;
}
else if (strcmp(argV[i], "-g") == 0) {
found_g = 1;
if (strcmp(argV[i+1], "prng57") == 0)
prng = prng57;
else if (strcmp(argV[i+1], "prng88") == 0)
prng = prng88;
else if (strcmp(argV[i+1], "prng113") == 0)
prng = prng113;
else
found_g = 0;
}
}
}
if (found_g && found_n && found_o && (argC == 7 || binary))
return 1;
if (!argC) {
printf ("Usage: Rebuild .xe with `-fcmdline-buffer-bytes=<value>` set\n");
printf (" and make sure you pass commandline arg using `xsim --args ...` or `axe --args ...`\n");
}
else {
printf ("Usage: `axe --args %s -g <prng57|prng88|prng113> -n <numValues|-1> -o <outfile|-> [-B]`\n", argV[0]);
printf (" -g <prng57|prng88|prng113> see random_prng.h and PrngSize for details;\n");
printf (" -n <numValues|-1> the number of 32bit values to generate, or -1 (with -B) for continuous;\n");
printf (" -o <outfile|-> output file name, or '-' for stdout;\n");
printf (" -B to turn on binary output, otherwise output will be in ASCII dieharder format.\n");
}
return 0;
}

FILE*unsafe openOutFile(const char*unsafe filename, unsigned numValues, unsigned prng, unsigned binary) {
FILE*unsafe fp = (strcmp(filename, "-") == 0) ? stdout :
fopen(filename, binary? "wb":"w");
if (!fp)
printf ("Unable to open output file %s\n", filename);
else if (!binary) {
fprintf(fp, "#==================================================================\n");
fprintf(fp, "# generator random_prng.h %s seed=null\n", prngString(prng));
fprintf(fp, "#==================================================================\n");
fprintf(fp, "type: d\n");
fprintf(fp, "count: %u\n", numValues);
fprintf(fp, "numbit: 32\n");
}
return fp;
}

int main(unsigned argC, char*unsafe argV[argC]) {
PrngSize prng = 0;
unsigned numValues = 0;
const char*unsafe filename;
unsigned binary;
unsafe {
if (!readArgs(argC, argV, prng, numValues, filename, binary))
return 1;
}
FILE*unsafe fp = openOutFile(filename, numValues, prng, binary);

//interface random_pool rpi[1];
par {
//random_pool_server(rpi, 1, bitsToPoolSize(1)); // We wont be using it.
{
interface random_prng prngi;
par {
[[distribute]]
random_prng_server(prngi, null, prng57, null);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@robert-lytton should the third argument passed be prng rather than prng57, or have I misunderstood?

// random_prng_server(prngi, rpi[0], prng57, null);
{
// Client task.
while (numValues) {
enum{blkLen=1000};
uint32_t values[blkLen];
unsigned len = (blkLen < numValues)? blkLen : numValues;
prngi.value(values, len);
if (binary)
fwrite(values, len, sizeof(uint32_t), fp);
else
for (unsigned i=0; i < len; ++i)
fprintf(fp, "%10u\n", values[i]);
if (!binary || numValues != (unsigned)(-1))
numValues -= len;
}
fclose(fp);
prngi.release();
}
}
//rpi[0].release();
}
}
return 0;
}
50 changes: 0 additions & 50 deletions lib_random/api/random.h

This file was deleted.

60 changes: 60 additions & 0 deletions lib_random/api/random_bit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) 2017, XMOS Ltd, All rights reserved
#ifndef __RANDOM_BIT_H__
#define __RANDOM_BIT_H__

#include <stdint.h>
#include <stddef.h>

#ifndef REFERENCE_PARAM

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for defining REFERENCE_PARAM here (and in random.h) rather than using the macro from xccompat.h?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no,
xccompat.h should be included

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

random.h has now been removed - use clib alternatives.

#ifdef __XC__
#define REFERENCE_PARAM(type, name) type &name
#else
#define REFERENCE_PARAM(type, name) type *name
#endif
#endif


/** The random_bit.h library is NOT thread safe.
*
* There is one oscillator per tile, hence there may be one user of the library per tile.
* However, on a multi-tile device, each tile may have one thread calling the library.
*/


/** Functions used to claim and release the random_bit library.
*
* As is only one oscillator per tile, there may only be one user of the
* library per tile.
*
* random_bit_claim() returns 0 if the library has already been claimed on
* this tile.
*
* N.B. Ownership of the library does not prevent others from calling it!
*/
int random_bit_claim();
void random_bit_release();

/** Functions that start & stop the random number generator.
*
* Calling this function will start/stop the free running oscillator.
* A running oscillator will increase power consumption by a few mW.
*
* N.B. There is no checking that the caller has previously claimed the library.
*/
void random_bit_start();
void random_bit_stop();

/** Function that produces a random bit.
*
* If random bits are available, then it returns '1' and the random bit.
*
* If no random bits are available, then it returns 0 and the absolute
* time in ticks at which a bit will be available.
* The calling code may then wait until this time (for example in a select statement),
* recalling the function when the bit will be available.
*
* N.B. There is no checking that the caller has previously claimed the library.
*/
uint32_t random_bit(REFERENCE_PARAM(uint32_t, bit_time));

#endif // __RANDOM_BIT_H__
74 changes: 74 additions & 0 deletions lib_random/api/random_pool.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) 2017, XMOS Ltd, All rights reserved
#ifndef __RANDOM_POOL_H__
#define __RANDOM_POOL_H__

#include <stdint.h>
#include <stddef.h>
#include "random_impl.h"

/** Interface for clients to request bits from a random pool.
*
* Multiple clients, situated on any tile, may receive bits from a server.
* There may be only one server per tile.
*
* The server task calls random_bit_claim() for the tile.
* If the claim fails, the task will exit immediately.
*/
interface random_pool {
/** Method that returns the maximum bits a pool can hold. */
size_t capacity();

/** Method that returns the number of bits available in the pool. */
size_t available();

/** Method that returns the approximate period until `bits` will be available.
*
* Clients may then callback or sleep whilst waiting for the pool to fill.
* The client will need to do multiple `fetch()` followed by waits if
* there are multiple clients calling `fetch() or if `bits` > `capacity()`.
*/
uint32_t timeUntil(size_t bits);

/** Method that overwrites `value[ bitPos : bitPos+numBits ]` with random bits.
*
* The bit range will be truncated to fit within value[].
*
* \returns The number of bits overwritten, starting at 'bitPos'.
* This will be the same as numBits if the bits are available.
*/
size_t insert(uint32_t& value, size_t bitPos, size_t numBits);

/** Method exits the random_pool server task when all clients have released.
*
* This allows a combined-par to exit if/when the client owning tasks exits.
* random_bit_release() will be called, allowing another task to claim it.
*/
void release();
};

/** Type represents an opaque bit pool size. */
typedef size_t PoolSize_t;

/** Helper function for turning the minimum number of bits into a `PoolSize_t` opaque value.
*
* N.B. As `PoolSize_t` values are opaque, they must be generated via this function!
* PoolSize_t bitsToPoolSize(size_t bits);
*/
#define bitsToPoolSize(bits) _bitsToPoolSize(bits)

/** Server task that collects random bits into a pool.
*
* The server task may be combined with other tasks in a combined-par statement.
* There may be one server task per tile (as there is only one random_bit generator per tile).
* Clients may then request random bits from the sever task's pool via the `interface random_pool`.
* There may be multiple clients, situated on a mixture of tile.
*
* \param rpi Server end of an `interface random_pool`.
* \param n Number of `client interface random_pool`s being served.
* \param poolSize Size of random bit pool to create - N.B. use bitsToPoolSize() to generate the value.
*/
[[combinable]]
void random_pool_server(server interface random_pool rpi[n], static const size_t n,
static const PoolSize_t poolSize);

#endif // __RANDOM_POOL_H__
Loading