From 29ddcf4b75cdf9d834186ea5820aaaab94c2d37c Mon Sep 17 00:00:00 2001 From: Russell Sears <sears@yahoo-inc.com> Date: Sat, 19 Nov 2011 16:49:29 -0800 Subject: [PATCH] Remove synchronization points from random number generation. This mostly consisted switching from per-class instances of Random() that are shared amongst threads to thread-local instances shared across classes. Also, CounterGenerator.nextInt() was synchronized. Changed it to use an AtomicInteger. Finally, removed lastString() from Generator, as it was only called in places where lastInt() was more appropriate; switched the calls to lastInt(). --- src/com/yahoo/ycsb/BasicDB.java | 5 +--- src/com/yahoo/ycsb/Client.java | 4 +--- src/com/yahoo/ycsb/RandomByteIterator.java | 5 +--- src/com/yahoo/ycsb/Utils.java | 15 +++++++++--- .../ycsb/generator/CounterGenerator.java | 23 +++++++++++-------- .../ycsb/generator/DiscreteGenerator.java | 5 ++-- .../ycsb/generator/ExponentialGenerator.java | 8 +++---- .../ycsb/generator/HistogramGenerator.java | 5 ++-- .../generator/HotspotIntegerGenerator.java | 5 ++-- .../ycsb/generator/IntegerGenerator.java | 5 ++-- .../ycsb/generator/SkewedLatestGenerator.java | 4 ++-- .../generator/UniformIntegerGenerator.java | 6 ++--- .../ycsb/generator/ZipfianGenerator.java | 8 +++---- 13 files changed, 51 insertions(+), 47 deletions(-) diff --git a/src/com/yahoo/ycsb/BasicDB.java b/src/com/yahoo/ycsb/BasicDB.java index 3b4adf63..9490451e 100644 --- a/src/com/yahoo/ycsb/BasicDB.java +++ b/src/com/yahoo/ycsb/BasicDB.java @@ -21,7 +21,6 @@ import java.util.HashMap; import java.util.Properties; import java.util.Set; import java.util.Enumeration; -import java.util.Random; import java.util.Vector; @@ -37,13 +36,11 @@ public class BasicDB extends DB public static final String SIMULATE_DELAY_DEFAULT="0"; - Random random; boolean verbose; int todelay; public BasicDB() { - random=new Random(); todelay=0; } @@ -54,7 +51,7 @@ public class BasicDB extends DB { try { - Thread.sleep((long)random.nextInt(todelay)); + Thread.sleep((long)Utils.random().nextInt(todelay)); } catch (InterruptedException e) { diff --git a/src/com/yahoo/ycsb/Client.java b/src/com/yahoo/ycsb/Client.java index 9da86041..64585f81 100644 --- a/src/com/yahoo/ycsb/Client.java +++ b/src/com/yahoo/ycsb/Client.java @@ -137,8 +137,6 @@ class StatusThread extends Thread */ class ClientThread extends Thread { - static Random random=new Random(); - DB _db; boolean _dotransactions; Workload _workload; @@ -215,7 +213,7 @@ class ClientThread extends Thread //and the sleep() doesn't make sense for granularities < 1 ms anyway if ( (_target>0) && (_target<=1.0) ) { - sleep(random.nextInt((int)(1.0/_target))); + sleep(Utils.random().nextInt((int)(1.0/_target))); } } catch (InterruptedException e) diff --git a/src/com/yahoo/ycsb/RandomByteIterator.java b/src/com/yahoo/ycsb/RandomByteIterator.java index 3e6cba18..99239f85 100644 --- a/src/com/yahoo/ycsb/RandomByteIterator.java +++ b/src/com/yahoo/ycsb/RandomByteIterator.java @@ -16,10 +16,7 @@ */ package com.yahoo.ycsb; -import java.util.Random; - public class RandomByteIterator extends ByteIterator { - static Random random=new Random(); long len; long off; int buf_off; @@ -31,7 +28,7 @@ public class RandomByteIterator extends ByteIterator { } private void fillBytesImpl(byte[] buf, int base) { - int bytes = random.nextInt(); + int bytes = Utils.random().nextInt(); try { buf[base+0] = (byte)(((bytes ) & 31) + ' '); buf[base+1] = (byte)(((bytes >> 5 ) & 31) + ' '); diff --git a/src/com/yahoo/ycsb/Utils.java b/src/com/yahoo/ycsb/Utils.java index 57dd141a..f49bc0f5 100644 --- a/src/com/yahoo/ycsb/Utils.java +++ b/src/com/yahoo/ycsb/Utils.java @@ -24,8 +24,17 @@ import java.util.Random; */ public class Utils { - static Random random=new Random(); - + private static final Random rand = new Random(); + private static final ThreadLocal<Random> rng = new ThreadLocal<Random>(); + + public static Random random() { + Random ret = rng.get(); + if(ret == null) { + ret = new Random(rand.nextLong()); + rng.set(ret); + } + return ret; + } /** * Generate a random ASCII string of a given length. */ @@ -34,7 +43,7 @@ public class Utils int interval='~'-' '+1; byte []buf = new byte[length]; - random.nextBytes(buf); + random().nextBytes(buf); for (int i = 0; i < length; i++) { if (buf[i] < 0) { buf[i] = (byte)((-buf[i] % interval) + ' '); diff --git a/src/com/yahoo/ycsb/generator/CounterGenerator.java b/src/com/yahoo/ycsb/generator/CounterGenerator.java index 11db1cf1..df37b239 100644 --- a/src/com/yahoo/ycsb/generator/CounterGenerator.java +++ b/src/com/yahoo/ycsb/generator/CounterGenerator.java @@ -17,34 +17,39 @@ package com.yahoo.ycsb.generator; +import java.util.concurrent.atomic.AtomicInteger; + /** * Generates a sequence of integers 0, 1, ... */ public class CounterGenerator extends IntegerGenerator { - int counter; + final AtomicInteger counter; /** * Create a counter that starts at countstart */ public CounterGenerator(int countstart) { - counter=countstart; - setLastInt(countstart-1); + counter=new AtomicInteger(countstart); + setLastInt(counter.get()-1); } /** * If the generator returns numeric (integer) values, return the next value as an int. Default is to return -1, which * is appropriate for generators that do not return numeric values. */ - public synchronized int nextInt() + public int nextInt() { - int lastint=counter; - counter++; - setLastInt(lastint); - return lastint; + int ret = counter.getAndIncrement(); + setLastInt(ret); + return ret; + } + @Override + public int lastInt() + { + return counter.get() - 1; } - @Override public double mean() { throw new UnsupportedOperationException("Can't compute mean of non-stationary distribution!"); diff --git a/src/com/yahoo/ycsb/generator/DiscreteGenerator.java b/src/com/yahoo/ycsb/generator/DiscreteGenerator.java index 087312c0..c28f3ae7 100644 --- a/src/com/yahoo/ycsb/generator/DiscreteGenerator.java +++ b/src/com/yahoo/ycsb/generator/DiscreteGenerator.java @@ -20,6 +20,7 @@ package com.yahoo.ycsb.generator; import java.util.Vector; import java.util.Random; +import com.yahoo.ycsb.Utils; import com.yahoo.ycsb.WorkloadException; /** @@ -40,13 +41,11 @@ public class DiscreteGenerator extends Generator } Vector<Pair> _values; - Random _random; String _lastvalue; public DiscreteGenerator() { _values=new Vector<Pair>(); - _random=new Random(); _lastvalue=null; } @@ -62,7 +61,7 @@ public class DiscreteGenerator extends Generator sum+=p._weight; } - double val=_random.nextDouble(); + double val=Utils.random().nextDouble(); for (Pair p : _values) { diff --git a/src/com/yahoo/ycsb/generator/ExponentialGenerator.java b/src/com/yahoo/ycsb/generator/ExponentialGenerator.java index 7a9187e1..de1a2760 100644 --- a/src/com/yahoo/ycsb/generator/ExponentialGenerator.java +++ b/src/com/yahoo/ycsb/generator/ExponentialGenerator.java @@ -19,6 +19,8 @@ package com.yahoo.ycsb.generator; import java.util.Random; +import com.yahoo.ycsb.Utils; + /** * A generator of an exponential distribution. It produces a sequence * of time intervals (integers) according to an exponential @@ -43,8 +45,6 @@ public class ExponentialGenerator extends IntegerGenerator */ double _gamma; - Random _random; - /******************************* Constructors **************************************/ /** @@ -54,12 +54,10 @@ public class ExponentialGenerator extends IntegerGenerator public ExponentialGenerator(double mean) { _gamma = 1.0/mean; - _random = new Random(); } public ExponentialGenerator(double percentile, double range) { _gamma = -Math.log(1.0-percentile/100.0) / range; //1.0/mean; - _random = new Random(); } /****************************************************************************************/ @@ -84,7 +82,7 @@ public class ExponentialGenerator extends IntegerGenerator */ public long nextLong() { - return (long) (-Math.log(_random.nextDouble()) / _gamma); + return (long) (-Math.log(Utils.random().nextDouble()) / _gamma); } @Override diff --git a/src/com/yahoo/ycsb/generator/HistogramGenerator.java b/src/com/yahoo/ycsb/generator/HistogramGenerator.java index baaf3588..aba42c47 100644 --- a/src/com/yahoo/ycsb/generator/HistogramGenerator.java +++ b/src/com/yahoo/ycsb/generator/HistogramGenerator.java @@ -20,6 +20,8 @@ import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Random; + +import com.yahoo.ycsb.Utils; import com.yahoo.ycsb.generator.IntegerGenerator; /** @@ -41,7 +43,6 @@ public class HistogramGenerator extends IntegerGenerator { long block_size; long[] buckets; long area; - Random rand = new Random(); long weighted_area = 0; double mean_size = 0; @@ -93,7 +94,7 @@ public class HistogramGenerator extends IntegerGenerator { @Override public int nextInt() { - int number = rand.nextInt((int)area); + int number = Utils.random().nextInt((int)area); int i; for(i = 0; i < (buckets.length - 1); i++){ diff --git a/src/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java b/src/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java index 2ede01b9..969ae770 100644 --- a/src/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java +++ b/src/com/yahoo/ycsb/generator/HotspotIntegerGenerator.java @@ -18,6 +18,8 @@ package com.yahoo.ycsb.generator; import java.util.Random; +import com.yahoo.ycsb.Utils; + /** * Generate integers resembling a hotspot distribution where x% of operations * access y% of data items. The parameters specify the bounds for the numbers, @@ -37,7 +39,6 @@ public class HotspotIntegerGenerator extends IntegerGenerator { private final int coldInterval; private final double hotsetFraction; private final double hotOpnFraction; - private final Random random; /** * Create a generator for Hotspot distributions. @@ -71,12 +72,12 @@ public class HotspotIntegerGenerator extends IntegerGenerator { this.hotInterval = (int)(interval * hotsetFraction); this.coldInterval = interval - hotInterval; this.hotOpnFraction = hotOpnFraction; - random = new Random(); } @Override public int nextInt() { int value = 0; + Random random = Utils.random(); if (random.nextDouble() < hotOpnFraction) { // Choose a value from the hot set. value = lowerBound + random.nextInt(hotInterval); diff --git a/src/com/yahoo/ycsb/generator/IntegerGenerator.java b/src/com/yahoo/ycsb/generator/IntegerGenerator.java index a49d9b47..13d36cd1 100644 --- a/src/com/yahoo/ycsb/generator/IntegerGenerator.java +++ b/src/com/yahoo/ycsb/generator/IntegerGenerator.java @@ -31,7 +31,7 @@ public abstract class IntegerGenerator extends Generator * Set the last value generated. IntegerGenerator subclasses must use this call * to properly set the last string value, or the lastString() and lastInt() calls won't work. */ - public void setLastInt(int last) + protected void setLastInt(int last) { lastint=last; } @@ -54,9 +54,10 @@ public abstract class IntegerGenerator extends Generator * Calling lastString() should not advance the distribution or have any side effects. If nextString() has not yet * been called, lastString() should return something reasonable. */ + @Override public String lastString() { - return ""+lastint; + return ""+lastInt(); } /** diff --git a/src/com/yahoo/ycsb/generator/SkewedLatestGenerator.java b/src/com/yahoo/ycsb/generator/SkewedLatestGenerator.java index 6d07c5fc..376eb777 100644 --- a/src/com/yahoo/ycsb/generator/SkewedLatestGenerator.java +++ b/src/com/yahoo/ycsb/generator/SkewedLatestGenerator.java @@ -28,7 +28,7 @@ public class SkewedLatestGenerator extends IntegerGenerator public SkewedLatestGenerator(CounterGenerator basis) { _basis=basis; - _zipfian=new ZipfianGenerator(Integer.parseInt(_basis.lastString())); + _zipfian=new ZipfianGenerator(_basis.lastInt()); nextInt(); } @@ -37,7 +37,7 @@ public class SkewedLatestGenerator extends IntegerGenerator */ public int nextInt() { - int max=Integer.parseInt(_basis.lastString()); + int max=_basis.lastInt(); int nextint=max-_zipfian.nextInt(max); setLastInt(nextint); return nextint; diff --git a/src/com/yahoo/ycsb/generator/UniformIntegerGenerator.java b/src/com/yahoo/ycsb/generator/UniformIntegerGenerator.java index a6ae08a6..fa6af131 100644 --- a/src/com/yahoo/ycsb/generator/UniformIntegerGenerator.java +++ b/src/com/yahoo/ycsb/generator/UniformIntegerGenerator.java @@ -19,12 +19,13 @@ package com.yahoo.ycsb.generator; import java.util.Random; +import com.yahoo.ycsb.Utils; + /** * Generates integers randomly uniform from an interval. */ public class UniformIntegerGenerator extends IntegerGenerator { - Random _random; int _lb,_ub,_interval; /** @@ -35,7 +36,6 @@ public class UniformIntegerGenerator extends IntegerGenerator */ public UniformIntegerGenerator(int lb, int ub) { - _random=new Random(); _lb=lb; _ub=ub; _interval=_ub-_lb+1; @@ -44,7 +44,7 @@ public class UniformIntegerGenerator extends IntegerGenerator @Override public int nextInt() { - int ret=_random.nextInt(_interval)+_lb; + int ret=Utils.random().nextInt(_interval)+_lb; setLastInt(ret); return ret; diff --git a/src/com/yahoo/ycsb/generator/ZipfianGenerator.java b/src/com/yahoo/ycsb/generator/ZipfianGenerator.java index 5a4c0198..8a70f086 100644 --- a/src/com/yahoo/ycsb/generator/ZipfianGenerator.java +++ b/src/com/yahoo/ycsb/generator/ZipfianGenerator.java @@ -19,6 +19,8 @@ package com.yahoo.ycsb.generator; import java.util.Random; +import com.yahoo.ycsb.Utils; + /** * A generator of a zipfian distribution. It produces a sequence of items, such that some items are more popular than others, according * to a zipfian distribution. When you construct an instance of this class, you specify the number of items in the set to draw from, either @@ -61,8 +63,6 @@ public class ZipfianGenerator extends IntegerGenerator */ double alpha,zetan,eta,theta,zeta2theta; - Random random; - /** * The number of items used to compute zetan the last time. */ @@ -136,8 +136,6 @@ public class ZipfianGenerator extends IntegerGenerator base=min; zipfianconstant=_zipfianconstant; - random=new Random(); - theta=zipfianconstant; zeta2theta=zeta(2,theta); @@ -273,7 +271,7 @@ public class ZipfianGenerator extends IntegerGenerator } } - double u=random.nextDouble(); + double u=Utils.random().nextDouble(); double uz=u*zetan; if (uz<1.0) -- GitLab