/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright 2013 University of Washington * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Simple M/M/1 queue example (Tom Henderson, tomh@tomh.org) */ #include #include #include #include #include #include "ns3/packet.h" #include "ns3/drop-tail-queue.h" #include "ns3/uinteger.h" #include "ns3/simulator.h" #include "ns3/nstime.h" #include "ns3/log.h" #include "ns3/double.h" #include "ns3/abort.h" #include "ns3/command-line.h" #include "ns3/random-variable-stream.h" #include "ns3/gnuplot.h" using namespace ns3; // Run as 'NS_LOG="MM1Queue" ./waf --run mm1-queue' for logging output NS_LOG_COMPONENT_DEFINE ("MM1Queue"); class Enqueuer { public: void SetQueue (Ptr queue) { m_queue = queue; } void SetGenerator (Ptr var) { m_var = var; } void Start (void) { Simulator::Schedule (Seconds (m_var->GetValue ()), &Enqueuer::Generate, this); } private: void Generate (void); Ptr m_queue; Ptr m_var; }; void Enqueuer::Generate (void) { NS_LOG_DEBUG ("Generating a packet at time " << Simulator::Now ().GetSeconds ()); Ptr p = Create (); m_queue->Enqueue (p); Simulator::Schedule (Seconds (m_var->GetValue ()), &Enqueuer::Generate, this); } class Dequeuer { public: void SetQueue (Ptr queue) { m_queue = queue; } void SetGenerator (Ptr var) { m_var = var; } void Start (void) { Simulator::Schedule (Seconds (m_var->GetValue ()), &Dequeuer::Consume, this); } private: void Consume (void); Ptr m_queue; Ptr m_var; }; void Dequeuer::Consume (void) { NS_LOG_DEBUG ("Consuming a packet at time " << Simulator::Now ().GetSeconds ()); Ptr p = m_queue->Dequeue (); p = 0; Simulator::Schedule (Seconds (m_var->GetValue ()), &Dequeuer::Consume, this); } class QueueTracer { public: void SetQueue (Ptr queue); protected: virtual void EnqueueTracer (Ptr p); virtual void DequeueTracer (Ptr p); virtual void DropTracer (Ptr p); private: Ptr m_queue; }; void QueueTracer::SetQueue (Ptr queue) { m_queue = queue; bool ok = queue->TraceConnectWithoutContext ("Enqueue", MakeCallback (&QueueTracer::EnqueueTracer, this)); NS_ABORT_MSG_UNLESS (ok == true, "Could not hook Enqueue trace source"); ok = queue->TraceConnectWithoutContext ("Dequeue", MakeCallback (&QueueTracer::DequeueTracer, this)); NS_ABORT_MSG_UNLESS (ok == true, "Could not hook Dequeue trace source"); ok = queue->TraceConnectWithoutContext ("Drop", MakeCallback (&QueueTracer::DropTracer, this)); NS_ABORT_MSG_UNLESS (ok == true, "Could not hook Drop trace source"); } void QueueTracer::EnqueueTracer (Ptr p) { NS_LOG_DEBUG ("Trace enqueue at time " << Simulator::Now ().GetSeconds ()); } void QueueTracer::DequeueTracer (Ptr p) { NS_LOG_DEBUG ("Trace dequeue at time " << Simulator::Now ().GetSeconds ()); } void QueueTracer::DropTracer (Ptr p) { NS_LOG_DEBUG ("Trace drop at time " << Simulator::Now ().GetSeconds ()); } class QueueSampler { public: void SetQueue (Ptr queue) { m_queue = queue;} void SetGenerator (Ptr var) { m_var = var; } void Start (void) { Simulator::Schedule (Seconds (m_var->GetValue ()), &QueueSampler::Sample, this); } void MakePlots (double lambda, double mu); private: void Sample (void); Ptr m_queue; Ptr m_var; std::vector m_times; std::vector m_queueDepths; }; void QueueSampler:: MakePlots (double lambda, double mu) { using namespace std; ostringstream lambdastr; lambdastr << lambda; ostringstream mustr; mustr << mu; // Plot the queue depth as a function of time. string fileNameWithNoExtension = "mm1-queue-depth-plot"; string graphicsFileName = fileNameWithNoExtension + ".png"; string plotFileName = fileNameWithNoExtension + ".plt"; string plotTitle = "Queue Depth vs. Time (lambda=" + lambdastr.str () + ", mu=" + mustr.str () + ")"; string dataTitle = "Queue Depth (packets)"; // Instantiate the plot and set its title. Gnuplot plot (graphicsFileName); plot.SetTitle (plotTitle); // Make the graphics file, which the plot file will create when it // is used with Gnuplot, be a PNG file. plot.SetTerminal ("png"); // Set the labels for each axis. plot.SetLegend ("Time (seconds)", "Queue Depth"); // Instantiate the dataset, set its title, and make the points be // plotted along with connecting lines. Gnuplot2dDataset dataset; dataset.SetTitle (dataTitle); dataset.SetStyle (Gnuplot2dDataset::LINES_POINTS); unsigned long count = m_queueDepths.size (); unsigned long i; // Populate the 2-D dataset. for (i = 0; i < count; i++) { // Add this point. dataset.Add (m_times[i], m_queueDepths[i]); } // Add the dataset to the plot. plot.AddDataset (dataset); // Open the plot file. ofstream plotFile (plotFileName.c_str()); // Write the plot file. plot.GenerateOutput (plotFile); // Close the plot file. plotFile.close (); } void QueueSampler::Sample (void) { m_times .push_back (Simulator::Now ().GetSeconds ()); m_queueDepths.push_back (m_queue->GetNPackets ()); NS_LOG_DEBUG ("Sampling queue depth at time " << Simulator::Now ().GetSeconds () << " depth = " << m_queue->GetNPackets ()); Simulator::Schedule (Seconds (m_var->GetValue ()), &QueueSampler::Sample, this); } int main (int argc, char *argv[]) { uint32_t numInitialPackets = 10; double lambda = 1; double mu = 2; uint32_t plot = 0; Time stopTime = Seconds (10000.0); CommandLine cmd; cmd.AddValue ("lambda", "arrival rate", lambda); cmd.AddValue ("mu", "departure rate", mu); cmd.AddValue ("plot", "whether to plot (gnuplot)", plot); cmd.AddValue ("initial", "initial packets in the system", numInitialPackets); cmd.Parse (argc, argv); Ptr queue = CreateObject (); bool ok = queue->SetAttributeFailSafe ("MaxPackets", UintegerValue (1000)); NS_ABORT_MSG_UNLESS (ok == true, "Could not set MaxPackets"); NS_ASSERT_MSG (lambda < mu, "Stability only if lamdba < mu"); NS_ASSERT (lambda > 0); NS_ASSERT (mu > 0); Enqueuer enq; enq.SetQueue (queue); Ptr enqrv = CreateObject (); enqrv->SetAttribute ("Mean", DoubleValue (1/lambda)); enq.SetGenerator (enqrv); enq.Start (); Dequeuer deq; deq.SetQueue (queue); Ptr deqrv = CreateObject (); deqrv->SetAttribute ("Mean", DoubleValue (1/mu)); deq.SetGenerator (deqrv); deq.Start (); QueueTracer qt; qt.SetQueue (queue); QueueSampler qs; qs.SetQueue (queue); Ptr qsrv = CreateObject (); qsrv->SetAttribute ("Constant", DoubleValue (1)); qs.SetGenerator (qsrv); qs.Start (); Simulator::Stop (stopTime); // // Pre-simulation stage // // Seed the queue with initial packets for (uint32_t i = 0; i < numInitialPackets; i++) { Ptr p = Create (); queue->Enqueue (p); } // // Simulation stage // Simulator::Run (); // // Post-simulation stage // NS_LOG_DEBUG ("Final queue depth = " << queue->GetNPackets ()); if (plot) { // Make some plots for the sampler. qs.MakePlots (lambda, mu); } Simulator::Destroy (); return 0; }