base: Use the global Mersenne twister throughout
authorAndreas Hansson <andreas.hansson@arm.com>
Wed, 3 Sep 2014 11:42:54 +0000 (07:42 -0400)
committerAndreas Hansson <andreas.hansson@arm.com>
Wed, 3 Sep 2014 11:42:54 +0000 (07:42 -0400)
This patch tidies up random number generation to ensure that it is
done consistently throughout the code base. In essence this involves a
clean-up of Ruby, and some code simplifications in the traffic
generator.

As part of this patch a bunch of skewed distributions (off-by-one etc)
have been fixed.

Note that a single global random number generator is used, and that
the object instantiation order will impact the behaviour (the sequence
of numbers will be unaffected, but if module A calles random before
module B then they would obviously see a different outcome). The
dependency on the instantiation order is true in any case due to the
execution-model of gem5, so we leave it as is. Also note that the
global ranom generator is not thread safe at this point.

Regressions using the memtest, TrafficGen or any Ruby tester are
affected and will be updated accordingly.

15 files changed:
src/cpu/testers/directedtest/SeriesRequestGenerator.cc
src/cpu/testers/memtest/memtest.cc
src/cpu/testers/networktest/networktest.cc
src/cpu/testers/rubytest/Check.cc
src/cpu/testers/rubytest/CheckTable.cc
src/cpu/testers/traffic_gen/generators.cc
src/cpu/testers/traffic_gen/traffic_gen.cc
src/mem/ruby/common/NetDest.cc
src/mem/ruby/common/NetDest.hh
src/mem/ruby/common/Set.cc
src/mem/ruby/common/Set.hh
src/mem/ruby/network/MessageBuffer.cc
src/mem/ruby/network/simple/PerfectSwitch.cc
src/mem/ruby/slicc_interface/RubySlicc_Util.hh
src/mem/ruby/structures/RubyMemoryControl.cc

index f4bb578e3c42731b33eaedbfe3d269a5d969c596..80523280b2105bf213e716e4a252192d27ca0e9e 100644 (file)
@@ -27,6 +27,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "base/random.hh"
 #include "cpu/testers/directedtest/DirectedGenerator.hh"
 #include "cpu/testers/directedtest/RubyDirectedTester.hh"
 #include "cpu/testers/directedtest/SeriesRequestGenerator.hh"
@@ -60,7 +61,7 @@ SeriesRequestGenerator::initiate()
     Request *req = new Request(m_address, 1, flags, masterId);
 
     Packet::Command cmd;
-    bool do_write = ((random() % 100) < m_percent_writes);
+    bool do_write = (random_mt.random(0, 100) < m_percent_writes);
     if (do_write) {
         cmd = MemCmd::WriteReq;
     } else {
index 7f3ff0d0332c0309771ebfc3a97c7815b56e3c52..6dc2ccb73fce5120555f413bb6dd4060bfbcc213 100644 (file)
@@ -37,6 +37,7 @@
 #include <vector>
 
 #include "base/misc.hh"
+#include "base/random.hh"
 #include "base/statistics.hh"
 #include "cpu/testers/memtest/memtest.hh"
 #include "debug/MemTest.hh"
@@ -261,14 +262,14 @@ MemTest::tick()
     }
 
     //make new request
-    unsigned cmd = random() % 100;
-    unsigned offset = random() % size;
-    unsigned base = random() % 2;
-    uint64_t data = random();
-    unsigned access_size = random() % 4;
-    bool uncacheable = (random() % 100) < percentUncacheable;
+    unsigned cmd = random_mt.random(0, 100);
+    unsigned offset = random_mt.random<unsigned>(0, size - 1);
+    unsigned base = random_mt.random(0, 1);
+    uint64_t data = random_mt.random<uint64_t>();
+    unsigned access_size = random_mt.random(0, 3);
+    bool uncacheable = random_mt.random(0, 100) < percentUncacheable;
 
-    unsigned dma_access_size = random() % 4; 
+    unsigned dma_access_size = random_mt.random(0, 3);
 
     //If we aren't doing copies, use id as offset, and do a false sharing
     //mem tester
@@ -296,7 +297,8 @@ MemTest::tick()
         return;
     }
 
-    bool do_functional = (random() % 100 < percentFunctional) && !uncacheable;
+    bool do_functional = (random_mt.random(0, 100) < percentFunctional) &&
+        !uncacheable;
     Request *req = new Request();
     uint8_t *result = new uint8_t[8];
 
index 8fff53aa78ead48b06fd08b4e072d7e662b071b0..c2d34489b543b4882b78e0308f2956400b1057da 100644 (file)
@@ -35,6 +35,7 @@
 #include <vector>
 
 #include "base/misc.hh"
+#include "base/random.hh"
 #include "base/statistics.hh"
 #include "cpu/testers/networktest/networktest.hh"
 #include "debug/NetworkTest.hh"
@@ -143,7 +144,7 @@ NetworkTest::tick()
     // - send pkt if this number is < injRate*(10^precision)
     bool send_this_cycle;
     double injRange = pow((double) 10, (double) precision);
-    unsigned trySending = random() % (int) injRange;
+    unsigned trySending = random_mt.random<unsigned>(0, (int) injRange);
     if (trySending < injRate*injRange)
         send_this_cycle = true;
     else
@@ -174,7 +175,7 @@ NetworkTest::generatePkt()
 {
     unsigned destination = id;
     if (trafficType == 0) { // Uniform Random
-        destination = random() % numMemories;
+        destination = random_mt.random<unsigned>(0, numMemories - 1);
     } else if (trafficType == 1) { // Tornado
         int networkDimension = (int) sqrt(numMemories);
         int my_x = id%networkDimension;
@@ -232,7 +233,7 @@ NetworkTest::generatePkt()
     // 
     MemCmd::Command requestType;
 
-    unsigned randomReqType = random() % 3;
+    unsigned randomReqType = random_mt.random(0, 2);
     if (randomReqType == 0) {
         // generate packet for virtual network 0
         requestType = MemCmd::ReadReq;
index b2b679018cfb2e7de496e5281a434b749f93a60f..126deba6daff8399158fe2e4eff829f838363823 100644 (file)
@@ -27,6 +27,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "base/random.hh"
 #include "cpu/testers/rubytest/Check.hh"
 #include "debug/RubyTest.hh"
 #include "mem/ruby/common/SubBlock.hh"
@@ -46,7 +47,8 @@ Check::Check(const Address& address, const Address& pc,
     pickInitiatingNode();
     changeAddress(address);
     m_pc = pc;
-    m_access_mode = RubyAccessMode(random() % RubyAccessMode_NUM);
+    m_access_mode = RubyAccessMode(random_mt.random(0,
+                                                    RubyAccessMode_NUM - 1));
     m_store_count = 0;
 }
 
@@ -57,11 +59,11 @@ Check::initiate()
     debugPrint();
 
     // currently no protocols support prefetches
-    if (false && (random() & 0xf) == 0) {
+    if (false && (random_mt.random(0, 0xf) == 0)) {
         initiatePrefetch(); // Prefetch from random processor
     }
 
-    if (m_tester_ptr->getCheckFlush() && (random() & 0xff) == 0) {
+        if (m_tester_ptr->getCheckFlush() && (random_mt.random(0, 0xff) == 0)) {
         initiateFlush(); // issue a Flush request from random processor
     }
 
@@ -81,7 +83,7 @@ Check::initiatePrefetch()
 {
     DPRINTF(RubyTest, "initiating prefetch\n");
 
-    int index = random() % m_num_readers;
+    int index = random_mt.random(0, m_num_readers - 1);
     MasterPort* port = m_tester_ptr->getReadableCpuPort(index);
 
     Request::Flags flags;
@@ -90,7 +92,7 @@ Check::initiatePrefetch()
     Packet::Command cmd;
 
     // 1 in 8 chance this will be an exclusive prefetch
-    if ((random() & 0x7) != 0) {
+    if (random_mt.random(0, 0x7) != 0) {
         cmd = MemCmd::ReadReq;
 
         // if necessary, make the request an instruction fetch
@@ -132,7 +134,7 @@ Check::initiateFlush()
 
     DPRINTF(RubyTest, "initiating Flush\n");
 
-    int index = random() % m_num_writers;
+    int index = random_mt.random(0, m_num_writers - 1);
     MasterPort* port = m_tester_ptr->getWritableCpuPort(index);
 
     Request::Flags flags;
@@ -161,7 +163,7 @@ Check::initiateAction()
     DPRINTF(RubyTest, "initiating Action\n");
     assert(m_status == TesterStatus_Idle);
 
-    int index = random() % m_num_writers;
+    int index = random_mt.random(0, m_num_writers - 1);
     MasterPort* port = m_tester_ptr->getWritableCpuPort(index);
 
     Request::Flags flags;
@@ -222,7 +224,7 @@ Check::initiateCheck()
     DPRINTF(RubyTest, "Initiating Check\n");
     assert(m_status == TesterStatus_Ready);
 
-    int index = random() % m_num_readers;
+    int index = random_mt.random(0, m_num_readers - 1);
     MasterPort* port = m_tester_ptr->getReadableCpuPort(index);
 
     Request::Flags flags;
@@ -339,7 +341,7 @@ Check::pickValue()
 {
     assert(m_status == TesterStatus_Idle);
     m_status = TesterStatus_Idle;
-    m_value = random() & 0xff; // One byte
+    m_value = random_mt.random(0, 0xff); // One byte
     m_store_count = 0;
 }
 
@@ -348,7 +350,7 @@ Check::pickInitiatingNode()
 {
     assert(m_status == TesterStatus_Idle || m_status == TesterStatus_Ready);
     m_status = TesterStatus_Idle;
-    m_initiatingNode = (random() % m_num_writers);
+    m_initiatingNode = (random_mt.random(0, m_num_writers - 1));
     DPRINTF(RubyTest, "picked initiating node %d\n", m_initiatingNode);
     m_store_count = 0;
 }
index f10132c89b9a68c3142a4295f661964a96a5ecca..df2bf864dfa5b3cd1963a40d45714ef536ffd43b 100644 (file)
@@ -28,6 +28,7 @@
  */
 
 #include "base/intmath.hh"
+#include "base/random.hh"
 #include "cpu/testers/rubytest/Check.hh"
 #include "cpu/testers/rubytest/CheckTable.hh"
 #include "debug/RubyTest.hh"
@@ -107,7 +108,7 @@ Check*
 CheckTable::getRandomCheck()
 {
     assert(m_check_vector.size() > 0);
-    return m_check_vector[random() % m_check_vector.size()];
+    return m_check_vector[random_mt.random<unsigned>(0, m_check_vector.size() - 1)];
 }
 
 Check*
index 7c6bab92cdd2c89334f64d79b1267e2a5f655b35..135765fce38a1769e4ad3e3ea870a4952a5ef2a3 100644 (file)
@@ -84,7 +84,7 @@ LinearGen::getNextPacket()
 {
     // choose if we generate a read or a write here
     bool isRead = readPercent != 0 &&
-        (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent);
+        (readPercent == 100 || random_mt.random(0, 100) < readPercent);
 
     assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
            readPercent != 100);
@@ -124,7 +124,7 @@ LinearGen::nextPacketTick(bool elastic, Tick delay) const
         return MaxTick;
     } else {
         // return the time when the next request should take place
-        Tick wait = random_mt.random<Tick>(minPeriod, maxPeriod);
+        Tick wait = random_mt.random(minPeriod, maxPeriod);
 
         // compensate for the delay experienced to not be elastic, by
         // default the value we generate is from the time we are
@@ -152,13 +152,13 @@ RandomGen::getNextPacket()
 {
     // choose if we generate a read or a write here
     bool isRead = readPercent != 0 &&
-        (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent);
+        (readPercent == 100 || random_mt.random(0, 100) < readPercent);
 
     assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
            readPercent != 100);
 
     // address of the request
-    Addr addr = random_mt.random<Addr>(startAddr, endAddr - 1);
+    Addr addr = random_mt.random(startAddr, endAddr - 1);
 
     // round down to start address of block
     addr -= addr % blocksize;
@@ -184,15 +184,14 @@ DramGen::getNextPacket()
 
         // choose if we generate a read or a write here
         isRead = readPercent != 0 &&
-            (readPercent == 100 ||
-             random_mt.random<uint8_t>(0, 100) < readPercent);
+            (readPercent == 100 || random_mt.random(0, 100) < readPercent);
 
         assert((readPercent == 0 && !isRead) ||
                (readPercent == 100 && isRead) ||
                readPercent != 100);
 
         // start by picking a random address in the range
-        addr = random_mt.random<Addr>(startAddr, endAddr - 1);
+        addr = random_mt.random(startAddr, endAddr - 1);
 
         // round down to start address of a block, i.e. a DRAM burst
         addr -= addr % blocksize;
@@ -275,7 +274,7 @@ RandomGen::nextPacketTick(bool elastic, Tick delay) const
         return MaxTick;
     } else {
         // return the time when the next request should take place
-        Tick wait = random_mt.random<Tick>(minPeriod, maxPeriod);
+        Tick wait = random_mt.random(minPeriod, maxPeriod);
 
         // compensate for the delay experienced to not be elastic, by
         // default the value we generate is from the time we are
index c1ce0d6d4ab6604abd80706671c233dd52669764..cbff712bc97851d68d5a942b8c3b77df93d5424a 100644 (file)
@@ -423,7 +423,7 @@ TrafficGen::transition()
     states[currState]->exit();
 
     // determine next state
-    double p = random_mt.gen_real1();
+    double p = random_mt.random<double>();
     assert(currState < transitionMatrix.size());
     double cumulative = 0.0;
     size_t i = 0;
index b8c490ac585b2d0e6f2761f5dfb1ba2cf4c5fd79..0a89bda530d17b7c4297b4d4263790e18d6ab894 100644 (file)
@@ -51,13 +51,6 @@ NetDest::addNetDest(const NetDest& netDest)
     }
 }
 
-void
-NetDest::addRandom()
-{
-    int i = random()%m_bits.size();
-    m_bits[i].addRandom();
-}
-
 void
 NetDest::setNetDest(MachineType machine, const Set& set)
 {
index ba72fe2143a262d4f955623d51ac44ff2383d241..9914ca218c78b209a62f6ba66928e8ec8691ba72 100644 (file)
@@ -55,7 +55,6 @@ class NetDest
 
     void add(MachineID newElement);
     void addNetDest(const NetDest& netDest);
-    void addRandom();
     void setNetDest(MachineType machine, const Set& set);
     void remove(MachineID oldElement);
     void removeNetDest(const NetDest& netDest);
index c674655aba896ee1f87af00c107da0eaebcf97a2..280fe71b4dfe6a9940c7bc9c3d13752bbb82abed 100644 (file)
@@ -102,22 +102,6 @@ Set::addSet(const Set& set)
         m_p_nArray[i] |= set.m_p_nArray[i];
 }
 
-/*
- * This function should randomly assign 1 to the bits in the set--it
- * should not clear the bits bits first, though?
- */
-void
-Set::addRandom()
-{
-
-    for (int i = 0; i < m_nArrayLen; i++) {
-        // this ensures that all 32 bits are subject to random effects,
-        // as RAND_MAX typically = 0x7FFFFFFF
-        m_p_nArray[i] |= random() ^ (random() << 4);
-    }
-    clearExcess();
-}
-
 /*
  * This function clears bits that are =1 in the parameter set
  */
index 724c5d9e941b1598be16a989cc85913edd22cb7f..bedd44aa617ec8a71476bdd7a1b2a2fc0159820e 100644 (file)
@@ -87,7 +87,6 @@ class Set
     }
 
     void addSet(const Set& set);
-    void addRandom();
 
     void
     remove(NodeID index)
index 1961765c5ea6cc0f9bbe5d69f72c225556208339..1bc55c2c97f47d4936a0ab808b5c4dd5a7720c71 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "base/cprintf.hh"
 #include "base/misc.hh"
+#include "base/random.hh"
 #include "base/stl_helpers.hh"
 #include "debug/RubyQueue.hh"
 #include "mem/ruby/network/MessageBuffer.hh"
@@ -133,9 +134,9 @@ Cycles
 random_time()
 {
     Cycles time(1);
-    time += Cycles(random() & 0x3);  // [0...3]
-    if ((random() & 0x7) == 0) {  // 1 in 8 chance
-        time += Cycles(100 + (random() % 0xf)); // 100 + [1...15]
+    time += Cycles(random_mt.random(0, 3));  // [0...3]
+    if (random_mt.random(0, 7) == 0) {  // 1 in 8 chance
+        time += Cycles(100 + random_mt.random(1, 15)); // 100 + [1...15]
     }
     return time;
 }
index fa0709496ed680738a87994ff85c7c27dd63dcc3..caf07b3cfc5684e3e06bdd63a7e8d905497116f7 100644 (file)
@@ -29,6 +29,7 @@
 #include <algorithm>
 
 #include "base/cast.hh"
+#include "base/random.hh"
 #include "debug/RubyNetwork.hh"
 #include "mem/ruby/network/MessageBuffer.hh"
 #include "mem/ruby/network/simple/PerfectSwitch.hh"
@@ -169,7 +170,8 @@ PerfectSwitch::operateVnet(int vnet)
                                 out_queue_length += m_out[out][v]->getSize();
                             }
                             int value =
-                                (out_queue_length << 8) | (random() & 0xff);
+                                (out_queue_length << 8) |
+                                random_mt.random(0, 0xff);
                             m_link_order[out].m_link = out;
                             m_link_order[out].m_value = value;
                         }
index 4398a4a00892bb0d7c79c2b0a6aed3a633daec22..5ec34f2dc631c741cb209699dd7fc493371f7367 100644 (file)
 #include "mem/ruby/common/DataBlock.hh"
 #include "mem/packet.hh"
 
-inline int
-random(int n)
-{
-  return random() % n;
-}
-
 inline Cycles zero_time() { return Cycles(0); }
 
 inline NodeID
index bc01c7f9468cb95fe5834aca0e3a22e297e29f80..69fd45fe4a13753a80a749cac463d6d1331a5731 100644 (file)
 
 #include "base/cast.hh"
 #include "base/cprintf.hh"
+#include "base/random.hh"
 #include "debug/RubyMemory.hh"
 #include "mem/ruby/common/Address.hh"
 #include "mem/ruby/common/Global.hh"
@@ -437,7 +438,7 @@ RubyMemoryControl::queueReady(int bank)
     }
 
     if (m_mem_random_arbitrate >= 2) {
-        if ((random() % 100) < m_mem_random_arbitrate) {
+        if (random_mt.random(0, 100) < m_mem_random_arbitrate) {
             m_profiler_ptr->profileMemRandBusy();
             return false;
         }
@@ -614,7 +615,7 @@ RubyMemoryControl::executeCycle()
 
     // If randomness desired, re-randomize round-robin position each cycle
     if (m_mem_random_arbitrate) {
-        m_roundRobin = random() % m_total_banks;
+        m_roundRobin = random_mt.random(0, m_total_banks - 1);
     }
 
     // For each channel, scan round-robin, and pick an old, ready