add TimeProbe class to data collection framework
authorTom Henderson <tomh@tomh.org>
Wed, 15 Oct 2014 07:06:11 -0700
changeset 11028 abeb2185bce5
parent 11027 e943837b17ad
child 11029 30f8c466a692
add TimeProbe class to data collection framework
CHANGES.html
RELEASE_NOTES
doc/tutorial/source/data-collection.rst
src/stats/doc/data-collection-helpers.rst
src/stats/doc/scope-and-limitations.rst
src/stats/examples/time-probe-example.cc
src/stats/examples/wscript
src/stats/helper/file-helper.cc
src/stats/helper/gnuplot-helper.cc
src/stats/model/time-probe.cc
src/stats/model/time-probe.h
src/stats/wscript
--- a/CHANGES.html	Wed Oct 15 07:00:24 2014 -0700
+++ b/CHANGES.html	Wed Oct 15 07:06:11 2014 -0700
@@ -57,6 +57,11 @@
   <li> It is now possible to print the Neighbor Cache (ARP and NDISC) by using
        the RoutingProtocolHelper
   </li>
+  <li> A TimeProbe class has been added to the data collection framework in 
+       the stats module, enabling TracedValues emitting values of type 
+       ns3::Time to be handled by the framework.
+  </li>
+
 </ul>
 
 <h2>Changes to existing API:</h2>
--- a/RELEASE_NOTES	Wed Oct 15 07:00:24 2014 -0700
+++ b/RELEASE_NOTES	Wed Oct 15 07:06:11 2014 -0700
@@ -25,6 +25,8 @@
   the RoutingProtocolHelper
 - The PrintRoutingTable... and PrintNeighborCache... are now static funtions
   i.e., it's not anymore needed to instantiate an helper just to use them.
+- A new TimeProbe class has been added to hook the data collection framework
+  to traced values emitting Time objects
 
 Bugs fixed
 ----------
--- a/doc/tutorial/source/data-collection.rst	Wed Oct 15 07:00:24 2014 -0700
+++ b/doc/tutorial/source/data-collection.rst	Wed Oct 15 07:06:11 2014 -0700
@@ -359,6 +359,8 @@
   +------------------+-------------------+------------------------------------+
   | bool             | BooleanProbe      | stats/model/uinteger-16-probe.h    |
   +------------------+-------------------+------------------------------------+
+  | ns3::Time        | TimeProbe         | stats/model/time-probe.h           |
+  +------------------+-------------------+------------------------------------+
 
 The following TraceSource types are supported by Probes as of this writing:
 
--- a/src/stats/doc/data-collection-helpers.rst	Wed Oct 15 07:00:24 2014 -0700
+++ b/src/stats/doc/data-collection-helpers.rst	Wed Oct 15 07:06:11 2014 -0700
@@ -605,6 +605,7 @@
 - Uinteger8Probe
 - Uinteger16Probe
 - Uinteger32Probe
+- TimeProbe
 - PacketProbe
 - ApplicationPacketProbe
 - Ipv4PacketProbe
--- a/src/stats/doc/scope-and-limitations.rst	Wed Oct 15 07:00:24 2014 -0700
+++ b/src/stats/doc/scope-and-limitations.rst	Wed Oct 15 07:06:11 2014 -0700
@@ -18,6 +18,7 @@
 - Uinteger8Probe
 - Uinteger16Probe
 - Uinteger32Probe
+- TimeProbe
 - PacketProbe
 - ApplicationPacketProbe
 - Ipv4PacketProbe
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/stats/examples/time-probe-example.cc	Wed Oct 15 07:06:11 2014 -0700
@@ -0,0 +1,247 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014 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
+ */
+
+//
+// This example is designed to show the main features of an ns3::TimeProbe.
+// A test object is used to emit values through a trace source.  The 
+// example shows three ways to use a ns3::TimeProbe to hook the output
+// of this trace source (in addition to hooking the raw trace source).
+//
+// It produces two types of output.  By default, it will generate a
+// gnuplot of interarrival times.  If the '--verbose=1' argument is passed,
+// it will also generate debugging output of the form (for example):
+//
+//     Emitting at 96.5378 seconds
+//     context: raw trace source old 0.293343 new 0.00760254
+//     context: probe1 old 0.293343 new 0.00760254
+//     context: probe2 old 0.293343 new 0.00760254
+//     context: probe3 old 0.293343 new 0.00760254
+//
+// The stopTime defaults to 100 seconds but can be changed by an argument.
+//
+
+#include <string>
+
+#include "ns3/core-module.h"
+#include "ns3/time-probe.h"
+#include "ns3/gnuplot-helper.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("TimeProbeExample");
+
+//
+// This is our test object, an object that emits values according to
+// a Poisson arrival process.   It emits a traced Time value as a 
+// trace source; this takes the value of interarrival time
+//
+class Emitter : public Object
+{
+public:
+  static TypeId GetTypeId (void);
+  Emitter ();
+private:
+  void DoInitialize (void);
+//  void Emit (void);
+  void Emit (void);
+
+  TracedValue<Time> m_interval;  
+  Time m_last;  
+  Ptr<ExponentialRandomVariable> m_var;
+};
+
+NS_OBJECT_ENSURE_REGISTERED (Emitter);
+
+TypeId
+Emitter::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::Emitter")
+    .AddConstructor<Emitter> ()
+    .SetParent<Object> ()
+    .AddTraceSource ("Interval",
+                     "Trace source",
+                     MakeTraceSourceAccessor (&Emitter::m_interval))
+  ;
+  return tid;
+}
+
+Emitter::Emitter (void)
+  : m_interval (Seconds (0)),
+    m_last (Seconds (0))
+{
+  m_var = CreateObject<ExponentialRandomVariable> ();
+}
+
+void
+Emitter::DoInitialize (void)
+{
+  Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Emit, this);
+}
+
+void
+Emitter::Emit (void)
+{
+  NS_LOG_DEBUG ("Emitting at " << Simulator::Now ().GetSeconds () << " seconds");
+  m_interval = Simulator::Now () - m_last;
+  m_last = Simulator::Now ();
+  TimeProbe::SetValueByPath ("/Names/probe3", m_interval);
+  Simulator::Schedule (Seconds (m_var->GetValue ()), &Emitter::Emit, this);
+}
+
+// This is a function to test hooking a raw function to the trace source
+void
+NotifyViaTraceSource (std::string context, Time oldVal, Time newVal)
+{
+  BooleanValue verbose;
+  GlobalValue::GetValueByName ("verbose", verbose);
+  if (verbose.Get ())
+    {
+      std::cout << "context: " << context << " old " << oldVal.GetSeconds () << " new " << newVal.GetSeconds () << std::endl;
+    }
+}
+
+// This is a function to test hooking it to the probe output
+void
+NotifyViaProbe (std::string context, double oldVal, double newVal)
+{
+  BooleanValue verbose;
+  GlobalValue::GetValueByName ("verbose", verbose);
+  if (verbose.Get ())
+    {
+      std::cout << "context: " << context << " old " << oldVal << " new " << newVal << std::endl;
+    }
+}
+
+static ns3::GlobalValue g_verbose ("verbose",
+                                   "Whether to enable verbose output",
+                                   ns3::BooleanValue (false),
+                                   ns3::MakeBooleanChecker ());
+
+int main (int argc, char *argv[])
+{
+  double stopTime = 100.0;
+  bool verbose = false;
+
+  CommandLine cmd;
+  cmd.AddValue ("stopTime", "Time (seconds) to terminate simulation", stopTime);
+  cmd.AddValue ("verbose", "Whether to enable verbose output", verbose);
+  cmd.Parse (argc, argv);
+  bool connected;
+
+  // Set a global value, so that the callbacks can access it
+  if (verbose)
+    {
+      GlobalValue::Bind ("verbose", BooleanValue (true));
+      LogComponentEnable ("TimeProbeExample", LOG_LEVEL_ALL);
+    }
+
+  Ptr<Emitter> emitter = CreateObject<Emitter> ();
+  Names::Add ("/Names/Emitter", emitter);
+
+  //
+  // The below shows typical functionality without a probe
+  // (connect a sink function to a trace source)
+  //
+  connected = emitter->TraceConnect ("Interval", "raw trace source", MakeCallback (&NotifyViaTraceSource));
+  NS_ASSERT_MSG (connected, "Trace source not connected");
+
+  //
+  // Next, we'll show several use cases of using a Probe to access and
+  // filter the values of the underlying trace source
+  //
+
+  //
+  // Probe1 will be hooked directly to the Emitter trace source object
+  //
+
+  // probe1 will be hooked to the Emitter trace source
+  Ptr<TimeProbe> probe1 = CreateObject<TimeProbe> ();
+  // the probe's name can serve as its context in the tracing
+  probe1->SetName ("probe1");
+
+  // Connect the probe to the emitter's Interval
+  connected = probe1->ConnectByObject ("Interval", emitter);
+  NS_ASSERT_MSG (connected, "Trace source not connected to probe1");
+
+  // The probe itself should generate output.  The context that we provide
+  // to this probe (in this case, the probe name) will help to disambiguate
+  // the source of the trace
+  connected = probe1->TraceConnect ("Output", probe1->GetName (), MakeCallback (&NotifyViaProbe));
+  NS_ASSERT_MSG (connected, "Trace source not connected to probe1 Output");
+
+  //
+  // Probe2 will be hooked to the Emitter trace source object by
+  // accessing it by path name in the Config database
+  //
+
+  // Create another similar probe; this will hook up via a Config path
+  Ptr<TimeProbe> probe2 = CreateObject<TimeProbe> ();
+  probe2->SetName ("probe2");
+
+  // Note, no return value is checked here
+  probe2->ConnectByPath ("/Names/Emitter/Interval");
+
+  // The probe itself should generate output.  The context that we provide
+  // to this probe (in this case, the probe name) will help to disambiguate
+  // the source of the trace
+  connected = probe2->TraceConnect ("Output", "probe2", MakeCallback (&NotifyViaProbe));
+  NS_ASSERT_MSG (connected, "Trace source not connected to probe2 Output");
+
+  //
+  // Probe3 will be called by the emitter directly through the
+  // static method SetValueByPath().
+  //
+  Ptr<TimeProbe> probe3 = CreateObject<TimeProbe> ();
+  probe3->SetName ("probe3");
+
+  // By adding to the config database, we can access it later
+  Names::Add ("/Names/probe3", probe3);
+
+  // The probe itself should generate output.  The context that we provide
+  // to this probe (in this case, the probe name) will help to disambiguate
+  // the source of the trace
+  connected = probe3->TraceConnect ("Output", "probe3", MakeCallback (&NotifyViaProbe));
+  NS_ASSERT_MSG (connected, "Trace source not connected to probe3 Output");
+
+  // Plot the interval values
+  GnuplotHelper plotHelper;
+  plotHelper.ConfigurePlot ("time-probe-example",
+                            "Emitter interarrivals vs. Time",
+                            "Simulation time (Seconds)",
+                            "Interarrival time (Seconds)",
+                            "png");
+
+  // Helper creates a TimeProbe and hooks it to the /Names/Emitter/Interval
+  // source.  Helper also takes the Output of the TimeProbe and plots it
+  // as a dataset labeled 'Emitter Interarrival Time'
+  plotHelper.PlotProbe ("ns3::TimeProbe",
+                        "/Names/Emitter/Interval",
+                        "Output",
+                        "Emitter Interarrival Time",
+                        GnuplotAggregator::KEY_INSIDE);
+
+  // The Emitter object is not associated with an ns-3 node, so
+  // it won't get started automatically, so we need to do this ourselves
+  Simulator::Schedule (Seconds (0.0), &Emitter::Initialize, emitter);
+
+  Simulator::Stop (Seconds (stopTime));
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}
--- a/src/stats/examples/wscript	Wed Oct 15 07:00:24 2014 -0700
+++ b/src/stats/examples/wscript	Wed Oct 15 07:06:11 2014 -0700
@@ -10,6 +10,9 @@
     program = bld.create_ns3_program('double-probe-example', ['network', 'stats'])
     program.source = 'double-probe-example.cc'
 
+    program = bld.create_ns3_program('time-probe-example', ['stats'])
+    program.source = 'time-probe-example.cc'
+
     program = bld.create_ns3_program('gnuplot-aggregator-example', ['network', 'stats'])
     program.source = 'gnuplot-aggregator-example.cc'
 
--- a/src/stats/helper/file-helper.cc	Wed Oct 15 07:00:24 2014 -0700
+++ b/src/stats/helper/file-helper.cc	Wed Oct 15 07:06:11 2014 -0700
@@ -543,6 +543,13 @@
         MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger32,
                       m_timeSeriesAdaptorMap[probeContext]));
     }
+  else if (m_probeMap[probeName].second == "ns3::TimeProbe")
+    {
+      m_probeMap[probeName].first->TraceConnectWithoutContext
+        (probeTraceSource,
+        MakeCallback (&TimeSeriesAdaptor::TraceSinkDouble,
+                      m_timeSeriesAdaptorMap[probeContext]));
+    }
   else
     {
       NS_FATAL_ERROR ("Unknown probe type " << m_probeMap[probeName].second << "; need to add support in the helper for this");
--- a/src/stats/helper/gnuplot-helper.cc	Wed Oct 15 07:00:24 2014 -0700
+++ b/src/stats/helper/gnuplot-helper.cc	Wed Oct 15 07:06:11 2014 -0700
@@ -403,6 +403,13 @@
         MakeCallback (&TimeSeriesAdaptor::TraceSinkUinteger32,
                       m_timeSeriesAdaptorMap[probeContext]));
     }
+  else if (m_probeMap[probeName].second == "ns3::TimeProbe")
+    {
+      m_probeMap[probeName].first->TraceConnectWithoutContext
+        (probeTraceSource,
+        MakeCallback (&TimeSeriesAdaptor::TraceSinkDouble,
+                      m_timeSeriesAdaptorMap[probeContext]));
+    }
   else
     {
       NS_FATAL_ERROR ("Unknown probe type " << m_probeMap[probeName].second << "; need to add support in the helper for this");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/stats/model/time-probe.cc	Wed Oct 15 07:06:11 2014 -0700
@@ -0,0 +1,111 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Bucknell University
+ *
+ * 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
+ *
+ * Authors: L. Felipe Perrone (perrone@bucknell.edu)
+ *          Tiago G. Rodrigues (tgr002@bucknell.edu)
+ *
+ * Modified by: Mitch Watrous (watrous@u.washington.edu)
+ *
+ */
+
+#include "ns3/time-probe.h"
+#include "ns3/object.h"
+#include "ns3/log.h"
+#include "ns3/names.h"
+#include "ns3/config.h"
+#include "ns3/trace-source-accessor.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("TimeProbe");
+
+NS_OBJECT_ENSURE_REGISTERED (TimeProbe);
+
+TypeId
+TimeProbe::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::TimeProbe")
+    .SetParent<Probe> ()
+    .AddConstructor<TimeProbe> ()
+    .AddTraceSource ("Output",
+                     "The double valued (units of seconds) probe output",
+                     MakeTraceSourceAccessor (&TimeProbe::m_output))
+  ;
+  return tid;
+}
+
+TimeProbe::TimeProbe ()
+{
+  NS_LOG_FUNCTION (this);
+  m_output = 0;
+}
+
+TimeProbe::~TimeProbe ()
+{
+  NS_LOG_FUNCTION (this);
+}
+
+double
+TimeProbe::GetValue (void) const
+{
+  NS_LOG_FUNCTION (this);
+  return m_output;
+}
+void
+TimeProbe::SetValue (Time newVal)
+{
+  NS_LOG_FUNCTION (this << newVal.GetSeconds ());
+  m_output = newVal.GetSeconds ();
+}
+
+void
+TimeProbe::SetValueByPath (std::string path, Time newVal)
+{
+  NS_LOG_FUNCTION (path << newVal.GetSeconds ());
+  Ptr<TimeProbe> probe = Names::Find<TimeProbe> (path);
+  NS_ASSERT_MSG (probe, "Error:  Can't find probe for path " << path);
+  probe->SetValue (newVal);
+}
+
+bool
+TimeProbe::ConnectByObject (std::string traceSource, Ptr<Object> obj)
+{
+  NS_LOG_FUNCTION (this << traceSource << obj);
+  NS_LOG_DEBUG ("Name of trace source (if any) in names database: " << Names::FindPath (obj));
+  bool connected = obj->TraceConnectWithoutContext (traceSource, MakeCallback (&ns3::TimeProbe::TraceSink, this));
+  return connected;
+}
+
+void
+TimeProbe::ConnectByPath (std::string path)
+{
+  NS_LOG_FUNCTION (this << path);
+  NS_LOG_DEBUG ("Name of trace source to search for in config database: " << path);
+  Config::ConnectWithoutContext (path, MakeCallback (&ns3::TimeProbe::TraceSink, this));
+}
+
+void
+TimeProbe::TraceSink (Time oldData, Time newData)
+{
+  NS_LOG_FUNCTION (this << oldData.GetSeconds () << newData.GetSeconds ());
+  if (IsEnabled ())
+    {
+      m_output = newData.GetSeconds ();
+    }
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/stats/model/time-probe.h	Wed Oct 15 07:06:11 2014 -0700
@@ -0,0 +1,110 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 Bucknell University
+ *
+ * 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
+ *
+ * Authors: L. Felipe Perrone (perrone@bucknell.edu)
+ *          Tiago G. Rodrigues (tgr002@bucknell.edu)
+ *
+ * Modified by: Mitch Watrous (watrous@u.washington.edu)
+ */
+
+#ifndef TIME_PROBE_H
+#define TIME_PROBE_H
+
+#include "ns3/probe.h"
+#include "ns3/object.h"
+#include "ns3/callback.h"
+#include "ns3/boolean.h"
+#include "ns3/traced-value.h"
+#include "ns3/simulator.h"
+#include "ns3/nstime.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup probes
+ *
+ * This class is designed to probe an underlying ns3 TraceSource exporting
+ * an ns3::Time.  This probe exports a trace source "Output" of type 
+ * double, in units of seconds. The Output trace source emits a value when 
+ * either the trace source emits a new value, or when SetValue () is called.
+ *
+ * The current value of the probe can be polled with the GetValue ()
+ * method.
+ */
+class TimeProbe : public Probe
+{
+public:
+  /**
+   * \brief Get the type ID.
+   * \return the object TypeId
+   */
+  static TypeId GetTypeId ();
+  TimeProbe ();
+  virtual ~TimeProbe ();
+
+  /**
+   * \return the most recent value (units of seconds)
+   */
+  double GetValue (void) const;
+
+  /**
+   * \param value set the traced Time to a new value
+   */
+  void SetValue (Time value);
+
+  /**
+   * \brief Set a probe value by its name in the Config system
+   *
+   * \param path Config path to access the probe
+   * \param value set the traced Time to a new value
+   */
+  static void SetValueByPath (std::string path, Time value);
+
+  /**
+   * \brief connect to a trace source attribute provided by a given object
+   *
+   * \param traceSource the name of the attribute TraceSource to connect to
+   * \param obj ns3::Object to connect to
+   * \return true if the trace source was successfully connected
+   */
+  virtual bool ConnectByObject (std::string traceSource, Ptr<Object> obj);
+
+  /**
+   * \brief connect to a trace source provided by a config path
+   *
+   * \param path Config path to bind to
+   *
+   * Note, if an invalid path is provided, the probe will not be connected
+   * to anything.
+   */
+  virtual void ConnectByPath (std::string path);
+
+private:
+  /**
+   * \brief Method to connect to an underlying ns3::TraceSource of type Time 
+   *
+   * \param oldData previous value of the Time 
+   * \param newData new value of the Time 
+   */
+  void TraceSink (Time oldData, Time newData);
+
+  TracedValue<double> m_output; //!< Output trace source.
+};
+
+} // namespace ns3
+
+#endif // TIME_PROBE_H
--- a/src/stats/wscript	Wed Oct 15 07:00:24 2014 -0700
+++ b/src/stats/wscript	Wed Oct 15 07:06:11 2014 -0700
@@ -25,6 +25,7 @@
         'model/probe.cc',
         'model/boolean-probe.cc',
         'model/double-probe.cc',
+        'model/time-probe.cc',
         'model/uinteger-8-probe.cc',
         'model/uinteger-16-probe.cc',
         'model/uinteger-32-probe.cc',
@@ -58,6 +59,7 @@
         'model/probe.h',
         'model/boolean-probe.h',
         'model/double-probe.h',
+        'model/time-probe.h',
         'model/uinteger-8-probe.h',
         'model/uinteger-16-probe.h',
         'model/uinteger-32-probe.h',