User Manual, Developers Guide and API Documentation

Implementing a SimulationModel

Beginners Tutorial

Implementing a SimulationModel

A very simple M/M/1 queuing system

Configuration of your system

How to tell openWNS which Simulation Model to load

A look behind the scenes (StaticFactory)

Expected Output

(  0.0000000) [  WNS] Application    Start up modules
(  0.0000000) [  WNS] Application    Creating simulation model: openwns.queuingsystem.SimpleMM1Step1
(  0.0000000) [  WNS] Application    Startup simulation model: openwns.queuingsystem.SimpleMM1Step1
(  0.0000000) [  WNS] SimpleMM1Step1    MM1Step1 started, generating first job
                                        Jobs in system: 0
(  0.0000000) [  WNS] SimpleMM1Step1    Generated new job, next job in 0.168591s
                                        Jobs in system: 1
(  0.0000000) [  WNS] SimpleMM1Step1    Processing next job, processing time: 0.0144122s
                                        Jobs in system: 1
(  0.0000000) [  WNS] Application       Start Scheduler
(  0.0144122) [  WNS] SimpleMM1Step1    Finished a job
                                        Jobs in system: 0
(  0.1685907) [  WNS] SimpleMM1Step1    Generated new job, next job in 0.236225s
                                        Jobs in system: 1
(  0.1685907) [  WNS] SimpleMM1Step1    Processing next job, processing time: 0.178384s
                                        Jobs in system: 1
...
( 10.0000000) [  WNS] Application       Simulation finished
( 10.0000000) [  WNS] Application       Calling shutDown for all modules
( 10.0000000) [  WNS] Application       Destroying all modules
 

This is the contents of the file MM1Step1.hpp

#ifndef WNS_QUEUINGSYSTEM_MM1STEP1_HPP
#define WNS_QUEUINGSYSTEM_MM1STEP1_HPP

#include <WNS/rng/RNGen.hpp>
#include <WNS/simulator/ISimulator.hpp>
#include <WNS/simulator/ISimulationModel.hpp>
#include <WNS/logger/Logger.hpp>
#include <WNS/IOutputStreamable.hpp>
#include <WNS/pyconfig/View.hpp>
#include <WNS/distribution/Distribution.hpp>

#include <boost/bind.hpp>

// In the OpenWNS we use nested namespaces
// which reflect the directory tree
// This file is in ./src/queuingsystem/
// so the convention is to use the same namespace:

namespace wns { namespace queuingsystem {

     // Simulation model for queueing system tutorial (step 1).
     //
     // Here We implement our own simulation model. To allow the openwns
     // application to load our custom simulation model, we must inherit
     // from wns::simulator::ISimulationModel.
     //
    class SimpleMM1Step1 :
        public IOutputStreamable,
        public wns::simulator::ISimulationModel
    {
    public:
        // All simulation models must be constructible from a
        // wns::pyconfig::View.
        explicit
        SimpleMM1Step1(const wns::pyconfig::View& configuration);
        // ^ The Python class used in MM1Step1.py
        // is intentionally called the same.
        // The Python view parameter here gets the values set as member
        // in the constructor of the Python class.

    private:
        // Implementation of the ISimulationModel interface.
        // The openwns application will call this method to indicate
        // that construction of the environment (scheduler, random number
        // generator, etc.) has finished.
        //
        // We will place our own startup code here
        virtual void
        doStartup();

        // Implementation of the ISimulationModel interface.
        // The openwns application will call this method to indicate
        // that the simulation ends and the model should shut down.
        //
        // We will place our own shutdown code here
        virtual void
        doShutdown();

        // Implementation of the IOutputStreamable interface.
        // IOutputStreamable implements the stream output operator for
        // us. It will get the contents to output to the stream by
        // calling this method.
        virtual std::string
        doToString() const;

        // Generates a new job that enters the queuing system
        void
        generateNewJob();

        // Excuted after a job has been processed
        void
        onJobProcessed();

        // Starts processing of the next job if one is available
        void
        processNextJob();

        // A random number generator object pointer. 
        wns::distribution::Distribution* jobInterarrivalTime_;

        // A random number generator object that creates exponentially
        // distributed random numbers.
        wns::distribution::Distribution* jobProcessingTime_;

        // Counter for the number of jobs in our system
        int jobsInSystem_;

        // Used to access the logging subsystem
        wns::logger::Logger logger_;
    };
}
}

#endif // NOT defined WNS_QUEUINGSYSTEM_MM1STEP1_HPP
This is the contents of the file MM1Step1.cpp
#include <WNS/queuingsystem/MM1Step1.hpp>

using namespace wns::queuingsystem;

STATIC_FACTORY_REGISTER_WITH_CREATOR(
    SimpleMM1Step1,
    wns::simulator::ISimulationModel,
    "openwns.queuingsystem.SimpleMM1Step1",
    wns::PyConfigViewCreator);

SimpleMM1Step1::SimpleMM1Step1(const wns::pyconfig::View& config) :
    jobsInSystem_(0),
    logger_(config.get("logger"))
{
    wns::pyconfig::View disConfig = config.get("jobInterArrivalTimeDistribution");
    std::string disName = disConfig.get<std::string>("__plugin__");
    jobInterarrivalTime_ = 
        wns::distribution::DistributionFactory::creator(disName)->create(disConfig);

    disConfig = config.get("jobProcessingTimeDistribution");
    disName = disConfig.get<std::string>("__plugin__");
    jobProcessingTime_ = 
        wns::distribution::DistributionFactory::creator(disName)->create(disConfig);
}

void
SimpleMM1Step1::doStartup()
{
    MESSAGE_SINGLE(NORMAL, logger_, "MM1Step1 started, generating first job\n" << *this);

    generateNewJob();
}

void
SimpleMM1Step1::doShutdown()
{

}

void
SimpleMM1Step1::generateNewJob()
{
    ++jobsInSystem_;

    wns::simulator::Time delayToNextJob = (*jobInterarrivalTime_)();

    MESSAGE_SINGLE(NORMAL, logger_, "Generated new job, next job in " << delayToNextJob << "s\n" << *this);

    // The job is the only job in the system. There is no job that is currently
    // being served -> the server is free and can process the next job
    if (jobsInSystem_ == 1)
    {
        processNextJob();
    }

    wns::simulator::getEventScheduler()->scheduleDelay(
        boost::bind(&SimpleMM1Step1::generateNewJob, this),
        delayToNextJob);

}

void
SimpleMM1Step1::onJobProcessed()
{
    --jobsInSystem_;
    MESSAGE_SINGLE(NORMAL, logger_, "Finished a job\n" << *this);
    // if there are still jobs, serve them
    if (jobsInSystem_ > 0)
    {
        processNextJob();
    }
}

void
SimpleMM1Step1::processNextJob()
{
    wns::simulator::Time processingTime = (*jobProcessingTime_)();

    wns::simulator::getEventScheduler()->scheduleDelay(
        boost::bind(&SimpleMM1Step1::onJobProcessed, this),
        processingTime);
    MESSAGE_SINGLE(NORMAL, logger_, "Processing next job, processing time: " << processingTime << "s\n" << *this);
}

std::string
SimpleMM1Step1::doToString() const
{
    std::stringstream ss;
    ss << "Jobs in system: " << jobsInSystem_;
    return ss.str();
}
This is the contents of the file MM1Step1.py

Generated on Fri Feb 10 03:33:21 2012 for openWNS by  doxygen 1.5.5