[
  {
    "path": ".travis.yml",
    "content": "language: go\n\ngo:\n  - 1.7\n  - 1.8\n\nscript:\n  # build test for supported platforms\n  - GOOS=linux go build\n  - GOOS=darwin go build\n  - GOOS=freebsd go build\n  - GOARCH=386 go build\n\n  # run tests on a standard platform\n  - go test -v ./...\n\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017 Aliaksandr Valialkin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "[![Build Status](https://travis-ci.org/valyala/fastrand.svg)](https://travis-ci.org/valyala/fastrand)\n[![GoDoc](https://godoc.org/github.com/valyala/fastrand?status.svg)](http://godoc.org/github.com/valyala/fastrand)\n[![Go Report](https://goreportcard.com/badge/github.com/valyala/fastrand)](https://goreportcard.com/report/github.com/valyala/fastrand)\n\n\n# fastrand\n\nFast pseudorandom number generator.\n\n\n# Features\n\n- Optimized for speed.\n- Performance scales on multiple CPUs.\n\n# How does it work?\n\nIt abuses [sync.Pool](https://golang.org/pkg/sync/#Pool) for maintaining\n\"per-CPU\" pseudorandom number generators.\n\nTODO: firgure out how to use real per-CPU pseudorandom number generators.\n\n\n# Benchmark results\n\n\n```\n$ GOMAXPROCS=1 go test -bench=. github.com/valyala/fastrand\ngoos: linux\ngoarch: amd64\npkg: github.com/valyala/fastrand\nBenchmarkUint32n                   \t50000000\t        29.7 ns/op\nBenchmarkRNGUint32n                \t200000000\t         6.50 ns/op\nBenchmarkRNGUint32nWithLock        \t100000000\t        21.5 ns/op\nBenchmarkMathRandInt31n            \t50000000\t        31.8 ns/op\nBenchmarkMathRandRNGInt31n         \t100000000\t        17.9 ns/op\nBenchmarkMathRandRNGInt31nWithLock \t50000000\t        30.2 ns/op\nPASS\nok  \tgithub.com/valyala/fastrand\t10.634s\n```\n\n```\n$ GOMAXPROCS=2 go test -bench=. github.com/valyala/fastrand\ngoos: linux\ngoarch: amd64\npkg: github.com/valyala/fastrand\nBenchmarkUint32n-2                     \t100000000\t        17.6 ns/op\nBenchmarkRNGUint32n-2                  \t500000000\t         3.36 ns/op\nBenchmarkRNGUint32nWithLock-2          \t50000000\t        32.0 ns/op\nBenchmarkMathRandInt31n-2              \t20000000\t        51.2 ns/op\nBenchmarkMathRandRNGInt31n-2           \t100000000\t        11.0 ns/op\nBenchmarkMathRandRNGInt31nWithLock-2   \t20000000\t        91.0 ns/op\nPASS\nok  \tgithub.com/valyala/fastrand\t9.543s\n```\n\n```\n$ GOMAXPROCS=4 go test -bench=. github.com/valyala/fastrand\ngoos: linux\ngoarch: amd64\npkg: github.com/valyala/fastrand\nBenchmarkUint32n-4                     \t100000000\t        14.2 ns/op\nBenchmarkRNGUint32n-4                  \t500000000\t         3.30 ns/op\nBenchmarkRNGUint32nWithLock-4          \t20000000\t        88.7 ns/op\nBenchmarkMathRandInt31n-4              \t10000000\t       145 ns/op\nBenchmarkMathRandRNGInt31n-4           \t200000000\t         8.35 ns/op\nBenchmarkMathRandRNGInt31nWithLock-4   \t20000000\t       102 ns/op\nPASS\nok  \tgithub.com/valyala/fastrand\t11.534s\n```\n\nAs you can see, [fastrand.Uint32n](https://godoc.org/github.com/valyala/fastrand#Uint32n)\nscales on multiple CPUs, while [rand.Int31n](https://golang.org/pkg/math/rand/#Int31n)\ndoesn't scale. Their performance is comparable on `GOMAXPROCS=1`,\nbut `fastrand.Uint32n` runs 3x faster than `rand.Int31n` on `GOMAXPROCS=2`\nand 10x faster than `rand.Int31n` on `GOMAXPROCS=4`.\n"
  },
  {
    "path": "fastrand.go",
    "content": "// Package fastrand implements fast pesudorandom number generator\n// that should scale well on multi-CPU systems.\n//\n// Use crypto/rand instead of this package for generating\n// cryptographically secure random numbers.\npackage fastrand\n\nimport (\n\t\"sync\"\n\t\"time\"\n)\n\n// Uint32 returns pseudorandom uint32.\n//\n// It is safe calling this function from concurrent goroutines.\nfunc Uint32() uint32 {\n\tv := rngPool.Get()\n\tif v == nil {\n\t\tv = &RNG{}\n\t}\n\tr := v.(*RNG)\n\tx := r.Uint32()\n\trngPool.Put(r)\n\treturn x\n}\n\nvar rngPool sync.Pool\n\n// Uint32n returns pseudorandom uint32 in the range [0..maxN).\n//\n// It is safe calling this function from concurrent goroutines.\nfunc Uint32n(maxN uint32) uint32 {\n\tx := Uint32()\n\t// See http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/\n\treturn uint32((uint64(x) * uint64(maxN)) >> 32)\n}\n\n// RNG is a pseudorandom number generator.\n//\n// It is unsafe to call RNG methods from concurrent goroutines.\ntype RNG struct {\n\tx uint32\n}\n\n// Uint32 returns pseudorandom uint32.\n//\n// It is unsafe to call this method from concurrent goroutines.\nfunc (r *RNG) Uint32() uint32 {\n\tfor r.x == 0 {\n\t\tr.x = getRandomUint32()\n\t}\n\n\t// See https://en.wikipedia.org/wiki/Xorshift\n\tx := r.x\n\tx ^= x << 13\n\tx ^= x >> 17\n\tx ^= x << 5\n\tr.x = x\n\treturn x\n}\n\n// Uint32n returns pseudorandom uint32 in the range [0..maxN).\n//\n// It is unsafe to call this method from concurrent goroutines.\nfunc (r *RNG) Uint32n(maxN uint32) uint32 {\n\tx := r.Uint32()\n\t// See http://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/\n\treturn uint32((uint64(x) * uint64(maxN)) >> 32)\n}\n\n// Seed sets the r state to n.\nfunc (r *RNG) Seed(n uint32) {\n\tr.x = n\n}\n\nfunc getRandomUint32() uint32 {\n\tx := time.Now().UnixNano()\n\treturn uint32((x >> 32) ^ x)\n}\n"
  },
  {
    "path": "fastrand_test.go",
    "content": "package fastrand\n\nimport (\n\t\"testing\"\n)\n\nfunc TestRNGSeed(t *testing.T) {\n\tvar r RNG\n\tfor _, seed := range []uint32{1, 2, 1234, 432432, 34324432} {\n\t\tr.Seed(seed)\n\t\tm := make(map[uint32]struct{})\n\t\tfor i := 0; i < 1e6; i++ {\n\t\t\tn := r.Uint32()\n\t\t\tif _, ok := m[n]; ok {\n\t\t\t\tt.Fatalf(\"number %v already exists\", n)\n\t\t\t}\n\t\t\tm[n] = struct{}{}\n\t\t}\n\t}\n}\n\nfunc TestUint32(t *testing.T) {\n\tm := make(map[uint32]struct{})\n\tfor i := 0; i < 1e6; i++ {\n\t\tn := Uint32()\n\t\tif _, ok := m[n]; ok {\n\t\t\tt.Fatalf(\"number %v already exists\", n)\n\t\t}\n\t\tm[n] = struct{}{}\n\t}\n}\n\nfunc TestRNGUint32(t *testing.T) {\n\tvar r RNG\n\tm := make(map[uint32]struct{})\n\tfor i := 0; i < 1e6; i++ {\n\t\tn := r.Uint32()\n\t\tif _, ok := m[n]; ok {\n\t\t\tt.Fatalf(\"number %v already exists\", n)\n\t\t}\n\t\tm[n] = struct{}{}\n\t}\n}\n\nfunc TestUint32n(t *testing.T) {\n\tm := make(map[uint32]int)\n\tfor i := 0; i < 1e6; i++ {\n\t\tn := Uint32n(1e2)\n\t\tif n >= 1e2 {\n\t\t\tt.Fatalf(\"n > 1000: %v\", n)\n\t\t}\n\t\tm[n]++\n\t}\n\n\t// check distribution\n\tavg := 1e6 / 1e2\n\tfor k, v := range m {\n\t\tp := (float64(v) - float64(avg)) / float64(avg)\n\t\tif p < 0 {\n\t\t\tp = -p\n\t\t}\n\t\tif p > 0.05 {\n\t\t\tt.Fatalf(\"skew more than 5%% for k=%v: %v\", k, p*100)\n\t\t}\n\t}\n}\n\nfunc TestRNGUint32n(t *testing.T) {\n\tvar r RNG\n\tm := make(map[uint32]int)\n\tfor i := 0; i < 1e6; i++ {\n\t\tn := r.Uint32n(1e2)\n\t\tif n >= 1e2 {\n\t\t\tt.Fatalf(\"n > 1000: %v\", n)\n\t\t}\n\t\tm[n]++\n\t}\n\n\t// check distribution\n\tavg := 1e6 / 1e2\n\tfor k, v := range m {\n\t\tp := (float64(v) - float64(avg)) / float64(avg)\n\t\tif p < 0 {\n\t\t\tp = -p\n\t\t}\n\t\tif p > 0.05 {\n\t\t\tt.Fatalf(\"skew more than 5%% for k=%v: %v\", k, p*100)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "fastrand_timing_test.go",
    "content": "package fastrand\n\nimport (\n\t\"math/rand\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"unsafe\"\n)\n\n// BenchSink prevents the compiler from optimizing away benchmark loops.\nvar BenchSink uint32\n\nfunc BenchmarkUint32n(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ts := uint32(0)\n\t\tfor pb.Next() {\n\t\t\ts += Uint32n(1e6)\n\t\t}\n\t\tatomic.AddUint32(&BenchSink, s)\n\t})\n}\n\nfunc BenchmarkRNGUint32n(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tvar r RNG\n\t\ts := uint32(0)\n\t\tfor pb.Next() {\n\t\t\ts += r.Uint32n(1e6)\n\t\t}\n\t\tatomic.AddUint32(&BenchSink, s)\n\t})\n}\n\nfunc BenchmarkRNGUint32nWithLock(b *testing.B) {\n\tvar r RNG\n\tvar rMu sync.Mutex\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ts := uint32(0)\n\t\tfor pb.Next() {\n\t\t\trMu.Lock()\n\t\t\ts += r.Uint32n(1e6)\n\t\t\trMu.Unlock()\n\t\t}\n\t\tatomic.AddUint32(&BenchSink, s)\n\t})\n}\n\nfunc BenchmarkRNGUint32nArray(b *testing.B) {\n\tvar rr [64]struct {\n\t\tr  RNG\n\t\tmu sync.Mutex\n\n\t\t// pad prevents from false sharing\n\t\tpad [64 - (unsafe.Sizeof(RNG{})+unsafe.Sizeof(sync.Mutex{}))%64]byte\n\t}\n\tvar n uint32\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ts := uint32(0)\n\t\tfor pb.Next() {\n\t\t\tidx := atomic.AddUint32(&n, 1)\n\t\t\tr := &rr[idx%uint32(len(rr))]\n\t\t\tr.mu.Lock()\n\t\t\ts += r.r.Uint32n(1e6)\n\t\t\tr.mu.Unlock()\n\t\t}\n\t\tatomic.AddUint32(&BenchSink, s)\n\t})\n}\n\nfunc BenchmarkMathRandInt31n(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ts := uint32(0)\n\t\tfor pb.Next() {\n\t\t\ts += uint32(rand.Int31n(1e6))\n\t\t}\n\t\tatomic.AddUint32(&BenchSink, s)\n\t})\n}\n\nfunc BenchmarkMathRandRNGInt31n(b *testing.B) {\n\tb.RunParallel(func(pb *testing.PB) {\n\t\tr := rand.New(rand.NewSource(42))\n\t\ts := uint32(0)\n\t\tfor pb.Next() {\n\t\t\ts += uint32(r.Int31n(1e6))\n\t\t}\n\t\tatomic.AddUint32(&BenchSink, s)\n\t})\n}\n\nfunc BenchmarkMathRandRNGInt31nWithLock(b *testing.B) {\n\tr := rand.New(rand.NewSource(42))\n\tvar rMu sync.Mutex\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ts := uint32(0)\n\t\tfor pb.Next() {\n\t\t\trMu.Lock()\n\t\t\ts += uint32(r.Int31n(1e6))\n\t\t\trMu.Unlock()\n\t\t}\n\t\tatomic.AddUint32(&BenchSink, s)\n\t})\n}\n\nfunc BenchmarkMathRandRNGInt31nArray(b *testing.B) {\n\tvar rr [64]struct {\n\t\tr  *rand.Rand\n\t\tmu sync.Mutex\n\n\t\t// pad prevents from false sharing\n\t\tpad [64 - (unsafe.Sizeof(RNG{})+unsafe.Sizeof(sync.Mutex{}))%64]byte\n\t}\n\tfor i := range rr {\n\t\trr[i].r = rand.New(rand.NewSource(int64(i)))\n\t}\n\n\tvar n uint32\n\tb.RunParallel(func(pb *testing.PB) {\n\t\ts := uint32(0)\n\t\tfor pb.Next() {\n\t\t\tidx := atomic.AddUint32(&n, 1)\n\t\t\tr := &rr[idx%uint32(len(rr))]\n\t\t\tr.mu.Lock()\n\t\t\ts += uint32(r.r.Int31n(1e6))\n\t\t\tr.mu.Unlock()\n\t\t}\n\t\tatomic.AddUint32(&BenchSink, s)\n\t})\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/valyala/fastrand\n"
  }
]