utils/bench-simulator.cc
changeset 9831 c08a9d8cb9fa
parent 6845 7dc660ca04ff
child 11464 30814be878cd
equal deleted inserted replaced
9830:f9f0769a40a1 9831:c08a9d8cb9fa
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    17  *
    17  *
    18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
    18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
    19  */
    19  */
    20 
    20 
    21 #include "ns3/core-module.h"
    21 #include <iomanip>
    22 #include <iostream>
    22 #include <iostream>
    23 #include <fstream>
    23 #include <fstream>
    24 #include <vector>
    24 #include <vector>
    25 #include <string.h>
    25 #include <string.h>
    26 
    26 
       
    27 #include "ns3/core-module.h"
       
    28 
    27 using namespace ns3;
    29 using namespace ns3;
    28 
    30 
    29 
    31 
    30 bool g_debug = false;
    32 bool g_debug = false;
    31 
    33 
       
    34 std::string g_me;
       
    35 #define LOG(x)   std::cout << x << std::endl
       
    36 #define LOGME(x) LOG (g_me << x)
       
    37 #define DEB(x) if (g_debug) { LOGME (x) ; }
       
    38 
       
    39 // Output field width
       
    40 int g_fwidth = 6;
       
    41 
    32 class Bench 
    42 class Bench 
    33 {
    43 {
    34 public:
    44 public:
    35   Bench ();
    45   Bench (const uint32_t population, const uint32_t total)
    36   void ReadDistribution (std::istream &istream);
    46   : m_population (population),
    37   void SetTotal (uint32_t total);
    47     m_total (total),
       
    48     m_count (0)
       
    49   { };
       
    50   
       
    51   void SetRandomStream (Ptr<RandomVariableStream> stream)
       
    52   {
       
    53     m_rand = stream;
       
    54   }
       
    55     
       
    56   void SetPopulation (const uint32_t population)
       
    57   {
       
    58     m_population = population;
       
    59   }
       
    60     
       
    61   void SetTotal (const uint32_t total)
       
    62   {
       
    63     m_total = total;
       
    64   }
       
    65     
    38   void RunBench (void);
    66   void RunBench (void);
    39 private:
    67 private:
    40   void Cb (void);
    68   void Cb (void);
    41   std::vector<uint64_t> m_distribution;
    69   
    42   std::vector<uint64_t>::const_iterator m_current;
    70   Ptr<RandomVariableStream> m_rand;
    43   uint32_t m_n;
    71   uint32_t m_population;
    44   uint32_t m_total;
    72   uint32_t m_total;
       
    73   uint32_t m_count;
    45 };
    74 };
    46 
       
    47 Bench::Bench ()
       
    48   : m_n (0),
       
    49     m_total (0)
       
    50 {}
       
    51 
       
    52 void 
       
    53 Bench::SetTotal (uint32_t total)
       
    54 {
       
    55   m_total = total;
       
    56 }
       
    57 
       
    58 void
       
    59 Bench::ReadDistribution (std::istream &input)
       
    60 {
       
    61   double data;
       
    62   while (!input.eof ()) 
       
    63     {
       
    64       if (input >> data) 
       
    65         {
       
    66           uint64_t ns = (uint64_t) (data * 1000000000);
       
    67           m_distribution.push_back (ns);
       
    68         } 
       
    69       else 
       
    70         {
       
    71           input.clear ();
       
    72           std::string line;
       
    73           input >> line;
       
    74         }
       
    75     }
       
    76 }
       
    77 
    75 
    78 void
    76 void
    79 Bench::RunBench (void) 
    77 Bench::RunBench (void) 
    80 {
    78 {
    81   SystemWallClockMs time;
    79   SystemWallClockMs time;
    82   double init, simu;
    80   double init, simu;
       
    81 
       
    82   DEB ("initializing");
       
    83 
    83   time.Start ();
    84   time.Start ();
    84   for (std::vector<uint64_t>::const_iterator i = m_distribution.begin ();
    85   for (uint32_t i = 0; i < m_population; ++i)
    85        i != m_distribution.end (); i++) 
    86     {
    86     {
    87       Time at = NanoSeconds (m_rand->GetValue ());
    87       Simulator::Schedule (NanoSeconds (*i), &Bench::Cb, this);
    88       Simulator::Schedule (at, &Bench::Cb, this);
    88     }
    89     }
    89   init = time.End ();
    90   init = time.End ();
    90   init /= 1000;
    91   init /= 1000;
    91 
    92   DEB ("initialization took " << init << "s");
    92   m_current = m_distribution.begin ();
    93 
    93 
    94   DEB ("running");
    94   time.Start ();
    95   time.Start ();
    95   Simulator::Run ();
    96   Simulator::Run ();
    96   simu = time.End ();
    97   simu = time.End ();
    97   simu /= 1000;
    98   simu /= 1000;
    98 
    99   DEB ("run took " << simu << "s");
    99   std::cout <<
   100 
   100       "init n=" << m_distribution.size () << ", time=" << init << "s" << std::endl <<
   101   LOG (std::setw (g_fwidth) << init <<
   101       "simu n=" << m_n << ", time=" <<simu << "s" << std::endl <<
   102        std::setw (g_fwidth) << (m_population / init) <<
   102       "init " << ((double)m_distribution.size ()) / init << " insert/s, avg insert=" <<
   103        std::setw (g_fwidth) << (init / m_population) <<
   103       init / ((double)m_distribution.size ())<< "s" << std::endl <<
   104        std::setw (g_fwidth) << simu <<
   104       "simu " << ((double)m_n) / simu<< " hold/s, avg hold=" << 
   105        std::setw (g_fwidth) << (m_count / simu) <<
   105       simu / ((double)m_n) << "s" << std::endl
   106        std::setw (g_fwidth) << (simu / m_count));
   106       ;
   107 
       
   108   // Clean up scheduler
       
   109   Simulator::Destroy ();
   107 }
   110 }
   108 
   111 
   109 void
   112 void
   110 Bench::Cb (void)
   113 Bench::Cb (void)
   111 {
   114 {
   112   if (m_n > m_total) 
   115   if (m_count > m_total) 
   113     {
   116     {
   114       return;
   117       return;
   115     }
   118     }
   116   if (m_current == m_distribution.end ()) 
   119   DEB ("event at " << Simulator::Now ().GetSeconds () << "s");
   117     {
   120 
   118       m_current = m_distribution.begin ();
   121   Time after = NanoSeconds (m_rand->GetValue ());
   119     }
   122   Simulator::Schedule (after, &Bench::Cb, this);
   120   if (g_debug) 
   123   ++m_count;
   121     {
   124 }
   122       std::cerr << "event at " << Simulator::Now ().GetSeconds () << "s" << std::endl;
   125 
   123     }
   126 
   124   Simulator::Schedule (NanoSeconds (*m_current), &Bench::Cb, this);
   127 Ptr<RandomVariableStream>
   125   m_current++;
   128 GetRandomStream (std::string filename)
   126   m_n++;
   129 {
   127 }
   130   Ptr<RandomVariableStream> stream = 0;
   128 
   131   
   129 void
   132   if (filename == "")
   130 PrintHelp (void)
   133     {
   131 {
   134       LOGME ("using default exponential distribution");
   132   std::cout << "bench-simulator filename [options]"<<std::endl;
   135       Ptr<ExponentialRandomVariable> erv = CreateObject<ExponentialRandomVariable> ();
   133   std::cout << "  filename: a string which identifies the input distribution. \"-\" represents stdin." << std::endl;
   136       erv->SetAttribute ("Mean", DoubleValue (100));
   134   std::cout << "  Options:"<<std::endl;
   137       stream = erv;
   135   std::cout << "      --list: use std::list scheduler"<<std::endl;
   138     }
   136   std::cout << "      --map: use std::map cheduler"<<std::endl;
   139   else
   137   std::cout << "      --heap: use Binary Heap scheduler"<<std::endl;
   140     {
   138   std::cout << "      --debug: enable some debugging"<<std::endl;
   141       std::istream *input; 
   139 }
   142 
       
   143       if (filename == "-") 
       
   144         {
       
   145           LOGME ("using event distribution from stdin");
       
   146           input = &std::cin;
       
   147         } 
       
   148       else
       
   149         {
       
   150           LOGME ("using event distribution from " << filename);
       
   151           input = new std::ifstream (filename.c_str ());
       
   152         }
       
   153 
       
   154       double value;
       
   155       std::vector<double> nsValues;
       
   156       
       
   157       while (!input->eof ()) 
       
   158         {
       
   159           if (*input >> value) 
       
   160             {
       
   161               uint64_t ns = (uint64_t) (value * 1000000000);
       
   162               nsValues.push_back (ns);
       
   163             } 
       
   164           else 
       
   165             {
       
   166               input->clear ();
       
   167               std::string line;
       
   168               *input >> line;
       
   169             }
       
   170         }
       
   171       LOGME ("found " << nsValues.size () << " entries");
       
   172       Ptr<DeterministicRandomVariable> drv = CreateObject<DeterministicRandomVariable> ();
       
   173       drv->SetValueArray (&nsValues[0], nsValues.size ());
       
   174       stream = drv;
       
   175     }
       
   176   
       
   177   return stream;
       
   178 }
       
   179 
       
   180 
   140 
   181 
   141 int main (int argc, char *argv[])
   182 int main (int argc, char *argv[])
   142 {
   183 {
   143   char const *filename = argv[1];
   184 
   144   std::istream *input;
   185   bool schedCal  = false;
   145   uint32_t n = 1;
   186   bool schedHeap = false;
   146   uint32_t total = 20000;
   187   bool schedList = false;
   147   if (argc == 1)
   188   bool schedMap  = true;
   148     {
   189 
   149       PrintHelp ();
   190   uint32_t pop   =  100000;
   150       return 0;
   191   uint32_t total = 1000000;
   151     }
   192   uint32_t runs  =       1;
   152   argc-=2;
   193   std::string filename = "";
   153   argv+= 2;
   194   
   154   if (strcmp (filename, "-") == 0) 
   195   CommandLine cmd;
   155     {
   196   cmd.Usage ("Benchmark the simulator scheduler.\n"
   156       input = &std::cin;
   197              "\n"
   157     } 
   198              "Event intervals are taken from one of:\n"
   158   else 
   199              "  an exponential distribution, with mean 100 ns,\n"
   159     {
   200              "  an ascii file, given by the --file=\"<filename>\" argument,\n"
   160       input = new std::ifstream (filename);
   201              "  or standard input, by the argument --file=\"-\"\n"
   161     }
   202              "In the case of either --file form, the input is expected\n"
   162   while (argc > 0) 
   203              "to be ascii, giving the relative event times in ns.");
   163     {
   204   cmd.AddValue ("cal",   "use CalendarSheduler",          schedCal);
   164       ObjectFactory factory;
   205   cmd.AddValue ("heap",  "use HeapScheduler",             schedHeap);
   165       if (strcmp ("--list", argv[0]) == 0) 
   206   cmd.AddValue ("list",  "use ListSheduler",              schedList);
   166         {
   207   cmd.AddValue ("map",   "use MapScheduler (default)",    schedMap);
   167           factory.SetTypeId ("ns3::ListScheduler");
   208   cmd.AddValue ("debug", "enable debugging output",       g_debug);
   168           Simulator::SetScheduler (factory);
   209   cmd.AddValue ("pop",   "event population size (default 1E5)",         pop);
   169         } 
   210   cmd.AddValue ("total", "total number of events to run (default 1E6)", total);
   170       else if (strcmp ("--heap", argv[0]) == 0) 
   211   cmd.AddValue ("runs",  "number of runs (default 1)",    runs);
   171         {
   212   cmd.AddValue ("file",  "file of relative event times",  filename);
   172           factory.SetTypeId ("ns3::HeapScheduler");
   213   cmd.AddValue ("prec",  "printed output precision",      g_fwidth);
   173           Simulator::SetScheduler (factory);
   214   cmd.Parse (argc, argv);
   174         } 
   215   g_me = cmd.GetName () + ": ";
   175       else if (strcmp ("--map", argv[0]) == 0) 
   216   g_fwidth += 6;  // 5 extra chars in '2.000002e+07 ': . e+0 _
   176         {
   217 
   177           factory.SetTypeId ("ns3::HeapScheduler");
   218   ObjectFactory factory ("ns3::MapScheduler");
   178           Simulator::SetScheduler (factory);
   219   if (schedCal)  { factory.SetTypeId ("ns3::CalendarScheduler"); }
   179         } 
   220   if (schedHeap) { factory.SetTypeId ("ns3::HeapScheduler");     }
   180       else if (strcmp ("--calendar", argv[0]) == 0)
   221   if (schedList) { factory.SetTypeId ("ns3::ListScheduler");     }  
   181         {
   222   Simulator::SetScheduler (factory);
   182           factory.SetTypeId ("ns3::CalendarScheduler");
   223 
   183           Simulator::SetScheduler (factory);
   224   LOGME (std::setprecision (g_fwidth - 6));
   184         }
   225   DEB ("debugging is ON");
   185       else if (strcmp ("--debug", argv[0]) == 0) 
   226 
   186         {
   227   LOGME ("scheduler: " << factory.GetTypeId ().GetName ());
   187           g_debug = true;
   228   LOGME ("population: " << pop);
   188         } 
   229   LOGME ("total events: " << total);
   189       else if (strncmp ("--total=", argv[0], strlen("--total=")) == 0) 
   230   LOGME ("runs: " << runs);
   190         {
   231   
   191           total = atoi (argv[0]+strlen ("--total="));
   232   Bench *bench = new Bench (pop, total);
   192         } 
   233   bench->SetRandomStream (GetRandomStream (filename));
   193       else if (strncmp ("--n=", argv[0], strlen("--n=")) == 0) 
   234 
   194         {
   235   // table header
   195           n = atoi (argv[0]+strlen ("--n="));
   236   LOG ("");
   196         } 
   237   LOG (std::left << std::setw (g_fwidth) << "Run #" <<
   197 
   238        std::left << std::setw (3 * g_fwidth) << "Inititialization:" <<
   198       argc--;
   239        std::left << std::setw (3 * g_fwidth) << "Simulation:");
   199       argv++;
   240   LOG (std::left << std::setw (g_fwidth) << "" <<
   200   }
   241        std::left << std::setw (g_fwidth) << "Time (s)" <<
   201   Bench *bench = new Bench ();
   242        std::left << std::setw (g_fwidth) << "Rate (ev/s)" <<
   202   bench->ReadDistribution (*input);
   243        std::left << std::setw (g_fwidth) << "Per (s/ev)" <<
       
   244        std::left << std::setw (g_fwidth) << "Time (s)" <<
       
   245        std::left << std::setw (g_fwidth) << "Rate (ev/s)" <<
       
   246        std::left << std::setw (g_fwidth) << "Per (s/ev)" );
       
   247   LOG (std::setfill ('-') <<
       
   248        std::right << std::setw (g_fwidth) << " " <<
       
   249        std::right << std::setw (g_fwidth) << " " <<       
       
   250        std::right << std::setw (g_fwidth) << " " <<       
       
   251        std::right << std::setw (g_fwidth) << " " <<       
       
   252        std::right << std::setw (g_fwidth) << " " <<       
       
   253        std::right << std::setw (g_fwidth) << " " <<       
       
   254        std::right << std::setw (g_fwidth) << " " <<
       
   255        std::setfill (' ')
       
   256        );
       
   257        
       
   258   // prime
       
   259   DEB ("priming");
       
   260   std::cout << std::left << std::setw (g_fwidth) << "(prime)";
       
   261   bench->RunBench ();
       
   262 
       
   263   bench->SetPopulation (pop);
   203   bench->SetTotal (total);
   264   bench->SetTotal (total);
   204   for (uint32_t i = 0; i < n; i++)
   265   for (uint32_t i = 0; i < runs; i++)
   205     {
   266     {
       
   267       std::cout << std::setw (g_fwidth) << i;
       
   268       
   206       bench->RunBench ();
   269       bench->RunBench ();
   207     }
   270     }
   208 
   271 
       
   272   LOG ("");
   209   return 0;
   273   return 0;
   210 }
   274 }