manual: revert unwanted change in changeset 13768:cedfa3990e73

This commit is contained in:
Tommaso Pecorella
2018-08-31 17:25:51 +02:00
parent 0ce701b2c6
commit de1fdb7673

View File

@@ -21,35 +21,35 @@ In |ns3| simulations, there are two main aspects to configuration:
This chapter focuses on the second item above: how the many values in use in
|ns3| are organized, documented, and modifiable by |ns3| users. The |ns3|
attribute system is also the underpinning of how traces and statistics are
gathered in the simulator.
gathered in the simulator.
In the course of this chapter we will discuss the various ways to set or
modify the values used by |ns3| model objects. In increasing order of
specificity, these are:
+-----------------------------------+-------------------------------------+----------------------------------+
| Method | Scope | |
+===================================+=====================================+==================================+
| Default Attribute values set when | Affect all instances of the class. | |
| Attributes are defined in | | |
| :cpp:func:`GetTypeId ()`. | | |
+-----------------------------------+-------------------------------------+----------------------------------+
| | :cpp:class:`CommandLine` | Affect all future instances. |
| | :cpp:func:`Config::SetDefault()` | |
| | :cpp:class:`ConfigStore` | |
+-----------------------------------+-------------------------------------+----------------------------------+
| :cpp:class:`ObjectFactory` | Affects all instances created with | |
| | the factory. | |
+-----------------------------------+-------------------------------------+----------------------------------+
| Helper methods with (string/ | Affects all instances created by | |
| AttributeValue) parameter pairs | the helper. | |
+-----------------------------------+-------------------------------------+----------------------------------+
| | :cpp:func:`MyClass::SetX ()` | Alters this particular instance. |
| | :cpp:func:`Object::SetAttribute ()` | Generally this is the only form |
| | :cpp:func:`Config::Set()` | which can be scheduled to alter |
| | an instance once the simulation | |
| | is running. | |
+-----------------------------------+-------------------------------------+----------------------------------+
+---------------------------------------+-------------------------------------+
| Method | Scope |
+=======================================+=====================================+
| Default Attribute values set when | Affect all instances of the class. |
| Attributes are defined in | |
| :cpp:func:`GetTypeId ()`. | |
+---------------------------------------+-------------------------------------+
| | :cpp:class:`CommandLine` | Affect all future instances. |
| | :cpp:func:`Config::SetDefault()` | |
| | :cpp:class:`ConfigStore` | |
+---------------------------------------+-------------------------------------+
| :cpp:class:`ObjectFactory` | Affects all instances created with |
| | the factory. |
+---------------------------------------+-------------------------------------+
| Helper methods with (string/ | Affects all instances created by |
| AttributeValue) parameter pairs | the helper. |
+---------------------------------------+-------------------------------------+
| | :cpp:func:`MyClass::SetX ()` | Alters this particular instance. |
| | :cpp:func:`Object::SetAttribute ()` | Generally this is the only form |
| | :cpp:func:`Config::Set()` | which can be scheduled to alter |
| | an instance once the simulation |
| | is running. |
+---------------------------------------+-------------------------------------+
By "specificity" we mean that methods in later rows in the table
override the values set by, and typically affect fewer instances than,
@@ -70,13 +70,13 @@ system and improving the memory management of our objects:
* "Metadata" system that links the class name to a lot of meta-information
about the object, including:
* The base class of the subclass,
* The set of accessible constructors in the subclass,
* The set of "attributes" of the subclass,
* Whether each attribute can be set, or is read-only,
* The allowed range of values for each attribute.
* Reference counting smart pointer implementation, for memory management.
|ns3| objects that use the attribute system derive from either
@@ -92,10 +92,10 @@ Smart Pointers
As introduced in the |ns3| tutorial, |ns3| objects are memory managed by a
`reference counting smart pointer implementation
<http://en.wikipedia.org/wiki/Smart_pointer>`_, class :cpp:class:`Ptr`.
<http://en.wikipedia.org/wiki/Smart_pointer>`_, class :cpp:class:`Ptr`.
Smart pointers are used extensively in the |ns3| APIs, to avoid passing
references to heap-allocated objects that may cause memory leaks.
references to heap-allocated objects that may cause memory leaks.
For most basic usage (syntax), treat a smart pointer like a regular pointer::
Ptr<WifiNetDevice> nd = ...;
@@ -104,7 +104,7 @@ For most basic usage (syntax), treat a smart pointer like a regular pointer::
So how do you get a smart pointer to an object, as in the first line
of this example?
CreateObject
============
@@ -124,7 +124,7 @@ You can think of this as being functionally equivalent to::
Objects that derive from :cpp:class:`Object` must be allocated on the heap
using :cpp:func:`CreateObject ()`. Those deriving from :cpp:class:`ObjectBase`,
such as |ns3| helper functions and packet headers and trailers,
can be allocated on the stack.
can be allocated on the stack.
In some scripts, you may not see a lot of :cpp:func:`CreateObject ()` calls
in the code; this is because there are some helper objects in effect
@@ -160,7 +160,7 @@ a static :cpp:func:`GetTypeId ()` function call::
This is defined in the ``node.cc`` file as follows::
TypeId
TypeId
Node::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::Node")
@@ -212,7 +212,7 @@ code how to get to the node ID above). There are also "Checker" methods which
are used to validate values against range limitations, such as maximum
and minimum allowed values.
When users want to create Nodes, they will usually call some form of
When users want to create Nodes, they will usually call some form of
:cpp:func:`CreateObject ()`,::
Ptr<Node> n = CreateObject<Node> ();
@@ -225,7 +225,7 @@ or more abstractly, using an object factory, you can create a
factory.SetTypeId (typeId);
Ptr<Object> node = factory.Create <Object> ();
Both of these methods result in fully initialized attributes being available
Both of these methods result in fully initialized attributes being available
in the resulting :cpp:class:`Object` instances.
We next discuss how attributes (values associated with member variables or
@@ -238,7 +238,7 @@ The goal of the attribute system is to organize the access of
internal member objects of a simulation. This goal arises because,
typically in simulation, users will cut and paste/modify existing
simulation scripts, or will use higher-level simulation constructs,
but often will be interested in studying or tracing particular
but often will be interested in studying or tracing particular
internal variables. For instance, use cases such as:
* *"I want to trace the packets on the wireless interface only on the first
@@ -264,7 +264,7 @@ Defining Attributes
We provide a way for users to access values deep in the system, without having
to plumb accessors (pointers) through the system and walk pointer chains to get
to them. Consider a class :cpp:class:`QueueBase` that has a member variable
:cpp:member:`m_maxSize` controlling the depth of the queue.
:cpp:member:`m_maxSize` controlling the depth of the queue.
If we look at the declaration of :cpp:class:`QueueBase`, we see
the following::
@@ -288,7 +288,7 @@ to be represented in different units::
PACKETS, /**< Use number of packets for queue size */
BYTES, /**< Use number of bytes for queue size */
};
class QueueSize
{
...
@@ -329,7 +329,7 @@ registrations are moved into the :cpp:class:`TypeId` class; *e.g*.::
NS_OBJECT_ENSURE_REGISTERED (QueueBase);
TypeId
QueueBase::GetTypeId (void)
QueueBase::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::DropTailQueue")
.SetParent<Queue> ()
@@ -343,7 +343,7 @@ registrations are moved into the :cpp:class:`TypeId` class; *e.g*.::
MakeQueueSizeChecker ())
...
;
return tid;
}
@@ -397,7 +397,7 @@ function begins::
// size of the FIFO queue in the PointToPointNetDevice
//
int
int
main (int argc, char *argv[])
{
@@ -411,7 +411,7 @@ function begins::
// hold queue size values in either unit (bytes or packets). The
// queue base class ns3::QueueBase has a MaxSize attribute that can
// be set to a QueueSize.
// By default, the MaxSize attribute has a value of 100 packets ('100p')
// (this default can be observed in the function QueueBase::GetTypeId)
//
@@ -420,8 +420,8 @@ function begins::
Config::SetDefault ("ns3::QueueBase::MaxSize", StringValue ("80p"));
// The below function call is redundant
Config::SetDefault ("ns3::QueueBase::MaxSize", QueueSizeValue (QueueSize (QueueSizeUnit::PACKETS, 80)));
The main thing to notice in the above are the two equivalent calls to
The main thing to notice in the above are the two equivalent calls to
:cpp:func:`Config::SetDefault ()`. This is how we set the default value
for all subsequently instantiated :cpp:class:`DropTailQueue`\s. We illustrate
that two types of ``Value`` classes, a :cpp:class:`StringValue` and
@@ -517,11 +517,11 @@ SmartPointer
============
Assume that a smart pointer (:cpp:class:`Ptr`) to a relevant network device
is in hand; in the current example, it is the ``net0`` pointer.
is in hand; in the current example, it is the ``net0`` pointer.
One way to change the value is to access a pointer to the underlying queue and
modify its attribute.
First, we observe that we can get a pointer to the (base class)
:cpp:class:`Queue` *via* the
:cpp:class:`PointToPointNetDevice` attributes, where it is called
@@ -551,7 +551,7 @@ the variable `limit` is written into by the GetAttribute method.::
QueueSizeValue limit;
dtq->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("1. dtq limit: " << limit.Get ());
Note that the above downcast is not really needed; we could have gotten
the attribute value directly from ``txQueue``::
@@ -581,7 +581,7 @@ would like to configure a specific attribute with a single statement.
Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxSize",
StringValue ("25p"));
txQueue->GetAttribute ("MaxSize", limit);
txQueue->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("4. txQueue limit changed through namespace: "
<< limit.Get ());
@@ -593,14 +593,14 @@ the second container is the list of all :cpp:class:`NetDevice`\s on
the chosen :cpp:class:`Node`. Finally, the configuration path usually
ends with a succession of member attributes, in this case the ``"MaxSize"``
attribute of the ``"TxQueue"`` of the chosen :cpp:class:`NetDevice`.
We could have also used wildcards to set this value for all nodes and all net
devices (which in this simple example has the same effect as the previous
:cpp:func:`Config::Set ()`)::
Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxSize",
StringValue ("15p"));
txQueue->GetAttribute ("MaxSize", limit);
txQueue->GetAttribute ("MaxSize", limit);
NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: "
<< limit.Get ());
@@ -664,7 +664,7 @@ So in the above, users have a choice of using strings or values::
The system provides some macros that help users declare and define
new AttributeValue subclasses for new types that they want to introduce into
the attribute system:
the attribute system:
* ``ATTRIBUTE_HELPER_HEADER``
* ``ATTRIBUTE_HELPER_CPP``
@@ -680,7 +680,7 @@ specified, nor enforced, by the system. A specific example of this can be seen
in automated configuration programs such as :cpp:class:`ConfigStore`.
Although a given model may arrange it so that Attributes are initialized in a
particular order, another automatic configurator may decide independently to
change Attributes in, for example, alphabetic order.
change Attributes in, for example, alphabetic order.
Because of this non-specific ordering, no Attribute in the system may have any
dependence on any other Attribute. As a corollary, Attribute setters must never
@@ -738,7 +738,7 @@ variable using the metadata system. If it were not already provided by |ns3|,
the user could declare the following addition in the runtime metadata system (to
the :cpp:func:`GetTypeId` definition for :cpp:class:`TcpSocket`)::
.AddAttribute ("Congestion window",
.AddAttribute ("Congestion window",
"Tcp congestion window (bytes)",
UintegerValue (1),
MakeUintegerAccessor (&TcpSocket::m_cWnd),
@@ -763,11 +763,11 @@ its parent class, :cpp:class:`ns3::MobilityModel`.
In the ``my-mobility.h`` header file::
namespace ns3 {
class MyMobility : public MobilityModel
{
This requires we declare the :cpp:func:`GetTypeId ()` function.
This requires we declare the :cpp:func:`GetTypeId ()` function.
This is a one-line public function declaration::
public:
@@ -808,7 +808,7 @@ If we don't want to subclass from an existing class, in the header file
we just inherit from :cpp:class:`ns3::Object`, and in the object file
we set the parent class to :cpp:class:`ns3::Object` with
``.SetParent<Object> ()``.
Typical mistakes here involve:
* Not calling ``NS_OBJECT_ENSURE_REGISTERED ()``
@@ -850,7 +850,7 @@ Header File
double yMin;
double yMax;
};
One macro call and two operators, must be added below the class declaration in
order to turn a Rectangle into a value usable by the ``Attribute`` system::
@@ -877,7 +877,7 @@ In the class definition (``.cc`` file), the code looks like this::
operator >> (std::istream &is, Rectangle &rectangle)
{
char c1, c2, c3;
is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3
is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3
>> rectangle.yMax;
if (c1 != '|' ||
c2 != '|' ||
@@ -901,7 +901,7 @@ and loaded into a future simulation run. This feature is known as the
|ns3| ConfigStore. The :cpp:class:`ConfigStore` is a specialized database for attribute values and default values.
Although it is a separately maintained module in the
``src/config-store/`` directory, we document it here because of its
``src/config-store/`` directory, we document it here because of its
sole dependency on |ns3| core module and attributes.
We can explore this system by using an example from
@@ -930,25 +930,25 @@ to show how the system is extended::
}
int16_t m_int16;
};
NS_OBJECT_ENSURE_REGISTERED (ConfigExample);
Next, we use the Config subsystem to override the defaults in a couple of
ways::
Config::SetDefault ("ns3::ConfigExample::TestInt16", IntegerValue (-5));
Ptr<ConfigExample> a_obj = CreateObject<ConfigExample> ();
NS_ABORT_MSG_UNLESS (a_obj->m_int16 == -5,
"Cannot set ConfigExample's integer attribute via Config::SetDefault");
Ptr<ConfigExample> a2_obj = CreateObject<ConfigExample> ();
a2_obj->SetAttribute ("TestInt16", IntegerValue (-3));
IntegerValue iv;
a2_obj->GetAttribute ("TestInt16", iv);
NS_ABORT_MSG_UNLESS (iv.Get () == -3,
"Cannot set ConfigExample's integer attribute via SetAttribute");
The next statement is necessary to make sure that (one of) the objects
created is rooted in the configuration namespace as an object instance.
This normally happens when you aggregate objects to a :cpp:class:`ns3::Node`
@@ -960,7 +960,7 @@ new root namespace object::
Writing
+++++++
Next, we want to output the configuration store. The examples show how
to do it in two formats, XML and raw text. In practice, one should perform
this step just before calling :cpp:func:`Simulator::Run ()` to save the
@@ -982,7 +982,7 @@ The example shows::
ConfigStore outputConfig;
outputConfig.ConfigureDefaults ();
outputConfig.ConfigureAttributes ();
// Output config store to txt format
Config::SetDefault ("ns3::ConfigStore::Filename", StringValue ("output-attributes.txt"));
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("RawText"));
@@ -990,12 +990,12 @@ The example shows::
ConfigStore outputConfig2;
outputConfig2.ConfigureDefaults ();
outputConfig2.ConfigureAttributes ();
Simulator::Run ();
Simulator::Destroy ();
Note the placement of these statements just prior to the
Note the placement of these statements just prior to the
:cpp:func:`Simulator::Run ()` statement. This output logs all of the
values in place just prior to starting the simulation (*i.e*. after
all of the configuration has taken place).
@@ -1033,7 +1033,7 @@ After running, you can open the ``output-attributes.txt`` file and see:
global ChecksumEnabled "false"
value /$ns3::ConfigExample/TestInt16 "-3"
In the above, several of the default values for attributes for the core
In the above, several of the default values for attributes for the core
and network modules are shown. Then, all the values for the |ns3| global values
are recorded. Finally, the value of the instance of :cpp:class:`ConfigExample`
that was rooted in the configuration namespace is shown. In a real
@@ -1073,7 +1073,7 @@ An XML version also exists in ``output-attributes.xml``:
<global name="ChecksumEnabled" value="false"/>
<value path="/$ns3::ConfigExample/TestInt16" value="-3"/>
</ns3>
This file can be archived with your simulation script and output data.
Reading
@@ -1107,11 +1107,11 @@ for input file configuration is to generate an initial configuration
using the output (``"Save"``) ``"Mode"`` described above, extract from
that configuration file only the elements one wishes to change,
and move these minimal elements to a new configuration file
which can then safely be edited and loaded in a subsequent simulation run.
which can then safely be edited and loaded in a subsequent simulation run.
When the :cpp:class:`ConfigStore` object is instantiated, its attributes
``"Filename"``, ``"Mode"``, and ``"FileFormat"`` must be set,
either *via* command-line or *via* program statements.
either *via* command-line or *via* program statements.
Reading/Writing Example
+++++++++++++++++++++++
@@ -1131,7 +1131,7 @@ write out the resulting attributes to a separate file called
Config::SetDefault ("ns3::ConfigStore::FileFormat", StringValue ("Xml"));
ConfigStore inputConfig;
inputConfig.ConfigureDefaults ();
//
// Allow the user to override any of the defaults and the above Bind () at
// run-time, viacommand-line arguments
@@ -1197,5 +1197,4 @@ are no :cpp:class:`ConfigStore` attributes involved::
Now, when you run the script, a GUI should pop up, allowing you to open menus of
attributes on different nodes/objects, and then launch the simulation execution
when you are done.
when you are done.