From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57953) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZLFsj-0006hO-0r for qemu-devel@nongnu.org; Fri, 31 Jul 2015 15:22:16 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZLFsd-0008FQ-UO for qemu-devel@nongnu.org; Fri, 31 Jul 2015 15:22:12 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36643) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZLFsd-0008Er-NE for qemu-devel@nongnu.org; Fri, 31 Jul 2015 15:22:07 -0400 Date: Fri, 31 Jul 2015 21:22:00 +0200 From: Andrew Jones Message-ID: <20150731192200.GJ3680@hawk.localdomain> References: <1438358041-18021-1-git-send-email-alex.bennee@linaro.org> <1438358041-18021-11-git-send-email-alex.bennee@linaro.org> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline In-Reply-To: <1438358041-18021-11-git-send-email-alex.bennee@linaro.org> Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [kvm-unit-tests PATCH v5 10/11] new: add isaac prng library from CCAN List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Alex =?iso-8859-1?Q?Benn=E9e?= Cc: mttcg@greensocs.com, peter.maydell@linaro.org, claudio.fontana@huawei.com, kvm@vger.kernel.org, a.spyridakis@virtualopensystems.com, mark.burton@greensocs.com, a.rigo@virtualopensystems.com, qemu-devel@nongnu.org, "Timothy B. Terriberry" , fred.konrad@greensocs.com On Fri, Jul 31, 2015 at 04:54:00PM +0100, Alex Benn=E9e wrote: > It's often useful to introduce some sort of random variation when > testing several racing CPU conditions. Instead of each test implementin= g > some half-arsed PRNG bring in a a decent one which has good statistical > randomness. Obviously it is deterministic for a given seed value which > is likely the behaviour you want. >=20 > I've pulled in the ISAAC library from CCAN: >=20 > http://ccodearchive.net/info/isaac.html >=20 > I shaved off the float related stuff which is less useful for unit > testing and re-indented to fit the style. The original license was > CC0 (Public Domain) which is compatible with the LGPL v2 of > kvm-unit-tests. >=20 > Signed-off-by: Alex Benn=E9e > CC: Timothy B. Terriberry > --- > config/config-arm-common.mak | 1 + > lib/prng.c | 162 +++++++++++++++++++++++++++++++++++= ++++++++ > lib/prng.h | 82 ++++++++++++++++++++++ > 3 files changed, 245 insertions(+) > create mode 100644 lib/prng.c > create mode 100644 lib/prng.h >=20 > diff --git a/config/config-arm-common.mak b/config/config-arm-common.ma= k > index 9c7607b..67a9dda 100644 > --- a/config/config-arm-common.mak > +++ b/config/config-arm-common.mak > @@ -34,6 +34,7 @@ cflatobjs +=3D lib/devicetree.o > cflatobjs +=3D lib/virtio.o > cflatobjs +=3D lib/virtio-mmio.o > cflatobjs +=3D lib/chr-testdev.o > +cflatobjs +=3D lib/prng.o > cflatobjs +=3D lib/arm/io.o > cflatobjs +=3D lib/arm/setup.o > cflatobjs +=3D lib/arm/mmu.o > diff --git a/lib/prng.c b/lib/prng.c > new file mode 100644 > index 0000000..ebd6df7 > --- /dev/null > +++ b/lib/prng.c > @@ -0,0 +1,162 @@ > +/* > + * Pseudo Random Number Generator > + * > + * Lifted from ccan modules ilog/isaac under CC0 > + * - http://ccodearchive.net/info/isaac.html > + * - http://ccodearchive.net/info/ilog.html > + * > + * And lightly hacked to compile under the KVM unit test environment. > + * This provides a handy RNG for torture tests that want to vary > + * delays and the like. > + * > + */ > + > +/*Written by Timothy B. Terriberry (tterribe@xiph.org) 1999-2009. > + CC0 (Public domain) - see LICENSE file for details > + Based on the public domain implementation by Robert J. Jenkins Jr.*/ > + > +#include "libcflat.h" > + > +#include > +#include "prng.h" > + > +#define ISAAC_MASK (0xFFFFFFFFU) > + > +/* Extract ISAAC_SZ_LOG bits (starting at bit 2). */ > +static inline uint32_t lower_bits(uint32_t x) > +{ > + return (x & ((ISAAC_SZ-1) << 2)) >> 2; > +} > + > +/* Extract next ISAAC_SZ_LOG bits (starting at bit ISAAC_SZ_LOG+2). */ > +static inline uint32_t upper_bits(uint32_t y) > +{ > + return (y >> (ISAAC_SZ_LOG+2)) & (ISAAC_SZ-1); > +} > + > +static void isaac_update(isaac_ctx *_ctx){ > + uint32_t *m; > + uint32_t *r; > + uint32_t a; > + uint32_t b; > + uint32_t x; > + uint32_t y; > + int i; > + m=3D_ctx->m; > + r=3D_ctx->r; > + a=3D_ctx->a; > + b=3D_ctx->b+(++_ctx->c); > + for(i=3D0;i + x=3Dm[i]; > + a=3D(a^a<<13)+m[i+ISAAC_SZ/2]; > + m[i]=3Dy=3Dm[lower_bits(x)]+a+b; > + r[i]=3Db=3Dm[upper_bits(y)]+x; > + x=3Dm[++i]; > + a=3D(a^a>>6)+m[i+ISAAC_SZ/2]; > + m[i]=3Dy=3Dm[lower_bits(x)]+a+b; > + r[i]=3Db=3Dm[upper_bits(y)]+x; > + x=3Dm[++i]; > + a=3D(a^a<<2)+m[i+ISAAC_SZ/2]; > + m[i]=3Dy=3Dm[lower_bits(x)]+a+b; > + r[i]=3Db=3Dm[upper_bits(y)]+x; > + x=3Dm[++i]; > + a=3D(a^a>>16)+m[i+ISAAC_SZ/2]; > + m[i]=3Dy=3Dm[lower_bits(x)]+a+b; > + r[i]=3Db=3Dm[upper_bits(y)]+x; > + } > + for(i=3DISAAC_SZ/2;i + x=3Dm[i]; > + a=3D(a^a<<13)+m[i-ISAAC_SZ/2]; > + m[i]=3Dy=3Dm[lower_bits(x)]+a+b; > + r[i]=3Db=3Dm[upper_bits(y)]+x; > + x=3Dm[++i]; > + a=3D(a^a>>6)+m[i-ISAAC_SZ/2]; > + m[i]=3Dy=3Dm[lower_bits(x)]+a+b; > + r[i]=3Db=3Dm[upper_bits(y)]+x; > + x=3Dm[++i]; > + a=3D(a^a<<2)+m[i-ISAAC_SZ/2]; > + m[i]=3Dy=3Dm[lower_bits(x)]+a+b; > + r[i]=3Db=3Dm[upper_bits(y)]+x; > + x=3Dm[++i]; > + a=3D(a^a>>16)+m[i-ISAAC_SZ/2]; > + m[i]=3Dy=3Dm[lower_bits(x)]+a+b; > + r[i]=3Db=3Dm[upper_bits(y)]+x; > + } > + _ctx->b=3Db; > + _ctx->a=3Da; > + _ctx->n=3DISAAC_SZ; > +} > + > +static void isaac_mix(uint32_t _x[8]){ > + static const unsigned char SHIFT[8]=3D{11,2,8,16,10,4,8,9}; > + int i; > + for(i=3D0;i<8;i++){ > + _x[i]^=3D_x[(i+1)&7]< + _x[(i+3)&7]+=3D_x[i]; > + _x[(i+1)&7]+=3D_x[(i+2)&7]; > + i++; > + _x[i]^=3D_x[(i+1)&7]>>SHIFT[i]; > + _x[(i+3)&7]+=3D_x[i]; > + _x[(i+1)&7]+=3D_x[(i+2)&7]; > + } > +} > + > + > +void isaac_init(isaac_ctx *_ctx,const unsigned char *_seed,int _nseed)= { > + _ctx->a=3D_ctx->b=3D_ctx->c=3D0; > + memset(_ctx->r,0,sizeof(_ctx->r)); > + isaac_reseed(_ctx,_seed,_nseed); > +} > + > +void isaac_reseed(isaac_ctx *_ctx,const unsigned char *_seed,int _nsee= d){ > + uint32_t *m; > + uint32_t *r; > + uint32_t x[8]; > + int i; > + int j; > + m=3D_ctx->m; > + r=3D_ctx->r; > + if(_nseed>ISAAC_SEED_SZ_MAX)_nseed=3DISAAC_SEED_SZ_MAX; > + for(i=3D0;i<_nseed>>2;i++){ > + r[i]^=3D(uint32_t)_seed[i<<2|3]<<24|(uint32_t)_seed[i<<2|2]<<16| > + (uint32_t)_seed[i<<2|1]<<8|_seed[i<<2]; > + } > + _nseed-=3Di<<2; > + if(_nseed>0){ > + uint32_t ri; > + ri=3D_seed[i<<2]; > + for(j=3D1;j<_nseed;j++)ri|=3D(uint32_t)_seed[i<<2|j]<<(j<<3); > + r[i++]^=3Dri; > + } > + x[0]=3Dx[1]=3Dx[2]=3Dx[3]=3Dx[4]=3Dx[5]=3Dx[6]=3Dx[7]=3D0x9E3779B9U; > + for(i=3D0;i<4;i++)isaac_mix(x); > + for(i=3D0;i + for(j=3D0;j<8;j++)x[j]+=3Dr[i+j]; > + isaac_mix(x); > + memcpy(m+i,x,sizeof(x)); > + } > + for(i=3D0;i + for(j=3D0;j<8;j++)x[j]+=3Dm[i+j]; > + isaac_mix(x); > + memcpy(m+i,x,sizeof(x)); > + } > + isaac_update(_ctx); > +} > + > +uint32_t isaac_next_uint32(isaac_ctx *_ctx){ > + if(!_ctx->n)isaac_update(_ctx); > + return _ctx->r[--_ctx->n]; > +} > + > +uint32_t isaac_next_uint(isaac_ctx *_ctx,uint32_t _n){ > + uint32_t r; > + uint32_t v; > + uint32_t d; > + do{ > + r=3Disaac_next_uint32(_ctx); > + v=3Dr%_n; > + d=3Dr-v; > + } > + while(((d+_n-1)&ISAAC_MASK) + return v; > +} > diff --git a/lib/prng.h b/lib/prng.h > new file mode 100644 > index 0000000..bf5776d > --- /dev/null > +++ b/lib/prng.h > @@ -0,0 +1,82 @@ > +/* > + * PRNG Header > + */ > +#ifndef __PRNG_H__ > +#define __PRNG_H__ > + > +# include > + > + > + > +typedef struct isaac_ctx isaac_ctx; > + > + > + > +/*This value may be lowered to reduce memory usage on embedded platfor= ms, at > + the cost of reducing security and increasing bias. > + Quoting Bob Jenkins: "The current best guess is that bias is detecta= ble after > + 2**37 values for [ISAAC_SZ_LOG]=3D3, 2**45 for 4, 2**53 for 5, 2**61= for 6, > + 2**69 for 7, and 2**77 values for [ISAAC_SZ_LOG]=3D8."*/ > +#define ISAAC_SZ_LOG (8) > +#define ISAAC_SZ (1< +#define ISAAC_SEED_SZ_MAX (ISAAC_SZ<<2) > + > + > + > +/*ISAAC is the most advanced of a series of pseudo-random number gener= ators > + designed by Robert J. Jenkins Jr. in 1996. > + http://www.burtleburtle.net/bob/rand/isaac.html > + To quote: > + No efficient method is known for deducing their internal states. > + ISAAC requires an amortized 18.75 instructions to produce a 32-bit v= alue. > + There are no cycles in ISAAC shorter than 2**40 values. > + The expected cycle length is 2**8295 values.*/ > +struct isaac_ctx{ > + unsigned n; > + uint32_t r[ISAAC_SZ]; > + uint32_t m[ISAAC_SZ]; > + uint32_t a; > + uint32_t b; > + uint32_t c; > +}; > + > + > +/** > + * isaac_init - Initialize an instance of the ISAAC random number gene= rator. > + * @_ctx: The instance to initialize. > + * @_seed: The specified seed bytes. > + * This may be NULL if _nseed is less than or equal to zero. > + * @_nseed: The number of bytes to use for the seed. > + * If this is greater than ISAAC_SEED_SZ_MAX, the extra bytes= are > + * ignored. > + */ > +void isaac_init(isaac_ctx *_ctx,const unsigned char *_seed,int _nseed)= ; > + > +/** > + * isaac_reseed - Mix a new batch of entropy into the current state. > + * To reset ISAAC to a known state, call isaac_init() again instead. > + * @_ctx: The instance to reseed. > + * @_seed: The specified seed bytes. > + * This may be NULL if _nseed is zero. > + * @_nseed: The number of bytes to use for the seed. > + * If this is greater than ISAAC_SEED_SZ_MAX, the extra bytes= are > + * ignored. > + */ > +void isaac_reseed(isaac_ctx *_ctx,const unsigned char *_seed,int _nsee= d); > +/** > + * isaac_next_uint32 - Return the next random 32-bit value. > + * @_ctx: The ISAAC instance to generate the value with. > + */ > +uint32_t isaac_next_uint32(isaac_ctx *_ctx); > +/** > + * isaac_next_uint - Uniform random integer less than the given value. > + * @_ctx: The ISAAC instance to generate the value with. > + * @_n: The upper bound on the range of numbers returned (not inclus= ive). > + * This must be greater than zero and less than 2**32. > + * To return integers in the full range 0...2**32-1, use > + * isaac_next_uint32() instead. > + * Return: An integer uniformly distributed between 0 and _n-1 (inclus= ive). > + */ > +uint32_t isaac_next_uint(isaac_ctx *_ctx,uint32_t _n); > + > +#endif > --=20 > 2.5.0 >=20 > Agreed that (pseudo) random numbers could be useful in unit tests. Acked-by: Andrew Jones