doc/tutorial/source/tweaking.rst
changeset 6754 7ff69b244b5b
child 7140 d203296efb63
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorial/source/tweaking.rst	Sun Jan 02 22:57:32 2011 -0800
@@ -0,0 +1,996 @@
+.. include:: replace.txt
+
+
+Tweaking
+--------
+
+Using the Logging Module
+************************
+
+We have already taken a brief look at the |ns3| logging module while
+going over the ``first.cc`` script.  We will now take a closer look and 
+see what kind of use-cases the logging subsystem was designed to cover.
+
+Logging Overview
+++++++++++++++++
+Many large systems support some kind of message logging facility, and 
+|ns3| is not an exception.  In some cases, only error messages are 
+logged to the "operator console" (which is typically ``stderr`` in Unix-
+based systems).  In other systems, warning messages may be output as well as 
+more detailed informational messages.  In some cases, logging facilities are 
+used to output debug messages which can quickly turn the output into a blur.
+
+|ns3| takes the view that all of these verbosity levels are useful 
+and we provide a selectable, multi-level approach to message logging.  Logging
+can be disabled completely, enabled on a component-by-component basis, or
+enabled globally; and it provides selectable verbosity levels.  The 
+|ns3| log module provides a straightforward, relatively easy to use
+way to get useful information out of your simulation.
+
+You should understand that we do provide a general purpose mechanism --- 
+tracing --- to get data out of your models which should be preferred for 
+simulation output (see the tutorial section Using the Tracing System for
+more details on our tracing system).  Logging should be preferred for 
+debugging information, warnings, error messages, or any time you want to 
+easily get a quick message out of your scripts or models.
+
+There are currently seven levels of log messages of increasing verbosity
+defined in the system.  
+
+* NS_LOG_ERROR --- Log error messages;
+* NS_LOG_WARN --- Log warning messages;
+* NS_LOG_DEBUG --- Log relatively rare, ad-hoc debugging messages;
+* NS_LOG_INFO --- Log informational messages about program progress;
+* NS_LOG_FUNCTION --- Log a message describing each function called;
+* NS_LOG_LOGIC -- Log messages describing logical flow within a function;
+* NS_LOG_ALL --- Log everything.
+
+We also provide an unconditional logging level that is always displayed,
+irrespective of logging levels or component selection.
+
+*  NS_LOG_UNCOND -- Log the associated message unconditionally.
+
+Each level can be requested singly or cumulatively; and logging can be set 
+up using a shell environment variable (NS_LOG) or by logging system function 
+call.  As was seen earlier in the tutorial, the logging system has Doxygen 
+documentation and now would be a good time to peruse the Logging Module 
+documentation if you have not done so.
+
+Now that you have read the documentation in great detail, let's use some of
+that knowledge to get some interesting information out of the 
+``scratch/myfirst.cc`` example script you have already built.
+
+Enabling Logging
+++++++++++++++++
+Let's use the NS_LOG environment variable to turn on some more logging, but
+first, just to get our bearings, go ahead and run the last script just as you 
+did previously,
+
+::
+
+  ./waf --run scratch/myfirst
+
+You should see the now familiar output of the first |ns3| example
+program
+
+::
+
+  Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  'build' finished successfully (0.413s)
+  Sent 1024 bytes to 10.1.1.2
+  Received 1024 bytes from 10.1.1.1
+  Received 1024 bytes from 10.1.1.2
+
+It turns out that the "Sent" and "Received" messages you see above are
+actually logging messages from the ``UdpEchoClientApplication`` and 
+``UdpEchoServerApplication``.  We can ask the client application, for 
+example, to print more information by setting its logging level via the 
+NS_LOG environment variable.  
+
+I am going to assume from here on that you are using an sh-like shell that uses 
+the"VARIABLE=value" syntax.  If you are using a csh-like shell, then you 
+will have to convert my examples to the "setenv VARIABLE value" syntax 
+required by those shells.
+
+Right now, the UDP echo client application is responding to the following line
+of code in ``scratch/myfirst.cc``,
+
+::
+
+  LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
+
+This line of code enables the ``LOG_LEVEL_INFO`` level of logging.  When 
+we pass a logging level flag, we are actually enabling the given level and
+all lower levels.  In this case, we have enabled ``NS_LOG_INFO``,
+``NS_LOG_DEBUG``, ``NS_LOG_WARN`` and ``NS_LOG_ERROR``.  We can
+increase the logging level and get more information without changing the
+script and recompiling by setting the NS_LOG environment variable like this:
+
+::
+
+  export NS_LOG=UdpEchoClientApplication=level_all
+
+This sets the shell environment variable ``NS_LOG`` to the string,
+
+::
+
+  UdpEchoClientApplication=level_all
+
+The left hand side of the assignment is the name of the logging component we
+want to set, and the right hand side is the flag we want to use.  In this case,
+we are going to turn on all of the debugging levels for the application.  If
+you run the script with NS_LOG set this way, the |ns3| logging 
+system will pick up the change and you should see the following output:
+
+::
+
+  Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build
+  Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  'build' finished successfully (0.404s)
+  UdpEchoClientApplication:UdpEchoClient()
+  UdpEchoClientApplication:SetDataSize(1024)
+  UdpEchoClientApplication:StartApplication()
+  UdpEchoClientApplication:ScheduleTransmit()
+  UdpEchoClientApplication:Send()
+  Sent 1024 bytes to 10.1.1.2
+  Received 1024 bytes from 10.1.1.1
+  UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
+  Received 1024 bytes from 10.1.1.2
+  UdpEchoClientApplication:StopApplication()
+  UdpEchoClientApplication:DoDispose()
+  UdpEchoClientApplication:~UdpEchoClient()
+
+The additional debug information provided by the application is from
+the NS_LOG_FUNCTION level.  This shows every time a function in the application
+is called during script execution.  Note that there are no requirements in the
+|ns3| system that models must support any particular logging 
+functionality.  The decision regarding how much information is logged
+is left to the individual model developer.  In the case of the echo 
+applications, a good deal of log output is available.
+
+You can now see a log of the function calls that were made to the application.
+If you look closely you will notice a single colon between the string 
+``UdpEchoClientApplication`` and the method name where you might have 
+expected a C++ scope operator (``::``).  This is intentional.  
+
+The name is not actually a class name, it is a logging component name.  When 
+there is a one-to-one correspondence between a source file and a class, this 
+will generally be the class name but you should understand that it is not 
+actually a class name, and there is a single colon there instead of a double
+colon to remind you in a relatively subtle way to conceptually separate the 
+logging component name from the class name.
+
+It turns out that in some cases, it can be hard to determine which method
+actually generates a log message.  If you look in the text above, you may
+wonder where the string "``Received 1024 bytes from 10.1.1.2``" comes
+from.  You can resolve this by OR'ing the ``prefix_func`` level into the
+``NS_LOG`` environment variable.  Try doing the following,
+
+::
+
+  export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func'
+
+Note that the quotes are required since the vertical bar we use to indicate an
+OR operation is also a Unix pipe connector.
+
+Now, if you run the script you will see that the logging system makes sure 
+that every message from the given log component is prefixed with the component
+name.
+
+::
+
+  Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  'build' finished successfully (0.417s)
+  UdpEchoClientApplication:UdpEchoClient()
+  UdpEchoClientApplication:SetDataSize(1024)
+  UdpEchoClientApplication:StartApplication()
+  UdpEchoClientApplication:ScheduleTransmit()
+  UdpEchoClientApplication:Send()
+  UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
+  Received 1024 bytes from 10.1.1.1
+  UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20)
+  UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
+  UdpEchoClientApplication:StopApplication()
+  UdpEchoClientApplication:DoDispose()
+  UdpEchoClientApplication:~UdpEchoClient()
+
+You can now see all of the messages coming from the UDP echo client application
+are identified as such.  The message "Received 1024 bytes from 10.1.1.2" is
+now clearly identified as coming from the echo client application.  The 
+remaining message must be coming from the UDP echo server application.  We 
+can enable that component by entering a colon separated list of components in
+the NS_LOG environment variable.
+
+::
+
+  export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func:
+                 UdpEchoServerApplication=level_all|prefix_func'
+
+Warning:  You will need to remove the newline after the ``:`` in the
+example text above which is only there for document formatting purposes.
+
+Now, if you run the script you will see all of the log messages from both the
+echo client and server applications.  You may see that this can be very useful
+in debugging problems.
+
+::
+
+  Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  'build' finished successfully (0.406s)
+  UdpEchoServerApplication:UdpEchoServer()
+  UdpEchoClientApplication:UdpEchoClient()
+  UdpEchoClientApplication:SetDataSize(1024)
+  UdpEchoServerApplication:StartApplication()
+  UdpEchoClientApplication:StartApplication()
+  UdpEchoClientApplication:ScheduleTransmit()
+  UdpEchoClientApplication:Send()
+  UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
+  UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
+  UdpEchoServerApplication:HandleRead(): Echoing packet
+  UdpEchoClientApplication:HandleRead(0x624920, 0x625160)
+  UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
+  UdpEchoServerApplication:StopApplication()
+  UdpEchoClientApplication:StopApplication()
+  UdpEchoClientApplication:DoDispose()
+  UdpEchoServerApplication:DoDispose()
+  UdpEchoClientApplication:~UdpEchoClient()
+  UdpEchoServerApplication:~UdpEchoServer()
+
+It is also sometimes useful to be able to see the simulation time at which a
+log message is generated.  You can do this by ORing in the prefix_time bit.
+
+::
+
+  export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func|prefix_time:
+                 UdpEchoServerApplication=level_all|prefix_func|prefix_time'
+
+Again, you will have to remove the newline above.  If you run the script now,
+you should see the following output:
+
+::
+
+  Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  'build' finished successfully (0.418s)
+  0s UdpEchoServerApplication:UdpEchoServer()
+  0s UdpEchoClientApplication:UdpEchoClient()
+  0s UdpEchoClientApplication:SetDataSize(1024)
+  1s UdpEchoServerApplication:StartApplication()
+  2s UdpEchoClientApplication:StartApplication()
+  2s UdpEchoClientApplication:ScheduleTransmit()
+  2s UdpEchoClientApplication:Send()
+  2s UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2
+  2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
+  2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet
+  2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0)
+  2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2
+  10s UdpEchoServerApplication:StopApplication()
+  10s UdpEchoClientApplication:StopApplication()
+  UdpEchoClientApplication:DoDispose()
+  UdpEchoServerApplication:DoDispose()
+  UdpEchoClientApplication:~UdpEchoClient()
+  UdpEchoServerApplication:~UdpEchoServer()
+
+You can see that the constructor for the UdpEchoServer was called at a 
+simulation time of 0 seconds.  This is actually happening before the 
+simulation starts, but the time is displayed as zero seconds.  The same is true
+for the UdpEchoClient constructor message.
+
+Recall that the ``scratch/first.cc`` script started the echo server 
+application at one second into the simulation.  You can now see that the 
+``StartApplication`` method of the server is, in fact, called at one second.
+You can also see that the echo client application is started at a simulation 
+time of two seconds as we requested in the script.
+
+You can now follow the progress of the simulation from the 
+``ScheduleTransmit`` call in the client that calls ``Send`` to the 
+``HandleRead`` callback in the echo server application.  Note that the 
+elapsed time for the packet to be sent across the point-to-point link is 3.69
+milliseconds.  You see the echo server logging a message telling you that it
+has echoed the packet and then, after another channel delay, you see the echo
+client receive the echoed packet in its ``HandleRead`` method.
+
+There is a lot that is happening under the covers in this simulation that you
+are not seeing as well.  You can very easily follow the entire process by
+turning on all of the logging components in the system.  Try setting the 
+``NS_LOG`` variable to the following,
+
+::
+
+  export 'NS_LOG=*=level_all|prefix_func|prefix_time'
+
+The asterisk above is the logging component wildcard.  This will turn on all 
+of the logging in all of the components used in the simulation.  I won't 
+reproduce the output here (as of this writing it produces 1265 lines of output
+for the single packet echo) but you can redirect this information into a file 
+and look through it with your favorite editor if you like,
+
+::
+
+  ./waf --run scratch/myfirst > log.out 2>&1
+
+I personally use this extremely verbose version of logging when I am presented 
+with a problem and I have no idea where things are going wrong.  I can follow the 
+progress of the code quite easily without having to set breakpoints and step 
+through code in a debugger.  I can just edit up the output in my favorite editor
+and search around for things I expect, and see things happening that I don't 
+expect.  When I have a general idea about what is going wrong, I transition into
+a debugger for a fine-grained examination of the problem.  This kind of output 
+can be especially useful when your script does something completely unexpected.
+If you are stepping using a debugger you may miss an unexpected excursion 
+completely.  Logging the excursion makes it quickly visible.
+
+Adding Logging to your Code
++++++++++++++++++++++++++++
+You can add new logging to your simulations by making calls to the log 
+component via several macros.  Let's do so in the ``myfirst.cc`` script we
+have in the ``scratch`` directory.
+
+Recall that we have defined a logging component in that script:
+
+::
+
+  NS_LOG_COMPONENT_DEFINE ("FirstScriptExample");
+
+You now know that you can enable all of the logging for this component by
+setting the ``NS_LOG`` environment variable to the various levels.  Let's
+go ahead and add some logging to the script.  The macro used to add an 
+informational level log message is ``NS_LOG_INFO``.  Go ahead and add one 
+(just before we start creating the nodes) that tells you that the script is 
+"Creating Topology."  This is done as in this code snippet,
+
+Open ``scratch/myfirst.cc`` in your favorite editor and add the line,
+
+::
+
+  NS_LOG_INFO ("Creating Topology");
+
+right before the lines,
+
+::
+
+  NodeContainer nodes;
+  nodes.Create (2);
+
+Now build the script using waf and clear the ``NS_LOG`` variable to turn 
+off the torrent of logging we previously enabled:
+
+::
+
+  ./waf
+  export NS_LOG=
+
+Now, if you run the script, 
+
+::
+
+  ./waf --run scratch/myfirst
+
+you will ``not`` see your new message since its associated logging 
+component (``FirstScriptExample``) has not been enabled.  In order to see your
+message you will have to enable the ``FirstScriptExample`` logging component
+with a level greater than or equal to ``NS_LOG_INFO``.  If you just want to 
+see this particular level of logging, you can enable it by,
+
+::
+
+  export NS_LOG=FirstScriptExample=info
+
+If you now run the script you will see your new "Creating Topology" log
+message,
+
+::
+
+  Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  'build' finished successfully (0.404s)
+  Creating Topology
+  Sent 1024 bytes to 10.1.1.2
+  Received 1024 bytes from 10.1.1.1
+  Received 1024 bytes from 10.1.1.2
+
+Using Command Line Arguments
+****************************
+
+Overriding Default Attributes
++++++++++++++++++++++++++++++
+Another way you can change how |ns3| scripts behave without editing
+and building is via *command line arguments.*  We provide a mechanism to 
+parse command line arguments and automatically set local and global variables
+based on those arguments.
+
+The first step in using the command line argument system is to declare the
+command line parser.  This is done quite simply (in your main program) as
+in the following code,
+
+::
+
+    int
+  main (int argc, char *argv[])
+  {
+    ...  
+
+    CommandLine cmd;
+    cmd.Parse (argc, argv);
+
+    ...
+  }
+
+This simple two line snippet is actually very useful by itself.  It opens the
+door to the |ns3| global variable and ``Attribute`` systems.  Go 
+ahead and add that two lines of code to the ``scratch/myfirst.cc`` script at
+the start of ``main``.  Go ahead and build the script and run it, but ask 
+the script for help in the following way,
+
+::
+
+  ./waf --run "scratch/myfirst --PrintHelp"
+
+This will ask Waf to run the ``scratch/myfirst`` script and pass the command
+line argument ``--PrintHelp`` to the script.  The quotes are required to 
+sort out which program gets which argument.  The command line parser will
+now see the ``--PrintHelp`` argument and respond with,
+
+::
+
+  Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  'build' finished successfully (0.413s)
+  TcpL4Protocol:TcpStateMachine()
+  CommandLine:HandleArgument(): Handle arg name=PrintHelp value=
+  --PrintHelp: Print this help message.
+  --PrintGroups: Print the list of groups.
+  --PrintTypeIds: Print all TypeIds.
+  --PrintGroup=[group]: Print all TypeIds of group.
+  --PrintAttributes=[typeid]: Print all attributes of typeid.
+  --PrintGlobals: Print the list of globals.
+
+Let's focus on the ``--PrintAttributes`` option.  We have already hinted
+at the |ns3| ``Attribute`` system while walking through the 
+``first.cc`` script.  We looked at the following lines of code,
+
+::
+
+    PointToPointHelper pointToPoint;
+    pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
+    pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
+
+and mentioned that ``DataRate`` was actually an ``Attribute`` of the 
+``PointToPointNetDevice``.  Let's use the command line argument parser
+to take a look at the ``Attributes`` of the PointToPointNetDevice.  The help
+listing says that we should provide a ``TypeId``.  This corresponds to the
+class name of the class to which the ``Attributes`` belong.  In this case it
+will be ``ns3::PointToPointNetDevice``.  Let's go ahead and type in,
+
+::
+
+  ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice"
+
+The system will print out all of the ``Attributes`` of this kind of net device.
+Among the ``Attributes`` you will see listed is,
+
+::
+
+  --ns3::PointToPointNetDevice::DataRate=[32768bps]:
+    The default data rate for point to point links
+
+This is the default value that will be used when a ``PointToPointNetDevice``
+is created in the system.  We overrode this default with the ``Attribute``
+setting in the ``PointToPointHelper`` above.  Let's use the default values 
+for the point-to-point devices and channels by deleting the 
+``SetDeviceAttribute`` call and the ``SetChannelAttribute`` call from 
+the ``myfirst.cc`` we have in the scratch directory.
+
+Your script should now just declare the ``PointToPointHelper`` and not do 
+any ``set`` operations as in the following example,
+
+::
+
+  ...
+
+  NodeContainer nodes;
+  nodes.Create (2);
+
+  PointToPointHelper pointToPoint;
+
+  NetDeviceContainer devices;
+  devices = pointToPoint.Install (nodes);
+
+  ...
+
+Go ahead and build the new script with Waf (``./waf``) and let's go back 
+and enable some logging from the UDP echo server application and turn on the 
+time prefix.
+
+::
+
+  export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time'
+
+If you run the script, you should now see the following output,
+
+::
+
+  Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  'build' finished successfully (0.405s)
+  0s UdpEchoServerApplication:UdpEchoServer()
+  1s UdpEchoServerApplication:StartApplication()
+  Sent 1024 bytes to 10.1.1.2
+  2.25732s Received 1024 bytes from 10.1.1.1
+  2.25732s Echoing packet
+  Received 1024 bytes from 10.1.1.2
+  10s UdpEchoServerApplication:StopApplication()
+  UdpEchoServerApplication:DoDispose()
+  UdpEchoServerApplication:~UdpEchoServer()
+
+Recall that the last time we looked at the simulation time at which the packet
+was received by the echo server, it was at 2.00369 seconds.
+
+::
+
+  2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1
+
+Now it is receiving the packet at 2.25732 seconds.  This is because we just dropped
+the data rate of the ``PointToPointNetDevice`` down to its default of 
+32768 bits per second from five megabits per second.
+
+If we were to provide a new ``DataRate`` using the command line, we could 
+speed our simulation up again.  We do this in the following way, according to
+the formula implied by the help item:
+
+::
+
+  ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps"
+
+This will set the default value of the ``DataRate`` ``Attribute`` back to 
+five megabits per second.  Are you surprised by the result?  It turns out that
+in order to get the original behavior of the script back, we will have to set 
+the speed-of-light delay of the channel as well.  We can ask the command line 
+system to print out the ``Attributes`` of the channel just like we did for
+the net device:
+
+::
+
+  ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointChannel"
+
+We discover the ``Delay`` ``Attribute`` of the channel is set in the following
+way:
+
+::
+
+  --ns3::PointToPointChannel::Delay=[0ns]:
+    Transmission delay through the channel
+
+We can then set both of these default values through the command line system,
+
+::
+
+  ./waf --run "scratch/myfirst
+    --ns3::PointToPointNetDevice::DataRate=5Mbps
+    --ns3::PointToPointChannel::Delay=2ms"
+
+in which case we recover the timing we had when we explicitly set the
+``DataRate`` and ``Delay`` in the script:
+
+::
+
+  Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  'build' finished successfully (0.417s)
+  0s UdpEchoServerApplication:UdpEchoServer()
+  1s UdpEchoServerApplication:StartApplication()
+  Sent 1024 bytes to 10.1.1.2
+  2.00369s Received 1024 bytes from 10.1.1.1
+  2.00369s Echoing packet
+  Received 1024 bytes from 10.1.1.2
+  10s UdpEchoServerApplication:StopApplication()
+  UdpEchoServerApplication:DoDispose()
+  UdpEchoServerApplication:~UdpEchoServer()
+
+Note that the packet is again received by the server at 2.00369 seconds.  We 
+could actually set any of the ``Attributes`` used in the script in this way.
+In particular we could set the ``UdpEchoClient Attribute MaxPackets`` 
+to some other value than one.
+
+How would you go about that?  Give it a try.  Remember you have to comment 
+out the place we override the default ``Attribute`` and explicitly set 
+``MaxPackets`` in the script.  Then you have to rebuild the script.  You 
+will also have to find the syntax for actually setting the new default attribute
+value using the command line help facility.  Once you have this figured out 
+you should be able to control the number of packets echoed from the command 
+line.  Since we're nice folks, we'll tell you that your command line should 
+end up looking something like,
+
+::
+
+  ./waf --run "scratch/myfirst 
+    --ns3::PointToPointNetDevice::DataRate=5Mbps 
+    --ns3::PointToPointChannel::Delay=2ms 
+    --ns3::UdpEchoClient::MaxPackets=2"
+
+Hooking Your Own Values
++++++++++++++++++++++++
+You can also add your own hooks to the command line system.  This is done
+quite simply by using the ``AddValue`` method to the command line parser.
+
+Let's use this facility to specify the number of packets to echo in a 
+completely different way.  Let's add a local variable called ``nPackets``
+to the ``main`` function.  We'll initialize it to one to match our previous 
+default behavior.  To allow the command line parser to change this value, we
+need to hook the value into the parser.  We do this by adding a call to 
+``AddValue``.  Go ahead and change the ``scratch/myfirst.cc`` script to
+start with the following code,
+
+::
+
+  int
+  main (int argc, char *argv[])
+  {
+    uint32_t nPackets = 1;
+
+    CommandLine cmd;
+    cmd.AddValue("nPackets", "Number of packets to echo", nPackets);
+    cmd.Parse (argc, argv);
+
+    ...
+
+Scroll down to the point in the script where we set the ``MaxPackets``
+``Attribute`` and change it so that it is set to the variable ``nPackets``
+instead of the constant ``1`` as is shown below.
+
+::
+
+  echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets));
+
+Now if you run the script and provide the ``--PrintHelp`` argument, you 
+should see your new ``User Argument`` listed in the help display.
+
+Try,
+
+::
+
+  ./waf --run "scratch/myfirst --PrintHelp"
+
+::
+
+  Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  'build' finished successfully (0.403s)
+  --PrintHelp: Print this help message.
+  --PrintGroups: Print the list of groups.
+  --PrintTypeIds: Print all TypeIds.
+  --PrintGroup=[group]: Print all TypeIds of group.
+  --PrintAttributes=[typeid]: Print all attributes of typeid.
+  --PrintGlobals: Print the list of globals.
+  User Arguments:
+      --nPackets: Number of packets to echo
+
+If you want to specify the number of packets to echo, you can now do so by
+setting the ``--nPackets`` argument in the command line,
+
+::
+
+  ./waf --run "scratch/myfirst --nPackets=2"
+
+You should now see
+
+::
+
+  Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build'
+  'build' finished successfully (0.404s)
+  0s UdpEchoServerApplication:UdpEchoServer()
+  1s UdpEchoServerApplication:StartApplication()
+  Sent 1024 bytes to 10.1.1.2
+  2.25732s Received 1024 bytes from 10.1.1.1
+  2.25732s Echoing packet
+  Received 1024 bytes from 10.1.1.2
+  Sent 1024 bytes to 10.1.1.2
+  3.25732s Received 1024 bytes from 10.1.1.1
+  3.25732s Echoing packet
+  Received 1024 bytes from 10.1.1.2
+  10s UdpEchoServerApplication:StopApplication()
+  UdpEchoServerApplication:DoDispose()
+  UdpEchoServerApplication:~UdpEchoServer()
+
+You have now echoed two packets.  Pretty easy, isn't it?
+
+You can see that if you are an |ns3| user, you can use the command 
+line argument system to control global values and ``Attributes``.  If you are
+a model author, you can add new ``Attributes`` to your ``Objects`` and 
+they will automatically be available for setting by your users through the
+command line system.  If you are a script author, you can add new variables to 
+your scripts and hook them into the command line system quite painlessly.
+
+Using the Tracing System
+************************
+
+The whole point of simulation is to generate output for further study, and 
+the |ns3| tracing system is a primary mechanism for this.  Since 
+|ns3| is a C++ program, standard facilities for generating output 
+from C++ programs could be used:  
+
+::
+
+  #include <iostream>
+  ...
+  int main ()
+  {
+    ...
+    std::cout << "The value of x is " << x << std::endl;
+    ...
+  } 
+
+You could even use the logging module to add a little structure to your 
+solution.  There are many well-known problems generated by such approaches
+and so we have provided a generic event tracing subsystem to address the 
+issues we thought were important.
+
+The basic goals of the |ns3| tracing system are:
+
+* For basic tasks, the tracing system should allow the user to generate 
+  standard tracing for popular tracing sources, and to customize which objects
+  generate the tracing;
+* Intermediate users must be able to extend the tracing system to modify
+  the output format generated, or to insert new tracing sources, without 
+  modifying the core of the simulator;
+* Advanced users can modify the simulator core to add new tracing sources
+  and sinks.
+
+The |ns3| tracing system is built on the concepts of independent 
+tracing sources and tracing sinks, and a uniform mechanism for connecting
+sources to sinks.  Trace sources are entities that can signal events that
+happen in a simulation and provide access to interesting underlying data. 
+For example, a trace source could indicate when a packet is received by a net
+device and provide access to the packet contents for interested trace sinks.
+
+Trace sources are not useful by themselves, they must be "connected" to
+other pieces of code that actually do something useful with the information 
+provided by the sink.  Trace sinks are consumers of the events and data
+provided by the trace sources.  For example, one could create a trace sink 
+that would (when connected to the trace source of the previous example) print 
+out interesting parts of the received packet.
+
+The rationale for this explicit division is to allow users to attach new
+types of sinks to existing tracing sources, without requiring editing and 
+recompilation of the core of the simulator.  Thus, in the example above, 
+a user could define a new tracing sink in her script and attach it to an 
+existing tracing source defined in the simulation core by editing only the 
+user script.
+
+In this tutorial, we will walk through some pre-defined sources and sinks and
+show how they may be customized with little user effort.  See the ns-3 manual
+or how-to sections for information on advanced tracing configuration including
+extending the tracing namespace and creating new tracing sources.
+
+ASCII Tracing
++++++++++++++
+|ns3| provides helper functionality that wraps the low-level tracing
+system to help you with the details involved in configuring some easily 
+understood packet traces.  If you enable this functionality, you will see
+output in a ASCII files --- thus the name.  For those familiar with 
+|ns2| output, this type of trace is analogous to the ``out.tr``
+generated by many scripts.
+
+Let's just jump right in and add some ASCII tracing output to our 
+``scratch/myfirst.cc`` script.  Right before the call to 
+``Simulator::Run ()``, add the following lines of code:
+
+::
+
+  AsciiTraceHelper ascii;
+  pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr"));
+
+Like in many other |ns3| idioms, this code uses a  helper object to 
+help create ASCII traces.  The second line contains two nested method calls.  
+The "inside" method, ``CreateFileStream()`` uses an unnamed object idiom
+to create a file stream object on the stack (without an object  name) and pass
+it down to the called method.  We'll go into this more in the future, but all
+you have to know at this point is that you are creating an object representing
+a file named "myfirst.tr" and passing it into ``ns-3``.  You are telling 
+``ns-3`` to deal with the lifetime issues of the created object and also to 
+deal with problems caused by a little-known (intentional) limitation of C++ 
+ofstream objects relating to copy constructors.
+
+The outside call, to ``EnableAsciiAll()``, tells the helper that you 
+want to enable ASCII tracing on all point-to-point devices in your simulation; 
+and you want the (provided) trace sinks to write out information about packet 
+movement in ASCII format.
+
+For those familiar with |ns2|, the traced events are equivalent to 
+the popular trace points that log "+", "-", "d", and "r" events.
+
+You can now build the script and run it from the command line:
+
+::
+
+  ./waf --run scratch/myfirst
+
+Just as you have seen many times before, you will see some messages from Waf and then
+"'build' finished successfully" with some number of messages from 
+the running program.  
+
+When it ran, the program will have created a file named ``myfirst.tr``.  
+Because of the way that Waf works, the file is not created in the local 
+directory, it is created at the top-level directory of the repository by 
+default.  If you want to control where the traces are saved you can use the 
+``--cwd`` option of Waf to specify this.  We have not done so, thus we 
+need to change into the top level directory of our repo and take a look at 
+the ASCII trace file ``myfirst.tr`` in your favorite editor.
+
+Parsing Ascii Traces
+~~~~~~~~~~~~~~~~~~~~
+There's a lot of information there in a pretty dense form, but the first thing
+to notice is that there are a number of distinct lines in this file.  It may
+be difficult to see this clearly unless you widen your window considerably.
+
+Each line in the file corresponds to a *trace event*.  In this case
+we are tracing events on the *transmit queue* present in every 
+point-to-point net device in the simulation.  The transmit queue is a queue 
+through which every packet destined for a point-to-point channel must pass.
+Note that each line in the trace file begins with a lone character (has a 
+space after it).  This character will have the following meaning:
+
+* ``+``: An enqueue operation occurred on the device queue;
+* ``-``: A dequeue operation occurred on the device queue;
+* ``d``: A packet was dropped, typically because the queue was full;
+* ``r``: A packet was received by the net device.
+
+Let's take a more detailed view of the first line in the trace file.  I'll 
+break it down into sections (indented for clarity) with a two digit reference
+number on the left side:
+
+::
+
+  00 + 
+  01 2 
+  02 /NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue 
+  03 ns3::PppHeader (
+  04   Point-to-Point Protocol: IP (0x0021)) 
+  05   ns3::Ipv4Header (
+  06     tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none] 
+  07     length: 1052 10.1.1.1 > 10.1.1.2)
+  08     ns3::UdpHeader (
+  09       length: 1032 49153 > 9) 
+  10       Payload (size=1024)
+
+The first line of this expanded trace event (reference number 00) is the 
+operation.  We have a ``+`` character, so this corresponds to an
+*enqueue* operation on the transmit queue.  The second line (reference 01)
+is the simulation time expressed in seconds.  You may recall that we asked the 
+``UdpEchoClientApplication`` to start sending packets at two seconds.  Here
+we see confirmation that this is, indeed, happening.
+
+The next line of the example trace (reference 02) tell us which trace source
+originated this event (expressed in the tracing namespace).  You can think
+of the tracing namespace somewhat like you would a filesystem namespace.  The 
+root of the namespace is the ``NodeList``.  This corresponds to a container
+managed in the |ns3| core code that contains all of the nodes that are
+created in a script.  Just as a filesystem may have directories under the 
+root, we may have node numbers in the ``NodeList``.  The string 
+``/NodeList/0`` therefore refers to the zeroth node in the ``NodeList``
+which we typically think of as "node 0".  In each node there is a list of 
+devices that have been installed.  This list appears next in the namespace.
+You can see that this trace event comes from ``DeviceList/0`` which is the 
+zeroth device installed in the node. 
+
+The next string, ``$ns3::PointToPointNetDevice`` tells you what kind of 
+device is in the zeroth position of the device list for node zero.
+Recall that the operation ``+`` found at reference 00 meant that an enqueue 
+operation happened on the transmit queue of the device.  This is reflected in 
+the final segments of the "trace path" which are ``TxQueue/Enqueue``.
+
+The remaining lines in the trace should be fairly intuitive.  References 03-04
+indicate that the packet is encapsulated in the point-to-point protocol.  
+References 05-07 show that the packet has an IP version four header and has
+originated from IP address 10.1.1.1 and is destined for 10.1.1.2.  References
+08-09 show that this packet has a UDP header and, finally, reference 10 shows
+that the payload is the expected 1024 bytes.
+
+The next line in the trace file shows the same packet being dequeued from the
+transmit queue on the same node. 
+
+The Third line in the trace file shows the packet being received by the net
+device on the node with the echo server. I have reproduced that event below.
+
+::
+
+  00 r 
+  01 2.25732 
+  02 /NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx 
+  03   ns3::Ipv4Header (
+  04     tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none]
+  05     length: 1052 10.1.1.1 > 10.1.1.2)
+  06     ns3::UdpHeader (
+  07       length: 1032 49153 > 9) 
+  08       Payload (size=1024)
+
+Notice that the trace operation is now ``r`` and the simulation time has
+increased to 2.25732 seconds.  If you have been following the tutorial steps
+closely this means that you have left the ``DataRate`` of the net devices
+and the channel ``Delay`` set to their default values.  This time should 
+be familiar as you have seen it before in a previous section.
+
+The trace source namespace entry (reference 02) has changed to reflect that
+this event is coming from node 1 (``/NodeList/1``) and the packet reception
+trace source (``/MacRx``).  It should be quite easy for you to follow the 
+progress of the packet through the topology by looking at the rest of the 
+traces in the file.
+
+PCAP Tracing
+++++++++++++
+The |ns3| device helpers can also be used to create trace files in the
+``.pcap`` format.  The acronym pcap (usually written in lower case) stands
+for packet capture, and is actually an API that includes the 
+definition of a ``.pcap`` file format.  The most popular program that can
+read and display this format is Wireshark (formerly called Ethereal).
+However, there are many traffic trace analyzers that use this packet format.
+We encourage users to exploit the many tools available for analyzing pcap
+traces.  In this tutorial, we concentrate on viewing pcap traces with tcpdump.
+
+The code used to enable pcap tracing is a one-liner.  
+
+::
+
+  pointToPoint.EnablePcapAll ("myfirst");
+
+Go ahead and insert this line of code after the ASCII tracing code we just 
+added to ``scratch/myfirst.cc``.  Notice that we only passed the string
+"myfirst," and not "myfirst.pcap" or something similar.  This is because the 
+parameter is a prefix, not a complete file name.  The helper will actually 
+create a trace file for every point-to-point device in the simulation.  The 
+file names will be built using the prefix, the node number, the device number
+and a ".pcap" suffix.
+
+In our example script, we will eventually see files named "myfirst-0-0.pcap" 
+and "myfirst-1-0.pcap" which are the pcap traces for node 0-device 0 and 
+node 1-device 0, respectively.
+
+Once you have added the line of code to enable pcap tracing, you can run the
+script in the usual way:
+
+::
+
+  ./waf --run scratch/myfirst
+
+If you look at the top level directory of your distribution, you should now
+see three log files:  ``myfirst.tr`` is the ASCII trace file we have 
+previously examined.  ``myfirst-0-0.pcap`` and ``myfirst-1-0.pcap``
+are the new pcap files we just generated.  
+
+Reading output with tcpdump
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The easiest thing to do at this point will be to use ``tcpdump`` to look
+at the ``pcap`` files.  
+
+::
+
+  tcpdump -nn -tt -r myfirst-0-0.pcap
+  reading from file myfirst-0-0.pcap, link-type PPP (PPP)
+  2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024
+  2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024
+
+  tcpdump -nn -tt -r myfirst-1-0.pcap
+  reading from file myfirst-1-0.pcap, link-type PPP (PPP)
+  2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024
+  2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024
+
+You can see in the dump of ``myfirst-0-0.pcap`` (the client device) that the 
+echo packet is sent at 2 seconds into the simulation.  If you look at the
+second dump (``myfirst-1-0.pcap``) you can see that packet being received
+at 2.257324 seconds.  You see the packet being echoed back at 2.257324 seconds
+in the second dump, and finally, you see the packet being received back at 
+the client in the first dump at 2.514648 seconds.
+
+Reading output with Wireshark
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you are unfamiliar with Wireshark, there is a web site available from which
+you can download programs and documentation:  http://www.wireshark.org/.
+
+Wireshark is a graphical user interface which can be used for displaying these
+trace files.  If you have Wireshark available, you can open each of the trace
+files and display the contents as if you had captured the packets using a
+*packet sniffer*.