Commit 08285dff authored by Mirko Stoffers's avatar Mirko Stoffers

Modified random number genaration

Instead of deriving from cNumberGenerator, models now use a distinct RNG
in the global RNG array. This ignores the user specific mapping, but
introduces a mapping that creates <num-rngs> RNGs per module and maps
them accordingly.

This solves the problem that RNGs could not be called from inside a
module before.

You may need to change your models and you'll have to update the example
model as well!
parent cbd2c699
......@@ -293,7 +293,7 @@ class SIM_API cComponent : public cDefaultList //implies noncopyable
* Returns the global RNG mapped to local RNG number k. For large indices
* (k >= map size) the global RNG k is returned, provided it exists.
*/
cRNG *getRNG(int k) const {return ev.getRNG(k<rngmapsize ? rngmap[k] : k);}
cRNG* getRNG(int k) const;
//@}
/** @name Interface for calling initialize()/finish().
......
......@@ -521,7 +521,7 @@ class SIM_API cEnvir
* Returns the number of RNGs available for the simulation
* ("num-rngs=" omnetpp.ini setting).
*/
virtual int getNumRNGs() const = 0;
virtual int getNumRNGsPerModule() const = 0;
/**
* Returns pointer to "physical" RNG k (0 <= k < getNumRNGs()).
......@@ -655,6 +655,8 @@ class SIM_API cEnvir
* abort waiting (e.g. pushed the Stop button).
*/
virtual bool idle() = 0;
virtual void createRNGs() = 0;
//@}
};
......
......@@ -25,7 +25,6 @@
#include <semaphore.h>
#include "cmodule.h"
#include "cnumgen.h"
#ifdef ATOMIC_OPS_DEBUG
#include "catomicopsdebug.h"
......@@ -72,7 +71,7 @@ class cCoroutine;
*
* @ingroup SimCore
*/
class SIM_API cSimpleModule : public cModule, public cNumberGenerator //implies noncopyable
class SIM_API cSimpleModule : public cModule //implies noncopyable
{
friend class cModule;
friend class cSimulation;
......@@ -564,10 +563,6 @@ class SIM_API cSimpleModule : public cModule, public cNumberGenerator //implies
{
return duration == SimTime::simTimeZero ? parZeroDur : true;
}
/*
* Initializes the local RNGs according to config options read from ini
*/
void initLocalRNGs();
//}@
......
......@@ -161,11 +161,6 @@ class SIM_API cSimulation : public cNamedObject, noncopyable
*/
void setupThreadPool();
/*
* setup the local Random Number Generators for each module
*/
void setupLocalRNGs();
public:
/** @name Constructor, destructor. */
//@{
......
......@@ -202,8 +202,7 @@ EnvirBase::EnvirBase()
outscalarmgr = NULL;
snapshotmgr = NULL;
num_rngs = 0;
rngs = NULL;
num_rngs_per_module = 0;
#ifdef WITH_PARSIM
parsimcomm = NULL;
......@@ -223,9 +222,8 @@ EnvirBase::~EnvirBase()
delete outscalarmgr;
delete snapshotmgr;
for (int i = 0; i < num_rngs; i++)
for (int i = 0; i < rngs.size(); i++)
delete rngs[i];
delete [] rngs;
#ifdef WITH_PARSIM
delete parsimcomm;
......@@ -1447,24 +1445,11 @@ void EnvirBase::readPerRunOptions()
delete testrng;
// set up RNGs
int i;
for (i=0; i<num_rngs; i++)
for (int i = 0; i < rngs.size(); i++)
delete rngs[i];
delete [] rngs;
num_rngs = opt_num_rngs;
rngs = new cRNG *[num_rngs];
for (i=0; i<num_rngs; i++)
{
cRNG *rng;
CREATE_BY_CLASSNAME(rng, opt_rng_class.c_str(), cRNG, "random number generator");
rngs[i] = rng;
rngs[i]->initialize(opt_seedset, i, num_rngs, getParsimProcId(), getParsimNumPartitions(), getConfig());
}
// and finally the private seed generator for all local generators of simple modules
CREATE_BY_CLASSNAME(seedGenerator, opt_rng_class.c_str(), cRNG, "random number generator");
seedGenerator->initializeAsMaster(opt_seedset, num_rngs+1, num_rngs, getParsimProcId(), getParsimNumPartitions(), getConfig());
num_rngs_per_module = opt_num_rngs;
createRNGs();
// init nextuniquenumber -- startRun() is too late because simple module ctors have run by then
nextuniquenumber = 0;
......@@ -1483,6 +1468,21 @@ void EnvirBase::readPerRunOptions()
}
}
void EnvirBase::createRNGs()
{
int offset=rngs.size();
int moduleId=offset/num_rngs_per_module;
for(int i=0;i<num_rngs_per_module;i++)
{
int pos=i+offset;
cRNG *rng;
CREATE_BY_CLASSNAME(rng, opt_rng_class.c_str(), cRNG, "random number generator");
assert(rngs.size()==pos);
rngs.push_back(rng);
rngs[pos]->initialize(opt_seedset*moduleId, i, num_rngs_per_module, getParsimProcId(), getParsimNumPartitions(), getConfig());
}
}
void EnvirBase::setEventlogRecording(bool enabled)
{
// NOTE: eventlogmgr must be non-NULL when record_eventlog is true
......@@ -1508,15 +1508,15 @@ void EnvirBase::clearEventlogRecordingIntervals()
//-------------------------------------------------------------
int EnvirBase::getNumRNGs() const
int EnvirBase::getNumRNGsPerModule() const
{
return num_rngs;
return num_rngs_per_module;
}
cRNG *EnvirBase::getRNG(int k)
{
if (k<0 || k>=num_rngs)
throw cRuntimeError("RNG index %d is out of range (num-rngs=%d, check the configuration)", k, num_rngs);
if (k<0 || k>=rngs.size())
throw cRuntimeError("RNG index %d is out of range (num-rngs=%d*<numberOfModules>=%d, check the configuration)", k, num_rngs_per_module, rngs.size());
return rngs[k];
}
......@@ -1544,10 +1544,10 @@ void EnvirBase::getRNGMappingFor(cComponent *component)
"numeric RNG indices expected",
suffix, value, component->getFullPath().c_str());
if (physRng>getNumRNGs())
if (physRng>rngs.size())
throw cRuntimeError("Configuration error: rng-%d=%d of module/channel %s: "
"RNG index out of range (num-rngs=%d)",
modRng, physRng, component->getFullPath().c_str(), getNumRNGs());
modRng, physRng, component->getFullPath().c_str(), rngs.size());
if (modRng>=mapsize)
{
if (modRng>=100)
......
......@@ -108,10 +108,8 @@ class ENVIR_API EnvirBase : public cRunnableEnvir
// end
// Random number generators. Module RNG's map to these RNG objects.
int num_rngs;
cRNG **rngs;
cRNG *seedGenerator; // central (and private) random num gen for generating seeds for all public ones
int num_rngs_per_module;
std::vector<cRNG*> rngs;
// Output file managers
EventlogFileManager *eventlogmgr; // NULL if no event log is being written, must be non NULL if record_eventlog is true
......@@ -195,7 +193,7 @@ class ENVIR_API EnvirBase : public cRunnableEnvir
// leave to subclasses: virtual cEnvir& flush();
// RNGs
virtual int getNumRNGs() const;
virtual int getNumRNGsPerModule() const;
virtual cRNG *getRNG(int k);
virtual void getRNGMappingFor(cComponent *component);
......@@ -222,6 +220,8 @@ class ENVIR_API EnvirBase : public cRunnableEnvir
virtual bool idle();
//@}
virtual void createRNGs();
protected:
// functions added locally
virtual bool simulationRequired();
......@@ -272,9 +272,6 @@ class ENVIR_API EnvirBase : public cRunnableEnvir
// Utility function: optionally appends host name to fname
virtual void processFileName(opp_string& fname);
cRNG *getSeedGenerator() const { return seedGenerator; }
protected:
// Utility function: checks simulation fingerprint and displays a message accordingly
void checkFingerprint();
......
......@@ -736,3 +736,12 @@ void cComponent::releaseLocalListeners()
*/
}
cRNG* cComponent::getRNG(int k) const
{
const cModule* const thisMod=dynamic_cast<const cModule* const>(this);
int modId=0;
if(thisMod) modId=thisMod->getId();
k+=modId*ev.getNumRNGsPerModule();
return ev.getRNG(k);
}
......@@ -603,75 +603,6 @@ unsigned cSimpleModule::getStackUsage() const
return coroutine ? coroutine->getStackUsage() : 0;
}
void cSimpleModule::initLocalRNGs()
{
//TODO
unsigned nrNumGens;
unsigned long * seeds;
//
// how many local random number generators do we need?
// default is 1
//
nrNumGens = ev.getConfig()->parseLong(
ev.getConfig()->getPerObjectConfigValue(getFullPath().c_str(),
"number-local-rngs"), "1", 1);
//
// read the seeds from ini file
//
const char * seedString = ev.getConfig()->getPerObjectConfigValue(
getFullPath().c_str(), "local-rng-seed");
//
// setup seeds for each RNG
//
seeds = new unsigned long[nrNumGens];
cStringTokenizer tokenizer(seedString);
const char * token = NULL;
for (unsigned i = 0; i < nrNumGens; i++)
{
if (tokenizer.hasMoreTokens())
{
token = tokenizer.nextToken();
if (strcmp(token, "auto") == 0)
{
token = NULL;
}
}
EnvirBase* e = dynamic_cast<EnvirBase*> (&ev);
if (e != NULL)
{
if (token)
{
//if the seed is set in the ini for this module, use ini-settings
//with fallback to autogeneration if parsing failes
seeds[i] = ev.getConfig()->parseLong(token, "",
e->getSeedGenerator()->intRand());
}
else
{
//else use SeedGenerator for automatic seed generation.
seeds[i] = e->getSeedGenerator()->intRand();
}
token = NULL;
}
else
{
throw cRuntimeError(
"cSimpleModule: Failed to initialize Number Generator, dynamic cast to EnvirBase failed.");
}
}
//
// generate the required number of RNGs with the corresponding seeds
//
setupSeeds(nrNumGens,seeds);
delete[] seeds;
}
void cSimpleModule::setMessageMetaData(cMessage* msg)
{
msg->setEventDuration(SimTime::simTimeUninitialized);
......
......@@ -312,6 +312,7 @@ int cSimulation::registerModule(cModule *mod)
vect = v;
size += delta;
}
ev.createRNGs();
vect[last_id] = mod;
return last_id;
}
......@@ -426,9 +427,6 @@ void cSimulation::startRun()
// read config and setup thread pool
setupThreadPool();
// setup local RNGs for each module according to config
setupLocalRNGs();
// reset counters. Note msgQueue.clear() was already called from setupNetwork()
cThreadPool::setSimTime(0.0);
//sim_time = 0;
......@@ -844,23 +842,6 @@ unsigned int cSimulation::getNextExecutionOrderId(cMessage* msg) {
return eventsPerSimTimeInstance + 1;
}
void cSimulation::setupLocalRNGs() {
//
// Walk through vect[] and setup RNGs for each cSimpleModule
//
// TODO: Better way to do this? What about dynamically created Modules?
cSimpleModule* mod = NULL;
for (int i = 1; i <= last_id; i++) {
if (vect[i]) {
mod = dynamic_cast<cSimpleModule*>(vect[i]);
if (mod) {
mod->initLocalRNGs();
}
}
}
}
//----
/**
......@@ -941,9 +922,10 @@ class StaticEnv : public cEnvir
virtual cEnvir& flush() {::fflush(stdout); return *this;}
// RNGs
virtual int getNumRNGs() const {return 0;}
virtual int getNumRNGsPerModule() const {return 0;}
virtual cRNG *getRNG(int k) {unsupported(); return NULL;}
virtual void getRNGMappingFor(cComponent *component) {component->setRNGMap(0,NULL);}
virtual void createRNGs() {unsupported();}
// output vectors
virtual void *registerOutputVector(const char *modulename, const char *vectorname) {return NULL;}
......
......@@ -49,7 +49,6 @@ USING_NAMESPACE
Register_GlobalConfigOption(CFG_IN_THREADPOOL_CPU_ID_OFFSET, "cpu-id-offset", CFG_INT, "0", "Offset for Thread Affinity. (When running multiple instances of Horizon at once)");
Register_PerRunConfigOption(CFGID_THREADPOOL_SIZE, "thread-pool-size", CFG_INT, "5", "Number of Threads in Threadpool");
Register_GlobalConfigOption(CFGID_SIMTIME_SCALE, "simtime-scale", CFG_INT, "-12", "Sets the scale exponent, and thus the resolution of time for the 64-bit fixed-point simulation time representation. Accepted values are -18..0; for example, -6 selects microsecond resolution. -12 means picosecond resolution, with a maximum simtime of ~110 days.");
static __thread cThreadLocalData* localData = NULL;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment