OMNeT++ 6.0 is the result of more than three years of work, and includes many essential new features that we would already have a hard time without. The present changelog summarizes all changes made during the 15+ pre-releases.
We briefly summarize the changes below in each part of OMNeT++ before going into the details.
The most prominent new feature is the new Python-based Analysis Tool in the IDE. The use of Python under the hood allows for arbitrarily complex computations to be performed on the data, visualizing the result in the most appropriate form chosen from a multitude of plot types, and producing publication quality output, all while using an intuitive user interface that makes straightforward tasks easy and convenient. Custom computations and custom plots are also easily accessible. The tool is able to handle large quantities of data. The Python APIs are also available outside the IDE (e.g. for standalone scripts), and a command-line tool for viewing and exporting charts created in the IDE also exists (opp_charttool
).
The NED language now supports parameters that carry C++ objects as values (type object
), which can be used to parameterize modules with structured data (e.g. nontrivial configuration), packet prototypes, function objects, etc. Structured data may come from NED functions like readCSV()
or readJSON()
which parse data files, or may be specified directly in NED or ini files using JSON syntax. The syntax of ini files has even been adjusted to make it more convenient to write multi-line JSON values in it. Further new functionality includes the string match operator =~
, the "spaceship" operator <=>
, and support for Universal Function Call Syntax (UFCS). Incompatible changes include the change in the interpretation of parameter names that are not qualified with the this
or parent
keywords, and the necessity to mark module parameters with @mutable
that are allowed to be set at runtime. Embedding NED files into simulation binaries for easier dissemination has also become possible.
Message descriptions (msg files) have undergone even bigger changes. An import system has been added to make the content of a msg file available in others. The generated code and class descriptors can now be widely customized via properties. Targeted C++ blocks have been introduced for injecting C++ code into various places in the generated source files. Altogether, these (and further, smaller) features facilitate writing significantly cleaner msg files, especially in large projects like INET.
The format of ini files have been made more flexible: the Config
word in section headers is now optional, and long lines can be broken up to multiple lines without using trailing backslashes (just indent the continuation lines).
In the simulation kernel, the most important change is the introduction of the Transmission Updates API, which allows in-progress packet (frame) transmissions to be modified, i.e. aborted, shortened, or extended. This API is necessary for implementing L2 features like frame preemption or on-the-fly frame aggregation. Other changes include the addition of utility APIs like scheduleAfter()
, rescheduleAt()
and rescheduleAfter()
, refinements around module deletion and the introduction of the preDelete()
virtual member function, refinements in the signals and listeners APIs, improved expression evaluation support, and the addition of string-handling utility functions, just to name a few.
Regarding statistics recording, perhaps the most significant addition is the demux
filter, which allows splitting a single stream (of emitted values) to multiple streams. The filter makes it possible to record statistics subdivided by some criteria, e.g. to record statistics per TCP connection, per remote IP address, per traffic class, etc., in INET. Further improvements include the addition of the warmup
filter and the autoWarmupFilter
statistic attribute that allow computed statistics to be calculated correctly also in the presence of a nonzero warm-up period. Result files now hold more metadata: parameter values and configuration entries are now also (optionally) recorded. This change, together with other, smaller adjustments, cause new result files not be understood by previous versions of OMNeT++.
A significant amount of work has been put into improving the looks and functionality of Qtenv: material-style icons, HIDPI support, dark theme support, and countless small features that improve usability, especially around the Object Inspector and the Log View. For example, it is now possible to set the Messages view of the Log to display all timestamps as a delta to a user-specified reference timestamp; or, the Object Inspector now allows selecting a different display mode for a tree node. One important change is that method call animations are now disabled by default.
The Sequence Chart tool in the IDE has been significantly improved, both visually and functionally, with the goal of allowing the user to configure the chart in a way that facilitates understanding of the sequence of events in the simulation. The tools provided for that purpose are the possibility to hide unnecessary elements (unrelated arrows, events, etc), support for user-defined coloring, interactively collapsible compound module axes, horizontally expanded events so that the arrows of nested method calls do not overlap, and more. The eventlog file format has also changed in a non-backward-compatible way, due to the addition of extra elements that allow the Sequence Chart tool to be faster and more scalable.
Generating documentation from NED and MSG files has been made possible from the command line as well, using the new opp_neddoc
tool. Functionality has been extended with the possibility of incorporating external information into the generated pages.
The C++ debugging experience has been made more pleasant in several ways. For example, the "Debug on Error" and "Debug Next Event" functionality in Qtenv may now invoke the integrated debugger of the Simulation IDE, which is especially useful when the simulation was launched from the IDE. The User Guide also contains a hint on how to configure simulations to invoke VS Code as debugger.
Due to improvements in the toolchain and the build process, Windows users may see the linking time of large models like INET Framework to drop dramatically (1-2 orders magnitude, e.g. from several minutes to several seconds). On macOS, Apple Silicon, is currently supported with x86-64 emulation.
Now, the details:
NED:
-
Semantics change: Within a submodule's or connection's curly brace block, the interpretation of parameter, gate, and submodule references that don't use an explicit parent
or this
qualifier has changed. They no longer refer to the enclosing compound module's item, but to the item of (or within) the local submodule or channel object. The interpretation of item references outside subcomponent blocks has remained unchanged. An example:
network Network {
parameters:
int foo;
submodules:
node1: { ... }
node2: Node {
foo = foo; // ERROR: self-reference! Change to 'foo=parent.foo'.
bar = this.foo; // OK
baz = node1.foo; // ERROR: refers to yet-uncreated submodule node2.node1!
bax = parent.node1.foo; // OK
}
}
The set of forms accepted by exists()
and sizeof()
has been expanded. Notably, exists()
can now be used to check the existence of an item in a submodule vector (as submodule vectors may now contain holes, due to @omittedTypename
). Also, the index()
syntax has been removed, index
is only accepted without parens.
Note that referencing a submodule's submodule from NED (i.e. the a.b
or this.a.b
syntax within a submodule block) is generally wrong, because the network is built top-down, and submodules are only created after parameters have already been set up. (An exception is using it in the values of volatile
parameters, because they are evaluated later.)
Error messages have been revised and expanded to be more helpful and facilitate porting NED code from 5.x.
To write NED which is compatible with both OMNeT++ version 5.x and 6.0, qualify all references within subcomponent blocks with explicit parent
or this
, and require OMNeT++ 5.7 which is the first and only 5.x version that understands the parent
keyword.
-
NED grammar: Added object
as parameter type. Parameters of this type may hold objects subclassed from cOwnedObject
that they can take ownership of.
-
NED parameters of type object
may have a @class()
property, with the syntax @class(classname)
or @class(classname?)
. The property specifies that the parameter should only accept objects of the given type and its subclasses. The referenced class must be registered via Register_Class()
or Register_Abstract_Class()
. Parameters declared without the question mark in @class()
don't accept nullptr
as value, while the ones with question mark do.
-
The NED expression syntax has been extended to accept JSON-style constructs, i.e. arrays and dictionaries (termed "object" in JSON), and the nullptr
keyword. The array syntax is a list of values enclosed in square brackets, for example [1, 2, 3]
, and the array is accessible as a cValueArray
object in C++. The dictionary syntax uses curly braces: {"foo" : 1, "bar" : 2 }
, and dictionaries are presented as cValueMap
objects. If a dictionary is prefixed by a name, then the name is interpreted as a class name, and values are interpreted as fields of the object: cMessage { name: "hello", kind: 1}
.
-
Object parameters allow simple values (int, double, bool, string) as well. C++-wise, they are stored in the parameter in cValueHolder
-wrapped cValue
objects.
-
New NED functions have been introduced: get()
(return an element of an array or dictionary), size()
(returns the size of an array or dictionary), eval()
(evaluates a NED expression given as string), dup()
(clones an object). dup()
simply calls an object's C++ dup()
method; it is useful because module parameters of type object
only accept objects they fully own, which can be worked around using dup()
. An example:
object a = [1,2,3];
object b = dup(a); // without dup() it is an error: value is owned by parameter 'a'
As dup()
invoked on containers only duplicates the objects owned by the container, you may need extra dup()
call when referring to objects owned by other parameters. Example:
object a = {};
object b = dup([a,a]); // ERROR (a's inside the array are not cloned)
object c = [dup(a), dup(a)] // OK
-
NED grammar: Made operator precedence more similar to C/C++. Relational operators (==, !=, <, <=, >, >=
) used to be on the same precedence level; now ==
and !=
have lower precedence than the rest.
-
NED grammar: Added the =~
(match) and <=>
(comparison, a.k.a. "spaceship") operators, the undefined
keyword, and bool()
as conversion function.
-
String constants are now accepted with apostrophes too. This makes it possible to write quotation marks in strings without the need to escape them.
-
For quantities (numbers with measurement units), the rules have changed slightly. When specifying quantities with multiple terms, a minus sign is only accepted at the front, to reduce the chance of confusion in arithmetic expressions. I.e. -5s100ms
is valid as a quantity string (and means -5.1s), but 5s-100ms
is no longer.
Also, the plain "0" constant is no longer accepted at places where a quantity with a measurement unit is expected. Reason: it was confusing when the expected unit was dB or dBm. E.g. in omnetpp.ini
, should **.power = 0
be interpreted as 0W or 0dBm?
-
Added support for Universal Function Call Syntax (UFCS) to NED, which means that now any function call may also be written as if the function was a method of its first argument (provided it has one). That is, f(x,..)
can now be also written in the alternative form x.f(...)
. This results in improved readability in certain cases, and allows chaining function calls.
-
xmldoc()
(and other file-reading functions) now interpret the file name as relative to the directory the expression comes from. When xmldoc()
occurs in an included ini file, the file name is now interpreted as relative to the directory containing the included ini file (as opposed to being relative to the main ini file or the working directory.) If xmldoc()
occurs in a NED file, the file name is relative to the directory where that NED file was loaded from.
-
NED functions for reading (from file) and parsing (from string) of CSV, JSON and XML files: parseCSV()
, readCSV()
, parseExtendedCSV()
, readExtendedCSV()
, parseJSON()
, readJSON()
, parseExtendedJSON()
, readExtendedJSON()
, parseXML()
, readXML()
. The "extended" variants support expressions in the file, which will be evaluated during parsing. The XML functions are aliases to the existing xml()
/xmldoc()
functions. Bonus file-related functions: readFile()
, workingDir()
, baseDir()
, resolveFile()
, absFilePath()
.
-
The body of a parametric submodule now allows assigning apparently nonexistent parameters. For example, in the example below, the sleepTime
assignment does not cause an error if FooApp
has a sleepTime
parameter but IApp
does not:
app: <default("FooApp")> like IApp {
parameters:
address = parent.address;
sleepTime = 1s; // ignored if app has no 'sleepTime' parameter
}
-
Implemented @omittedTypename
property. @omittedTypename
allows one to specify a NED type to use when typename=""
is specified for a parametric submodule or channel. @omittedTypename
can be specified on a module interface or channel interface, or on a submodule or connection. It should contain a single (optional) value. The value names the type to use. If it is absent, the submodule or channel will not be created. (The connection will be created without a channel object.)
-
The @mutable
property was introduced for parameters. If the module (or channel) is prepared for a parameter to change its value at runtime (i.e. the new value takes effect), then it should be marked with @mutable
. If @mutable
is missing, then trying to change the parameter will now result in a runtime error ("Cannot change non-mutable parameter".)
The motivation is that in a complex model framework, there is usually a large number of (module or channel) parameters, and so far it has not been obvious for users which parameters can be meaningfully changed at runtime. For example, if a simple module did not implement handleParameterChange()
or the handleParameterChange()
method did not handle a particular parameter, then the user could technically change that NED parameter at runtime, but the change did not take effect. This has often caused confusion.
Parameters of ned.DelayChannel
and ned.DatarateChannel
are now marked @mutable
.
To allow running existing simulation models that have not yet been updated with @mutable
annotations, we have added the parameter-mutability-check
configuration option. Setting parameter-mutability-check=false
will give back the old behavior (not raising an error).
-
Added the expr()
operator to NED, with the purpose of allowing models to accept formulas or expressions which it could use e.g. to determine the processing time of a packet based on packet length or other properties, decide whether a packet should be allowed to pass or should be filtered out based on its contents (filter condition), or to derive x and y coordinates of a mobile node in the function of time.
The argument to expr()
is a NED expression which will typically contain free variables, (like x and y in expr(x+y)
). The expr()
operator creates an object that encapsulates the expression, so it can be assigned to parameters of the type object
. On the C++ side, the module implementation should query the parameter to get at the expression object (of type cOwnedDynamicExpression
), and then it may bind the free variables and evaluate the expression as often as it wishes.
-
In xml()
and xmldoc()
element selectors, $MODULE_INDEX
, $PARENTMODULE_NAME
and similar variables now evaluate to the empty string if they are not applicable, instead of raising an error that was often problematic.
-
Improved error reporting during network building: when an error occurs during assigning a parameter from a NED file, the error message now includes the location of the assignment (file:line in NED file).
MSG:
-
Made the hitherto experimental operation mode and feature set of the message compiler official. This feature set was originally added around OMNeT++ 5.3, and could be enabled by passing the --msg6
option to opp_msgtool
. There was also a no-op --msg4
option that selected the old (OMNeT++ 4.x compatible) operation. Most of the OMNeT++ 6.0 pre-releases shipped with the new operation mode being the default (i.e. --msg6
became a no-op), with features continually being added and refined. Then, finally, the old code and the --msg4
option were removed altogether.
The new operation mode represents a complete overhaul of the message compiler, with significant non-backward-compatible changes to the MSG language. These features were largely motivated by the needs of INET 4.
-
The message compiler is now aware of the OMNeT++ library classes, as if they were imported by default. Declarations come from sim_std.msg
.
-
Added import support. A message file can now reference definitions in other message files using the import
keyword. Type announcements are no longer needed (in fact, they are ignored with a warning), and there is now much less need for cplusplus
blocks as well.
-
Classes without an extends
clause no longer have cObject
as their default base class. If cObject
should be the base class, extends cObject
needs to be added explicitly.
-
Field getters now return const
reference. Separate get..ForUpdate()
getters that return non-const
are generated to cover uses cases when the contained value (typically an object) needs to be modified in-place.
-
Added targeted cplusplus
blocks, with the syntax of cplusplus(<target>) {{..}}
. The target can be h
(the generated header file -- the default), cc
(the generated C++ file), <classname>
(content is inserted into the declaration of the type, just before the closing curly bracket), or <classname>::<methodname>
(content is inserted into the body of the specified method). For the last one, supported methods include the constructor, copy constructor (use Foo&
as name), destructor, operator=
, copy()
, parsimPack()
, parsimUnpack()
, etc., and the per-field generated methods (setter, getter, etc.).
-
Enum names can now be used as field type name, i.e. int foo @enum(Foo)
can now be also written as Foo foo
.
-
Support for const
fields (no setter generated/expected).
-
Support for pointer and owned pointer fields. Owned pointers are denoted with the @owned
field property. Non-owned pointers are simply stored and returned; owned pointers imply delete-in-destructor and clone-on-dup behavior. Owned pointer fields have a remover method generated for them (removeFoo()
for a foo
field, or removeFoo(index)
if the foo
field is an array). The remover method removes and returns the object in the field or array element, and replaces it with a nullptr
. Additionally, if the object is a cOwnedObject
, take()
and drop()
calls are also generated into the bodies of the appropriate methods. There is also an @allowReplace
property that controls whether the setter method of an owned pointer field is allowed to delete the previously set object; the default is @allowReplace(false)
.
-
More convenient dynamic arrays: inserter, appender and eraser methods are now generated into the class. For example insertFoo(index,value)
, appendFoo(value)
, and eraseFoo(index)
are generated for a foo[]
field.
-
Support for pass-by-value for fields. Annotate the field with @byValue
for that. @byValue
and many other properties can also be specified on the class, and they are inherited by fields that instantiate that type.
-
Additional C++ base classes may be specified with the @implements
property.
-
The @str
property causes an str()
method to be generated; the expression to be returned from the method should be given in the value of the property.
-
The @clone
property specifies code to duplicate (one array element of) the field value.
-
The @beforeChange
class property specifies the name of a method to be called from all generated methods that mutate the object, e.g. from setters. It allows implementing objects that become immutable ("frozen") after an initial setup phase.
-
The @custom
field property causes the field to only appear in descriptors, but no code is generated for it at all. One can inject the code that implements the field (data member, getter, setter, etc.) via targeted cplusplus
blocks.
-
The @customImpl
field property, suppresses generating implementations for the field's accessor methods, allowing custom implementations to be supplied by the user.
-
Added the @abstract
field and class property. For a field, it is equivalent to the abstract
keyword; for classes, it marks the whole class as abstract.
-
Abstract fields no longer require the class to be marked with @customize
.
-
Message files now allow more than one namespace <namespace>;
directive. The namespace;
syntax should be used to return to the toplevel C++ namespace.
-
The names of generated method can be overridden with the following field properties: @setter
, @getter
, @getterForUpdate
, @sizeSetter
, @sizeGetter
, @inserter
, @eraser
, @appender
, @remover
, etc.
-
Data types can be overridden with the following properties: @cppType
, @datamemberType
, @argType
, @returnType
, @sizeType
.
-
Changed C++ type for array sizes and indices, i.e. the default of @sizeType
, from int
to size_t
.
-
Added support for setting pointer members and array sizes via class descriptors. (cClassDescriptor
had no facility for that.) This involves adding two methods to cClassDescriptor
(setFieldArraySize()
and setFieldStructValuePointer()
), and support for the @resizable()
and @replaceable
field attributes that tell the message compiler to generate the respective code in the class.
-
The @toString
and @fromString
properties specify a method name or code fragment to convert the field's value to/from string form in class descriptors (getFieldValueAsString()
and setFieldValueFromString()
methods of cClassDescriptor
). In the absence of @toString
, previous versions converted the value to string by writing it to a stream using operator<<
; now the str()
method of the object is used if it has one. If neither @toString
nor str()
exist, an empty string is returned.
-
Likewise, the @toValue
and @fromValue
properties specify a method name or code fragment to convert the field's value to/from cValue
form in class descriptors ((getFieldValue()
and setFieldValue()
methods of cClassDescriptor
)).
-
Better code for generated classes, e.g. inline field initializers, and use of the =delete
syntax of C++11 in the generated code.
-
Better code generated for descriptors, e.g. symbolic constants for field indices.
-
The list of reserved words (words that cannot be used as identifiers in MSG files; it is the union of the words reserved by C++ and by the MSG language) has been updated.
-
A complete list of supported properties (not all of them are explicitly listed above) can be found in an Appendix of the Simulation Manual.
Ini files:
-
It is now possible to break long lines without using a trailing backslash. Continuation lines are marked as such by indenting them, i.e. an indented line is now interpreted as a continuation of the previous line. (It is not possible to break a line inside a string constant that way.) Breaking lines using a trailing backslash way still works (and it can also be used to break string constants, too). Indentation-based line continuation has the advantage over backslashes that it allows placing comments on intermediate lines (whereas with backslashes, the first #
makes the rest of the lines also part of the comment).
-
The Config
prefix in section headers is now optional, that is, the heading [Config PureAloha]
may now be also written as [PureAloha]
, with the two being equivalent.
Simulation kernel / Modules, channels, programming model:
-
Added the scheduleAfter()
, rescheduleAt()
, rescheduleAfter()
methods to cSimpleModule
. They are mainly for convenience, but using rescheduleAt()
instead of cancelEvent()
+ scheduleAt()
will eventually allow for a more efficient implementation.
-
Change in the parameter change notification mechanism: Calls to the handleParameterChange()
method during initialization are no longer suppressed. Because now every change results in a notification, the umbrella handleParameter(nullptr)
call at the end of the initialization is no longer needed and has been removed. The consequence is that handleParameterChange()
methods need to be implemented more carefully, because they may be called at a time when the module may not have completed all initialization stages. Also, if an existing model relied on handleParameter(nullptr)
being called, it needs to be updated.
-
Improvements in the multi-stage initialization protocol with regard to dynamic module creation. Modules now keep track of the last init stage they completed (lastCompletedInitStage
). During an init stage, initialization of modules is restarted if creation/deletion is detected during iteration; modules already initialized in the previous round are recognized and skipped with the help of lastCompletedInitStage
.
-
cModule
now keeps track of submodule vectors as entities, and not just as a collection of submodules with vector indices, meaning that we can now distinguish between nonexistent and zero-size submodule vectors. Random access of vector elements has also became more efficient (constant-time operation). Several new methods have been added as part of this change: hasSubmoduleVector()
, getSubmoduleVectorSize()
, addSubmoduleVector()
, deleteSubmoduleVector()
, setSubmoduleVectorSize()
, getSubmoduleVectorNames()
.
-
As part of the above change, several cModule
and cModuleType
methods have been added or updated. A partial list:
- In
cModule
, the hasSubmodule()
, getSubmoduleNames()
, hasGateVector()
, hasGates()
methods have been added for consistency between submodule and gate APIs.
- The return type of the
getGateNames()
method has been changed from std::string<const char*>
to std::vector<std::string>
, for consistency with getSubmoduleNames()
.
cModule
: added setIndex()
and setNameAndIndex()
.
cModule
, cGate
: getIndex()
, getVectorSize()
, gateSize()
and similar methods now throw exception for non-vector submodules/gates.
cModule
: add separate addGateVector()
method instead misusing addGate()
for creating gate vectors, also for consistency with addSubmoduleVector()
.
- In
cModuleType::create()
, the vectorSize
parameter of create()
has been removed.
- In
cModuleType::createScheduleInit()
, an index argument was added to allow creating submodule vector elements.
cModule
: added addSubmodule()
method which flows more naturally than cModuleType::create()
.
-
There have been changes in submodule and channel iterators. SubmoduleIterator
has been rewritten due to the change in how submodule vectors are represented, which may affect the iteration order in some cases. Iterators now throw an exception if a change occurs in the list of submodules/channels during iteration. Their APIs have also changed a little: operator--
was removed, and init(m)
was renamed to reset()
.
-
Optimized cModule::ChannelIterator
by letting cModule
maintain a linked list of channels (cChannel
), so that ChannelIterator
doesn't have to search through the whole compound module to find them.
-
Module name and full name (i.e. "name[index]") are now stringpooled, which reduces memory usage in exchange for a small build-time extra cost. In addition, string pools now use std::unordered_map
instead of std::map
, which results in improved performance.
-
cComponent
: added getNedTypeAndFullName()
and getNedTypeAndFullPath()
. They are especially useful in constructing error messages in NED functions.
Simulation kernel / Signals and notifications:
-
intpar_t
was renamed to intval_t
, and uintval_t
was added. Both are guaranteed to be at least 64 bits wide.
-
Signal listeners changed to use intval_t
and uintval_t
instead of long
and unsigned long
. This change was necessary because long
is only 32 bits wide on Windows. This affects methods of cListener
and subclasses like cResultFilter
and cResultRecorder
.
-
Emitting nullptr
as a string (const char*
overload of emit()
) is disallowed. The reason is that nullptr
cannot be represented in std::string
, which causes problems e.g. in result filters and recorders.
-
Added two new model change notifications: cPostModuleBuildNotification
, cPostComponentInitializeNotification
.
-
Minor changes in some model change notification classes. In cPreModuleAddNotification
, the vectorSize
field was removed (as it was redundant), and in cPostModuleDeleteNotification
, the interpretation of the index field has changed a little: if the deleted module was not part of a module vector, index is now set to -1 instead of 0.
Simulation kernel / Utilities:
-
Two utility functions were added to cObject
: getClassAndFullPath()
and getClassAndFullName()
. They are mostly useful in logging and error messages.
-
cMatchExpression
: The field =~ pattern
syntax replaces field(pattern)
. Also removed the implicit OR syntax. The old syntaxes looked confusing, and made it difficult to tell apart the concise notation from expression-style notation.
-
Added opp_component_ptr<T>
. It implements a smart pointer that points to a cComponent
(i.e. a module or channel), and automatically becomes nullptr
when the referenced object is deleted. It is a non-owning ("weak") pointer, i.e. the pointer going out of scope has no effect on the referenced object. opp_component_ptr<T>
can be useful in implementing modules that hold pointers to other modules and want to be prepared for those modules getting deleted. It can also be useful for simplifying safe destruction of compound modules containing such modules.
-
New classes: opp_pooledstring
, opp_staticpooledstring
. They provide pool- backed string storage (reference-counted and non-reference-counted, respectively). In turn, the cStringPool
class was removed; use either of the pooled string classes or or opp_staticpooledstring::get(const char *)
instead.
-
Several string functions have been made available for models. A representative partial list: opp_isempty()
, opp_isblank()
, opp_nulltoempty()
, opp_trim()
, opp_split()
, opp_splitandtrim()
, opp_join()
, opp_stringendswith()
, opp_substringbefore()
, etc.
-
The cStringTokenizer
class has been rewritten. It now supports features like optional skipping of empty tokens, optional trimming of tokens, optional honoring of quotes, optional honoring of parens/braces/brackets (i.e. the input string is not broken into tokens in the middle of a parenthesized expression).
Simulation kernel / Visualization support:
-
Added display name support to modules. Display name is a string that optionally appears in Qtenv next to (or instead of) the normal module name, in order to help the user distinguish between similarly-named submodules. For example, application-layer modules app[0]
, app[1]
, etc. in INET may be given descriptive names like "file transfer", "video", "voice", or "CBR", and have them displayed in Qtenv. Display names may be set using the display-name
per-module configuration option, or programmatically by calling setDisplayName()
.
-
Added the g=<group>
(layout group) display string tag, which makes it possible to apply predefined arrangements like row, column, matrix or ring to a group of unrelated submodules. This layouting feature was previously only available for submodule vectors. When "g" tags are used, submodules in the same group are now regarded for layouting purposes as if they were part of the same submodule vector.
-
Made it possible to specify display strings in the configuration. The value given in the display-string
per-component configuration option is merged into the component's display string in the same way inheritance or submodule display strings work: it may add, overwrite or remove items from it.
-
Added text alignment support to text and label figures: cFigure::Alignment
enum, getAlignment()
/setAlignment()
in cAbstractTextFigure
.
-
Added the toAlpha()
method and a constructor taking Color
to cFigure::RGBA
.
Simulation kernel / Transmission updates:
-
The initial send()
is interpreted as: "packet transmission begins now, packet content and duration are, as things are now, going to be this".
Following that, an "update" (or any number of updates) can be sent. An update is a packet with the updated ("actual") content, and with a "remaining transmission duration" attached. Updates may only be sent while transmission is still ongoing.
As an example, aborting a transmission is done by sending a packet with a truncated content and a remaining duration of zero.
Transmission updates are paired with the original packet they modify using a transmissionId. The transmissionId is normally chosen to be the packet ID of the original transmission. Channels should understand updates and handle them accordingly.
Receivers that receive the packet at the end of the reception, which is the default operating mode, will only receive the final update. The original packet and intermediate updates are absorbed by the simulation kernel.
Receivers that receive the packet at the start of the reception (see cGate::setDeliverImmediately()
, previously called setDeliverOnReceptionStart()
) should be prepared to receive all of the original packet and the updates, and handle them appropriately. Tx updates can be recognized from cPacket::isUpdate()
returning true
. cPacket::getRemainingDuration()
returns the remaining transmission duration, and cPacket::getDuration()
the total transmission duration.
As a safeguard against unprepared modules accidentally processing tx updates as normal full-blown packets, the module is only given tx updates if it explicitly declares that it is able to handle them properly. The latter is done by the module calling setTxUpdateSupport(true)
before receiving packets, e.g. in initialize()
.
Non-transmission channels treat tx updates in the same way as they treat any other messages and packets (they ignore the cPacket::isUpdate()
flag).
Details and related changes follow.
-
send()
and sendDirect()
now accept a SendOptions
struct where optional parameters such as delay can be passed in. sendDelayed()
and other send()
/sendDirect()
variants now convert their extra args to a SendOptions
, and delegate to the "standard" send()
/sendDirect()
versions. SendOptions
was introduced as a means to handle combinatorial explosion of send()
variants.
-
For methods that participate in the send protocol (cGate::deliver()
, cModule::arrived()
, cChannel::processMessage()
), SendOptions
was added.
-
cDatarateChannel
now allows the sender to explicitly specify the packet duration in SendOptions
, overriding the duration that the channel would compute from the packet length and the channel datarate.
-
cDatarateChannel
's datarate is now optional: set it to 0 or nan
to leave it unspecified. This change was necessary to support transmitting frames with per-frame data rate selection. If the datarate is unspecified, the packet duration must be supplied in the send call, otherwise a runtime error will be raised.
-
cDatarateChannel
: non-packet messages now pass through without interfering with packets.
-
cDatarateChannel
: disabled channels now let transmission updates through, so that it is possible for the transmitter module to abort the ongoing packet transmission.
-
Tx updates (without duration/remainingDuration) are allowed on paths without transmission channels.
-
In cChannel::processMessage()
, result_t
was renamed cChannel::Result
, and it is now a proper return value (not an output parameter).
-
remainingDuration
was added to cChannel::Result
.
-
cDatarateChannel
now optionally allows multiple concurrent transmissions, with or without any bookkeeping and associated checks. This is useful for modeling a channel with multiple subchannels or carriers. The operating mode has to be selected programmatically, with the channel's setMode()
method. Possible modes are SINGLE
, MULTI
and UNCHECKED
.
-
The forceTransmissionFinishTime()
method of channels has been deprecated. It was always meant as a temporary device to allow implementing aborting frame transmissions, and now with the arrival of the new transmission update API there is no reason to use it any more. Simulations using it should be migrated to the new API.
-
Renamed setDeliverOnReceptionStart()
to setDeliverImmediately()
.
-
Added cSimpleModule::supportsTxUpdates()
flag.
-
cPacket
now carries a remainingDuration
field.
-
cPacket
: eliminated FL_ISRECEPTIONSTART
; isReceptionStart()
now uses remainingDuration
as input; added a similar isReceptionEnd()
method.
-
cPacket::str()
overhaul to reflect new fields and uses.
-
In the APIs, send delay and propagation delay, which were sort of combined into a single value, are now distinct values, handled separately.
Simulation kernel / Module deletion:
-
Added the preDelete()
method to cComponent
. This is an initially empty virtual function that the user can override to add tasks to be done before the module (or channel) is deleted. When deleteModule()
is called on a compound module, it first invokes preDelete()
for each module in the submodule tree, and only starts deleting modules after that. preDelete()
can help simplify network or module deletion in a complex simulation that involves model change listeners.
-
cIListener
's destructor now unsubscribes from all places it was subscribed to. This change was necessitated by the following deleteModule()
change.
-
deleteModule()
: Module destruction sequence was changed so that when deleting a compound module, the compound module's local listeners are notified about the deletion of the submodules.
-
deleteModule()
internals refactored. The motivation was to avoid doing things like firing pre-model-change notifications from a halfway-deleted module. Now we do every potentially risky thing (such as deleting submodules and disconnecting gates) from doDeleteModule()
, and only delete the module object when it is already barebones (no submodules, gates, listeners, etc). With this change, the deletion sequence is now pretty much the reverse of the setup sequence.
-
Now it is allowed for modules to be deleted (including self-deletion) and created at will during initialization.
Simulation kernel / Expressions, object parameters, JSON values:
-
Under the hood, all expression parsing and evaluation tasks now use the same new generic extensible expression evaluator framework. It is used for NED expressions, object matching, scenario constraint, statistics recording, result selection in the Simulation IDE and in opp_scavetool
, in cDynamicExpression
and cMatchExpression
, etc. In the new framework, expression parsing and the translation of the AST to an evaluator tree are done in separate steps, which makes the library very versatile. Evaluators include support for shortcutting logical and conditional operators, constant folding, and an undefined
value (anything involving undefined
will evaluate to undefined
).
-
cNedValue
was renamed to cValue
(compatibility typedef added), as it is now a generic value container used throughout the simulation kernel (cPar
, cExpression
, cClassDescriptor
, etc.), i.e. it is no longer specific to NED.
-
cValue
's doubleValue()
and intValue()
methods now throw an exception when called on a value that has a measurement unit, in order to reduce usage mistakes. If the value has a unit, call either doubleValueInUnit()
/ intValueInUnit()
, or doubleValueRaw()
/intValueRaw()
plus getUnit()
.
-
cValue
changed to hold any_ptr
(see later) instead of cObject*
. This change involves several changes, e.g. type OBJECT
renamed to POINTER
, and pointerValue()
added.
-
cPar
: Added support for object parameters. New type constant: OBJECT
. New methods: setObjectValue()
, objectValue()
, operator=(cObject*)
, operator cObject*
.
-
cPar
: Added cValue
-based generic access: getValue()
, setValue()
.
-
Store origin (file:line) info in cPar
parameters (more precisely, in cDynamicExpression
), so we can report it on evaluation errors. Most visible change: cPar::parse()
gained an extra FileLine
argument. Also, cDynamicExpression
now has get/setSourceLocation()
.
-
Added cValueArray
and cValueMap
classes for representing JSON data in NED expressions. A third class is cValueHolder
, a wrapper around cValue
, which is only used when a non-object value (double, string, etc) is assigned to a NED parameter of the type object
. All three classes subclass from cValueContainer
. Note that behavior of the dup()
methods of cValueArray
and cValueMap
is consistent with that of cArray
and cQueue
, i.e. only those objects that are owned by the cloned container are duplicated.
-
NED functions that take or return values of type object
are now allowed.
-
NED functions can now be defined with the alternative signature:
cValue f(cExpression::Context *context, cValue argv[], int argc)
in addition to the existing signature
cValue f(cComponent *contextComponent, cValue argv[], int argc)
The cExpression::Context
argument allows one to access the context component, and also the directory where the ini file entry or the NED file containing the expression occurred (the "base directory"). Define_NED_Function()
accepts both signatures. The base directory is useful for functions like xmldoc()
that want to access files relative to the location of the NED expression.
-
cNedFunction
now allows to search for NED functions by name AND accepted number of args.
-
cDynamicExpression
has been reimplemented using the new internal Expression
class, and support for user-defined variables, members, methods, and functions was added. As a consequence, the public interface of the class has significantly changed as well.
-
Added the cOwnedDynamicExpression
class which holds the result of a NED expr()
operator. cOwnedDynamicExpression
is both cOwnedObject
and cDynamicExpression
(multiple inheritance). To make this possible, the cObject
base class was removed from cExpression
.
-
cClassDescriptor
: Use exception instead of returning false
for indicating error. The return types of the following methods changed from bool
to void
: setFieldValueAsString()
, setFieldArraySize()
, setFieldStructValuePointer()
.
-
cClassDescriptor
: Added support for setting pointer members and array sizes via class descriptors. New methods: setFieldArraySize()
, setFieldStructValuePointer()
.
-
cClassDescriptor
: Added getFieldValue()
/setFieldValue()
methods to allow accessing fields in a typed way, using cValue
. Previously existing methods getFieldValueAsString()
/setFieldValueAsString()
only allowed string-based access. In MSG files, the @toValue()
and @fromValue()
properties can be used to provide code to convert objects or fields to cValue
.
-
cClassDescriptor
: Methods changed to use any_ptr
instead of void*
for passing the object. (any_ptr
is a smart pointer class that provides type safety for void*
pointers.) Pointers need to be put into and extracted from any_ptr
using the new toAnyPtr()
/ fromAnyPtr()
functions. They have specialized versions for each type (via templates and overloading). For new types, the message compiler generates toAnyPtr()
/fromAnyPtr()
in the header file. For the simulation library classes, these methods come from sim_std_m.h
(generated from sim_std.msg
); sim_std_m.h
is now part of <omnetpp.h>
.
Simulation kernel / Fingerprints:
-
Due a bugfix in cHasher::add(const char *)
, fingerprints that involve hashing strings changed their values.
-
The implementation of cHasher::add(const std::string&)
was changed to be consistent with the add(const char *)
overload. This may cause fingerprint changes in models that use it.
-
Changed the way fingerprints are computed from figures. Most importantly, fingerprints are now affected by all visual properties, not just geometry information. This change only affects fingerprints that contain the 'f' (=figures) ingredient.
-
The introduction of the new expression evaluation framework also somewhat affects fingerprints. The fact that logical operators and inline-if are now shortcutting may change the fingerprint of some simulations, due to consuming fewer random numbers during expression evaluation.
Simulation kernel / Miscellaneous:
-
The getModuleByPath()
method was changed to never return nullptr
, even if an empty string is given as path. Instead, it will throw an exception if the module was not found. This change makes this method consistent with other getter methods in the simulation library, and allows nullptr
checks to be removed from model code that uses it. A new method, findModuleByPath()
was added for cases when an optionally existing module needs to be found. These methods, initially defined on cModule
, have been moved to cComponent
so that they can be called on channels too.
-
Signature change of the cVisitor::visit(cObject *obj)
virtual method: it can now request end of iteration via returning false
(hence, return type changed from void
to bool
) instead of throwing EndTraversalException
. Existing cVisitor
subclasses in model code will need to be adjusted.
-
cPar
: Implemented isMutable()
and the mechanism behind the new @mutable
property.
-
cProperty
: Added getNumKeys()
method; updateWith()
made public.
-
cConfiguration
: Removed getParameterKeyValuePairs()
. Instead, getKeyValuePairs()
made smarter with an extra flags
parameter to be able to handle the various use cases.
-
cMessage
: Allowed isMessage()
to be called from subclasses.
-
cEnvir
: New result recording related methods: recordComponentType()
, recordParameter()
.
-
cEnvir
: Added getConnectionLine()
, which returns the coordinates of a connection arrow. This is for certain custom animations.
-
cEnvir
: Added pausePoint()
, an animation-related experimental API.
-
Result filters: Two new methods in the cResultListener
interface: emitInitialValue()
and callEmitInitialValue()
.
-
cResultFilter
, cResultRecorder
: Grouped init()
args into a Context
struct, The old init()
methods have been preserved as deprecated (and invoked from the new init()
) in case an existing filter/recorder overrides them. Note that potential external calls to the old init()
method won't work any more (they will have no effect), and need to be changed to the new version.
-
Added MergeFilter
, a result filter that allows multiple inputs, and multiplexes them onto its singe output. It is available (as the merge()
function) in the source=
part of @statistic
.
-
Fixed histogram loading issue in the output scalar file (.sca). Bin edges that are very close could become equal in the file if insufficient printing precision was set, rendering the file unreadable. The issue is now handled both during result file writing (if such condition is detected, bin edges are written with full [16-digit] precision) and reading (zero-width bins are merged into adjacent nonzero-width bin).
Simulation kernel / Cleanup:
-
Removed obsolete/deprecated classes and methods. A partial list: cVarHistogram
, cLegacyHistogram
, cLongHistogram
, cDoubleHistogram
, cWeightedStdDev
, cDensityEstBase
; detailedInfo()
method; timeval_*()
functions; cHistogram
methods setRangeAuto()
, setRangeAutoLower()
, setRangeAutoUpper()
, setNumCells()
, setCellSize()
; operator()
of iterator classes in cArray
/cModule
/cQueue
; cFigure
/cCanvas
deprecated methods addFigureAbove()
and addFigureBelow()
; many cAbstractHistogram
(ex-cDensityEstBase
) methods, etc. Instead of the removed timeval_*()
methods, use opp_get_monotonic_clock_usecs()
or opp_get_monotonic_clock_nsecs()
, and perform the arithmetic in int64_t
.
-
Refactoring: Some classes, methods and variables related to ownership management were renamed: cDefaultOwner
-> cSoftOwner
; defaultOwner
-> owningContext
, etc.
-
The setPerformFinalGC()
method was removed. It was meant for internal use, and pretty much unused by model code.
-
Removed the support for OMNeT++ 4.x fingerprints (USE_OMNETPP4x_FINGERPRINTS
).
-
WITH_OMNETPP4x_LISTENER_SUPPORT
was removed.
-
Source code modernization: use in-class member initializers wherever possible. The source code now requires a C++14 compiler.
-
Internal classes, global variables, etc moved into the omnetpp::internal
namespace.
Runtime:
-
Accept expressions as value for (most) config options. For options that accept values both with and without quotes (types STRING, FILENAME, FILENAMES, PATH), a heuristic decides whether a string is to be taken literally or to be evaluated as an expression. Expressions may also use NED operators, module parameters and other NED expression features. For example, it is possible to use the module vector index in the value of the display-name
option: **.app[0..3].display-name = "cbr-" + string(index)
-
Allow parameter values to be specified on the command line. For example, --**.mss=512
is equivalent to inserting the **.mss=512
line near the top of the configuration in omnetpp.ini
.
-
Do not complain about missing omnetpp.ini
if a --network
command-line option is present.
-
There were several improvements related to the NED path. The NEDPATH
environment variable has been renamed to OMNETPP_NED_PATH
, but the old one is still recognized for backward compatibility. Multiple -n
options are now accepted. Also, the NEDPATH
environment variable used to be ignored when a -n
option was present, no longer so. Excluding packages from NED file loading has also been implemented. NED exclusions can be specified in multiple ways: the -x <packagelist>
command-line option, the OMNETPP_NED_PACKAGE_EXCLUSIONS
environment variable, and the ned-package-exclusions
configuration option (they accept semicolon- separated lists).
-
Change in NED loading: Now, if a package has files in several distinct source trees, only one of them may contain a package.ned
file.
-
There were also several improvements related the image path. The -i <imgpath>
option command-line option has been added. It may occur multiple times. The image path is now defined jointly by the OMNETPP_IMAGE_PATH
environment variable, -i
command-line options, and the image-path
configuration option. ./bitmaps
was removed from default image path, as it was virtually unused. The default value ./images
now comes from the default value of the image-path configuration option.
-
Added support for embedding NED files into a binary (an executable or library). The cpp
subcommand of opp_nedtool
generates C++ code that contains the content of NED files as string constants, which can then be compiled into the simulation binary. When the simulation program is started, these embedded NED files will be loaded automatically, and the original NED files will no longer be needed for running simulations. Optional garbling, which prevents NED source code from being directly readable inside the compiled binaries, is also available. A makefrag
file can be used to integrate the NED-to-C++ translation into the build process. To see an example makefrag
file, view the makefrag
help topic in opp_nedtool
.
-
Several global config options were changed to be per-run: scheduler-class
, debug-on-errors
, print-undisposed
, fingerprintcalculator-class
.
-
Added the parsim-num-partitions
config option, which makes it possible to explicitly declare the number of partitions to be used with parallel simulation. (Before, it was explicitly taken by OMNeT++ from MPI or the respective communication layer.)
-
Added the config-recording
configuration option, which controls the amount of configuration options to save into result files.
-
Allow recording actual module/channel parameter values into the output scalar file, via the new param-recording
per-object boolean configuration option. Note that parameters will be recorded as "parameter" result items, not as scalars. For volatile parameters, the expression itself will be recorded (e.g. exponential(0.5)
), not any particular value drawn from it.
-
Added support for result directory subdivision: the resultdir-subdivision
boolean configuration option and the ${iterationvarsd}
variable. The motivation is that the performance of various file managers (including Eclipse's Project Explorer) tends to degrade severely if there are more than a few thousand files in a single directory. In OMNeT++, this problem occurs when a parameter study produces a large number of result files. The common workaround is to "hash" the files into a subdirectory tree. (For example, git also uses this technique to store the contents of .git/objects
dir).
In OMNeT++, such feature can be turned on by setting resultdir-subdivision=
true
in the configuration. Since it is natural to use the iteration variables to define the directory hierarchy, directory subdivision makes use of the new ${iterationvarsd}
configuration variable. This variable is similar to ${iterationvarsf}
but it contains slashes instead of commas, which makes it suitable for creating a directory tree. Enabling directory subdivision will cause /${configname}/${iterationvarsd}
to be appended to the name of the results directory (see result-dir
config option), causing result files to be created in a subdirectory tree under the results directory.
If you want to set up the directory hierarchy in a different way, you can do so by setting the result-dir
config option and appending various variables to the value. E.g.: result-dir = "results/${repetition}"
-
Added the ${datetimef}
inifile variable, which contains the current timestamp in a form usable as part of a file name.
-
Eventlog recording: Implemented snapshot and incremental index support to increase performance and scalability. This introduces significant (breaking) changes in the elog
file format, and adds a set of associated configuration options; see the Sequence Chart section below for details.
-
Added %<
(trim preceding whitespace) to the list of accepted directives
for log prefixes.
-
The obsolete command-line options -x
, -X
, -g
, and -G
were removed.
-
Made the -q
option more permissive: if -c
is missing, assume General
-
Added the -e
option, which prints the value of the given configuration option.
-
opp_run -v
output now includes the system architecture OMNeT++ was built for
(e.g. ARCH_X86_64
or ARCH_AARCH64
).
-
-h resultfilters
and -h resultrecorders
now include the descriptions in the list of result filters and recorders.
-
Added two new -h
topics: latexconfigvars
, sqliteschema
. They are mainly used for producing info for the Appendices in the manual.
-
In order to reduce OMNeT++'s external dependencies, we now use an embedded copy of Yxml as the default XML parser. Yxml (https://dev.yorhel.nl/yxml) is a small and fast SAX-style XML parser with a liberal license.
Support for using LibXML2 remained in place, but very few users will actually need it. Expat support has been removed. Note that no significant functionality is lost when Yxml is used instead of LibXML2. LibXML2 is only needed for Schema or DTD-based validation (and possibly, default value completion), which virtually no simulation models require. Also note that Yxml-based parsing scales much better than LibXML2, both performance-wise and regarding memory usage.
-
The bundled SQLite sources were upgraded to version 3.30.1.
Statistics recording:
-
Added the warmup
filter. This filter discards values during the warm-up period, and is automatically inserted at the front of the result filter chains when the warmup-period
config option is present.
-
Added the autoWarmupFilter
statistic attribute that allows one to disable auto-adding the warmup
filter to a statistic. Example:
@statisticfoo;
This will cause all values from the foo
signal to be recorded, even values emitted during the warm-up period (if one is set).
However, the real motivation behind this feature is to allow the user to add the warm-up filter at a non-default location in the filter chain, because the default location is not always correct.
For example, @statistic[foo](source=min;record=vector)
is equivalent to @statistic[foo](source=min(warmup(foo));autoWarmupFilter=false;record=vector)
, and records (as vector) the minimum of the values which were emitted after the warmup period is over. In contrast, if we replace min(warmup(foo))
with warmup(min(foo))
, it will compute the minimum of ALL values, but only starts recording the result after the warmup period has expired.
This is a crucial difference sometimes. For example, a statistic might record queue length computed as the difference of the number of messages that entered the queue and those that left it:
@statisticqueueLen; //INCORRECT
In this case, if a warmup period is set, the result may even go negative because the pkIn
and pkOut
signals that arrive during the warmup period are ignored, and if pkOut
arrives after that, we are at -1. The correct solution is to add the warmup
filter after the difference between arrivals and departures have been computed:
@statisticqueueLen; //OK
The autoWarmupFilter
option exists because either location for the warmup filter (beginning or end of the chain, or even mid-chain) may make sense for certain statistics. The model author needs to decide per-statistic which one is correct.
-
Added the demux
filter, which allows splitting the stream of values arriving from a signal to multiple streams. For example, if values from a foo
signal are tagged with the labels first
, second
and third
, then the following statistics:
@statisticfoo;
will produce three scalars: first:foo:count(demux)
, second:foo:count(demux)
, and third:foo:count(demux)
. The labels are taken from the (full) name of the details object specified in the emit()
call.
This filter is especially useful if you intend to save multiple instances of the same statistics from the same module (e.g. per-connection TCP statistics).
-
In result files, the ,vector
suffix is now suppressed in the titles of vector results (similarly also ,histogram
and ,stats
), as they simply echo the result item's type. (They were there in the first place because recording mode is automatically appended to result titles @statistic(title=...)
after a comma; it is now suppressed for the mentioned recording modes.)
-
Added the merge
filter which multiplexes several inputs onto a single output. It is available in the source=
part of @statistic
.
-
Result filters: The count
and sum
filters now record the initial zero value as well.
-
Result files now include two new result attributes for each item: recordingmode
, which is the item in the @statistic(record=...)
list that produced the given result item, and moduledisplaypath
, the module/channel path that contains display names instead of the normal names where available.
-
sumPerDuration
filter: fix computation when invoked during warmup period.
Cmdenv:
- Added the
cmdenv-fake-gui
boolean configuration option, which enables "fake GUI" functionality during simulation. "Fake GUI" means that refreshDisplay()
is periodically invoked during simulation, in order to mimic the behavior of a graphical user interface like Qtenv. It is useful for batch testing of simulation models that contain visualization. Several further configuration options exist for controlling the details: cmdenv-fake-gui-after-event-probability
, cmdenv-fake-gui-before-event-probability
, cmdenv-fake-gui-on-hold-numsteps
, cmdenv-fake-gui-on-hold-probability
, cmdenv-fake-gui-on-simtime-numsteps
, cmdenv-fake-gui-on-simtime-probability
, cmdenv-fake-gui-seed
.
Qtenv:
-
Modernized look: Material-style SVG-based icons, HIDPI support, dark theme support.
-
New actions on the main toolbar: "Debug next event", "Debug on errors", "Show animation parameters". ("Load NED file" was removed from the toolbar as it was rarely needed, but it's still available from the menu.)
-
The default digit separator used in the main simulation time and event number displays was changed to space.
-
A lot of effort was made to refine packet animation, also with regard to the new "transmission updates" API. For example, the animation filter now affects deliveries as well, and transmissions on ideal channels are now shown as a full-length line. Transmission updates are drawn as "notches" on the message line.
-
Turned off animating method calls by default. The rationale is that method call animations usually expose low-level (C++ implementation level) details on the GUI, which are rarely of interest to a casual user.
-
Added the possibility to disable method call visualization locally (for that module type) via the context menu, even when the global switch in the Preferences dialog is turned on.
-
Added support for showing a submodule's display name under the icon instead of, or in addition to, the normal name. The format can be selected in the context menu.
-
The view mode (grouped/flat/inheritance/children) in the Object Inspector used to be tied to the type (class) of the object displayed in the inspector. Since that resulted in too much mode switching while the user navigated the object tree, and the switching logic was not easily discoverable by the user, we removed the feature of per-type remembering of view modes. The view mode now only changes when the user explicitly switches in on the UI.
-
In the Object Inspector, added the possibility to select display mode (Children/Grouped/Flat/Inheritance) per-node. If display mode override is specified for a node, it will affect the whole subtree. The display mode for the selected tree can be changed via hotkey (Ctrl+B) or via the context menu.
-
The "Set Sending Time as Reference" option was added to the messages view context menu. This option makes it possible to set a reference time, and display all other times as a delta compared to it.
-
In the messages view, there was a slight change in the notation used for the source and destination modules of the message, in order to make it unambiguous. Use explicit "." and "^" to indicate the location of the module. Also, it now uses arrows of uniform lengths everywhere.
-
The "Allow Backward Arrows for Hops" option was added to the messages view context menu. When this option is enabled, it allows the use of backward arrows to ensure a consistent relative ordering of modules in the log. For example, if two modules A and B exchange messages, this option will cause the window to display them as "A-->B" and "A<--B", as opposed to the default "A-->B" and "B-->A". This sometimes makes the log easier to follow.
-
Added support for new columns in the packet log view: TxUpdate, Durations, Length, Info. This was implemented in the cDefaultMessagePrinter
class which is part of the simulation library. This change makes it possible to see if a packet is a transmission update (except if the simulation installs its own packet printer like INET does).
-
In the messages view, simulation time is now formatted with digit grouping on.
-
In the log, the banners of component init stages that do not print anything are now suppressed.
-
Added the "Fira Code" font as embedded resource, and set it to be used by default for the log window. The reason is that it provides nice "-->" arrow ligatures in the Messages view.
-
Prevent manually enabled "Debug on Errors" setting from being turned off by (lack of) configuration option.
-
Fix osgEarth viewpoints ignoring SRS (PR #851).
-
Countless small improvements and bug fixes.
-
Raised the minimum required Qt version to 5.9.
Tkenv:
- Tkenv has been removed. Use Qtenv for all simulations.
Tools:
-
The names of all command-line tools now begin with opp_
.
-
Added opp_ide
, an alternative to the omnetpp
command that launches the Simulation IDE.
-
Added opp_neddoc
, a tool that makes it possible to generate HTML documentation from NED files from the command line. opp_neddoc
works by launching the IDE in headless mode.
-
opp_nedtool
was rewritten for convenience and features. The main points are the following:
- Removed msgc-related functionality, now it is really just about NED.
- Command-line interface redesigned for better usability (subcommands, better help, etc.)
- Added support for generating C++ source (
cpp
subcommand), for embedding NED files into an executable or library.
- The tool now accepts directories as command-line arguments, too, and processes all NED files in them.
- More convenient output (no
*_n.ned
, *_n.xml
).
- Removed obsolete
@listfile
and @@listfile
support.
- Fixed bugs in splitting NED files to one NED type per file.
-
opp_msgtool
was rewritten in the style of opp_nedtool
. Details:
- Made
--msg6
the default mode, --msg4
was removed.
- The command-line interface now uses subcommands; if no subcommand is specified, the default action is C++ code generation. The rarely useful
-T
(type of next file) and -h
(here) options have been removed.
- Better help. A
builtindefs
help page has also been added, which prints the built-in declarations.
-
opp_scavetool
had several improvements. A brief summary:
- The tool now accepts directories as command-line arguments, too, and recursively loads scalar and vector files from them.
- Command-line arguments may now contain double asterisk wildcards (
**
) in addition to normal wildcards (*
,?
). Double asterisks can match any number of directory levels. Example: results/**.vec
matches all .vec
files anywhere under the results/
directory. (When specifying wildcard arguments on the command line, be sure to quote them so that the shell does not expand them before opp_scavetool
gets invoked.)
- Added options to limit vector data by simulation time:
--start-time <time>
, --end-time <time>
.
- Accepts exporter options in the
--<key>=<value>
notation as well, not only with -x
.
- In filter expressions, run attributes now have to be referred to with the
runattr:
prefix. The attr:
prefix now only matches result attributes.
- In exporters, the way of representing histograms in the output has slightly changed: underflow/overflow values are now saved separately instead of as underflow/overflow "bins". Thus, there are now one more bin edges than bin values.
- The possibility to apply vector operations to vector results was removed from
opp_scavetool
and exporters. The recommended way of processing output vectors is with Python and NumPy.
- The
help
subcommand was refined.
-
Added opp_charttool
, a tool for "running" ANF files on the command line, e.g. for image or data export. Filtering options (-i
, -n
) allow multiple charts to be selected for exporting. The templates
subcommand lists the available chart templates.
-
opp_featuretool
: Extensive refactoring as well as refinement of its operation and command-line options. In general, the tool has become more forgiving: a missing .featurestates
file or extra/missing entries in it no longer causes an error or warning. Missing file and file entries are initialized with the default enablement state; extra entries are preserved (in the hope they'll be useful, e.g. after switching to a different topic branch). The content of the .nedexclusions
file is now also automatically adjusted without stopping with an error. User-visible changes are the following:
- Removed the
validate
and repair
subcommands (all commands implicitly validate and repair now).
- Better validation of the
.oppfeatures
file: Detect and report duplicate feature IDs and unresolved feature dependencies.
- Check for the existence of the C++ source root and NED folders.
- Preserve unknown features in the
.featurestate
file instead of fail/warn about them. Reason: they often occur when switching between branches.
isenabled -v
prints list of disabled features to stdout, not to stderr
- Complain less about fixable problems.
- Non-verbose operation by default.
- Improved error/warning messages.
-
opp_makemake
: The makefrag
file is now included instead of copied into the generated makefile. Also, a help
target has been added to the generated makefiles: typing make help
now prints the list of accepted targets (all
, clean
, etc.) and user-settable makefile variables (MODE
, V
, CFLAGS
, etc.), complete with helpful descriptions and usage examples.
-
opp_test
: The set of possible test outcomes has been refined. Possible outcomes are now PASS
, FAIL
, ERROR
, SKIP
and EXPECTEDFAIL
. SKIP
means that the test was not performed, because e.g. it would test an optional feature which is currently disabled; ERROR
means that the test was not performed because of an unrecoverable error (i.e. crash or exception). The diagnostic output for failed tests is now a colorized diff instead of a simple printout of the expected and the actual contents. It is possible to designate a test case as an "expected failure", by specifying %expected-failure: <reason>
in the test file. This is useful if we know that a certain test case is correct, but it is not possible to fix it for some reason.
IDE / Analysis Tool:
-
The Analysis Tool in the IDE has been rewritten, using a new approach. The number one goals were to allow ARBITRARY computations to be performed on the data, VISUALIZE the result in the most appropriate form chosen from a multitude of chart/plot types, and produce PUBLICATION QUALITY output. Additional goals were an intuitive user interface that makes straightforward tasks easy and convenient, scalability that allows the processing of a large amount of simulation results inside the IDE, and facilities to make (most of) the UI's functionality available on the command line as well.
The key technologies the new Analysis Tool employs are Python, NumPy, Pandas, and Matplotlib. The use of Python and Pandas gives access to advanced data manipulation and analysis capabilities, while Matplotlib offers dozens of plot types out of the box, endless customizations, and proven high-quality output. A large effort was made to properly integrate these technologies into the IDE, so that using the Analysis Tool provides a superior user experience, and brings the power of Python close to users without necessarily requiring them to write code in Python.
Common charting tasks are accessible with a few mouse clicks, via predefined Chart Templates that can be configured using dialogs. The heart of all Chart Templates is Python code that performs all of the computation and plotting. The Python code behind a chart can be viewed and freely edited using an integrated language-aware editor. Matplotlib plots appear inside the Analysis Tool's UI, and they are live (i.e. not just images): zooming, panning, and interacting with possible embedded controls in the plot all work seamlessly. IDE-native plots can also be chosen as an alternative to Matplotlib, as they provide increased scalability at the cost of being less flexible and featureful.
Special attention was paid to scalability. The UI is now easily capable of dealing with at least several tens of thousands of result files, and several million result items.
The OMNeT++ Python API for querying, transforming and plotting simulation results is available in the form of Python packages for use in Python scripts outside the IDE as well. There is also a command-line tool (opp_charttool
) that can "run" Analysis (anf) files e.g. for image export. opp_charttool
can be integrated e.g. into the build process of a paper written in LaTeX.
The documentation of the Analysis Tool's user interface can be found in the User Guide. A reference of the Python API has a dedicated Appendix in the Simulation Manual, while the "Result Recording and Analysis" chapter in the same Manual provides some practical guidance on how to use the API.
IDE / Sequence Chart Tool:
-
The visualization of events have been horizontally expanded on the chart, now it uses long rounded rectangles instead of small circles. This change allows the visualization of method calls without their arrows overlapping. If method calls are hidden then the chart falls back to the old behavior where events are small circles.
-
The set of displayed axes can be explicitly configured independently from the set of displayed events. The chart now also supports displaying events on a compound module axis if the corresponding submodule axis is hidden. Collapsing and expanding module axes can be done using the mouse.
-
The chart now also displays a set of axis headers on the left side that shows the module hierarchy in a compact and interactive way.
-
All parts of the sequence chart can be independently shown/hidden.
-
The selection has been extended with support for axes and method call arrows.
-
A new time measurement feature has been added that allows measuring the time difference between multiple selected events and other interesting points in time.
-
Several automatic configuration presets have been added (e.g. network level, full detail, default) to make the configuration for the most common use cases easier.
-
A new pattern-matching-based user-defined colorization (e.g. message sends, method calls, axes, events) feature has been added. This feature allows creating more easily understandable sequence charts by encoding certain model properties as colors.
-
The chart can display diagnostics information such as eventlog file statistics and operation statistics.
-
Added support for SVG export.
IDE / NED Documentation Generator:
-
The documentation generator now allows you to inject your own documentation fragments (possibly generated by 3rd-party tools) at various points in the documentation.
-
Modern look for the generated pages (Material design).
-
It is now possible to specify excluded directories during documentation generation, in order to be able to exclude samples, showcases etc. that are not integral part of the documentation.
-
Now generates nedtags.xml
and msgtags.xml
files which are compatible with the doxytags.xml
file that Doxygen generates. This allows crosslinking to the NED documentation from a Sphinx-based documentation, using the doxy-link plugin.
-
Generate usage and inheritance diagrams only if they are meaningful.
-
Use SVG files as the usage/inheritance diagram image. Removed map files as SVG already contains proper links.
-
Generate "Implementors" table for interfaces. The Implementors table includes indirect implementors as well.
-
Fix: Inheritance diagrams were missing in module interface pages, even if they had implementors. This bug made INET documentation much less useful.
-
The functionality of the documentation generator is now also available from the command line (opp_neddoc
).
IDE / Inifile Editor:
-
Added support for ignorable options. User can mark custom config options as ones to be ignored by the editor.
-
Config option values that contain expressions are no longer falsely flagged as errors.
-
The confusing "Unused entry (does not match any parameters)" warning that often appeared falsely for INET simulations due to deficiencies in analyzing the network structure has been re-worded to include the possibility that it is false, and has also been demoted from being "warning" to "info".
-
Eliminated the asynchronous/delayed form page reread in Form mode, which often caused editing glitches.
IDE Miscellaneous:
-
Install Simulation Models dialog: Added support for changing the project name and location on download.
-
Turned on showing the line numbers ruler in source editors by default.
-
Added an XML editor, Terminal (a view that contains a shell prompt), PyDev (Python editor), and the Eclipse Marketplace client to the IDE.
-
The simulation launcher now passes NED exclusions to the simulation program as -x
options. NED exclusions typically come from disabled project features, e.g. in INET.
-
Added SVG export capability to the NED Editor.
-
Updated to Eclipse 4.22, CDT 10.5 and PyDev 9.2.
-
The JRE is now provided by the Eclipse JustJ project, so the IDE no longer requires Java to be installed on the host OS.
-
Added support for ARM-based Linux distros.
C++ Debugging:
-
Better debugging experience by fine-tuning the compiler options, especially with the clang compiler.
-
Added LLDB pretty printers for various OMNeT++ types. They can be useful if you use LLDB-based external debuggers like XCode or VS Code. You should manually import them from the LLDB debugger console with the following command:
command script import <OMNETPP_ROOT>/python/omnetpp/lldb/formatters/omnetpp.py
-
Allow Qtenv's "Debug on Error" and "Debug Next Event" functionality to use the integrated debugger of the Simulation IDE. This required multiple changes. First, the IDE was extended to accept an URL which, when opened in the IDE, causes the integrated debugger to start a debug session and attach to a process given with its PID. This URL is:
omnetpp://cdt/debugger/attach?pid=<pid>
The URL can also be opened from the command line, by running the omnetpp
command with the URL as argument. The command opens the URL in the existing IDE instance if it is already running, or starts a new one if it does not.
The second change was to update the default value of the OMNeT++ debugger-attach-command
configuration option to use the above command. (Previously it has used various other debuggers which were likely to be found on the host OS: GDB, Nemiver, VS Code, etc.)
Hint: You can force Qtenv to use Visual Studio Code as your external debugger by setting the following environment variable:
export OMNETPP_DEBUGGER_COMMAND="code --open-url "vscode://vadimcn.vscode-lldb/launch/config?{request:'attach', pid:'%u'}""
Alternatively, you can specify the same value (code --open-url ...
) to the "debugger-attach-command" configuration option in omnetpp.ini
.
Result file format changes:
-
There were a number of changes in the format of result files (.sca and .vec files), so the file format version has been bumped from 2 to 3. (The file format is recorded at the top of each result file in a version
line.) The set of changes is relatively small; see details below.
-
Iteration variables are no longer saved as run attributes but in separate itervar
lines, in order to be able to tell them apart with certainty.
-
param
lines (which recorded parameter assignment entries in the configuration) have been replaced with the more general config
lines. config
lines record all configuration entries, not just parameter assignments.
-
In version 2, concrete parameter values (if requested) were recorded as scalars, whereas in version 3 they are recorded as a separate result item type, in par
lines. This allows the recording of volatile parameters (as expressions) and non-numeric values as well.
-
Component NED type names are now recorded, as typename
pseudo parameters.
-
The sum
and sqrsum
fields of weighted statistics are no longer recorded, as they are irrelevant.
SQLite result file format changes:
-
SQLite result files underwent a similar change in the database schema. Files in the old format are no longer understood. A brief summary of changes follows.
-
The runParam
table was renamed to runConfig
, and its columns were also similarly renamed: paramKey
, paramValue
and paramOrder
became configKey
, configValue
and configOrder
, respectively.
-
Iteration variables are in a new table called runItervar
, with columns runId
, itervarName
and itervarValue
.
-
Two new tables were added for representing the new result item types: parameter
(with the columns paramId
, runId
, moduleName
, paramName
and paramValue
), and paramAttr
(with the columns paramId
, attrName
and attrValue
). Note that paramValue
contains values in the syntax it would have to be written in a NED file or in omnetpp.ini
, i.e. string constants include the quotation marks.
Eventlog file format and configuration:
-
The eventlog file format has been changed substantially. You won't be able to open older eventlog files with this version of the IDE, nor new files in previous IDE versions.
-
The most prominent change is the introduction of snapshot and index chunks in addition to the already recorded event chunks. The former contains a complete snapshot of the relevant simulation state without referring to any other line in the file. The latter provides the set of changes in the relevant simulation state since the last index or snapshot chunk. The contents of the index chunk is expressed as references to other lines of the eventlog file. This change in the eventlog format provides the foundation for a better user experience in the IDE especially for large eventlog files.
-
Several new eventlog-recording-related configuration options have been added:
-
The eventlog-snapshot-frequency
configuration option specifies how often snapshots are recorded in the eventlog file. Snapshots help various tools to handle large eventlog files more efficiently. Specifying greater value means less help, while smaller value means bigger eventlog files.
-
The eventlog-index-frequency
configuration option specifies how often indices are recorder in the eventlog file. An index is much smaller than a full snapshot, but it only contains the differences since the last index. Specifying greater value means less help, while smaller value means bigger eventlog files.
-
The eventlog-max-size
configuration option specifies the maximum size of the eventlog file in bytes. The eventlog file is automatically truncated when this limit is reached.
-
The eventlog-min-truncated-size
configuration options specifies the minimum size of the eventlog file in bytes after the file is truncated. Truncation means older events are discarded while newer ones are kept.
-
The eventlog-options
configuration option allows for recording only certain categories (e.g. text, message, module, method call, display string), to reduce the eventlog file size.
Build environment:
-
If a file called setenv_local
is present in the installation root, it is automatically sourced from the setenv
script. setenv_local
can be used to set up user specific environment variables.
-
The content of the $PLATFORM
makefile variable has changed. Until now, it contained a <platform>.<architecture>
pair (e.g. win32.x86_64
) which was misleading. From now on, Makefile.inc
provides $PLATFORM
(e.g. win32
) and $ARCH
(e.g. x86_64
) as separate variables. makefrag
files must be updated if $PLATFORM
variable was used in them.
-
To build OMNeT++ with Akaroa support, WITH_AKAROA=yes
must be specified in the configure.user
file. The configuration script no longer tries to autodetect Akaroa without the user explicitly requesting it.
-
osgEarth support is now disabled by default. You must explicitly set WITH_OSGEARTH=yes
in the configure.user
file. Some Linux distibutions no longer include osgEarth so you may need to build it manually from sources.
-
Debug builds are now compiled with -O0 for maximum debuggability. Release builds are compiled with -O2 -ffp-contract=off
to disable fused multiply-add operations. This ensures that floating point operations will generate exactly the same results in DEBUG and RELEASE mode and their accuracy would not depend on unpredictable optimizations.
Windows Support:
-
On Windows, the toolchain (compiler, libraries, etc.) can now be found in tools/win32.x86_64
.
-
Setting of environment variables has been moved into the setenv
script. It is automatically sourced when mingwenv.cmd
or vcenv.cmd
is started.
-
On Windows, libraries and other dependencies used by simulations, such as Qt, OSG, osgEarth, etc., are now separated from the rest of the toolchain binaries (compiler, etc.). You can find them in the opt
subdirectory of the tools/win32.x86_64
folder.
-
On Windows, when creating a shared library, the build system now generates a proper import library and also a module definition file (<targetname>.dll.a
, <targetname>.def
). External projects must link against that library instead of linking directly with the <targetname>.dll
file. (Note that the linker automatically uses the .dll.a
files if they are present in the library path and falls back to use the pure .dll
file only if the import library is not present. It means that you don't have to do anything extra to use these files apart from making them available along your .dll
files.)
-
The Windows toolchain now contains the (much faster) LLD linker. LLD is also used on other platforms instead of the GNU linker, if available. For large projects, LLD is dramatically faster than the standard GNU linker. In one instance, the use of LLD, together with other changes that were partly done in INET, reduced INET linking time on Windows from 380s to 2s in DEBUG mode, and from 90s to 5s in RELEASE mode on one of our dev boxes.
macOS support:
-
On macOS, the toolchain (compiler, libraries, etc.) can now be found in tools/macos.x86_64
.
-
Rudimentary support for Apple silicon: source setenv
now automatically launches a (nested) x86_64 emulation shell on ARM-based Macs.
Sample simulations:
-
Added "openstreetmap", an example simulation that displays a city map, with some animated car traffic on it. Map data come from an OSM file exported from openstreetmap.org.
-
Added "petrinets", an example simulation demonstrating how to implement stochastic Petri nets, a well-known formalism for the description of distributed systems.
-
Added the "wiredphy" sample simulation to demonstrate transmission updates.
-
The "fifo" example simulation was extended with a TandemQueues network and related configurations in omnetpp.ini.
-
The "resultfiles" folder project now contains scalar and vector result files from the Fifo1, Fifo2, and the new TandemQueues simulations.
Documentation:
-
Simulation Manual has been updated. The largest changes were in the "Message Descriptions" and "Result Analysis" sections (which were practically rewritten). There are also two new appendices: "Python API for Chart Scripts", and "Message Class/Field Properties".
-
User Guide: The chapter about the Analysis Tool ("Result Analysis") has been rewritten.
-
Install Guide has been updated. New sections in the macOS chapter: "Enabling Development Mode in the Terminal", "Running OMNeT++ on Apple Silicon". We also added instructions on installing OMNeT++ on WSL (Windows Subsystem for Linux) on Windows 10, which is important because we found that running OMNeT++ on WSL is considerably faster than using it with the MinGW toolchain.
-
Converted all of our structured documents (User Guide, Install Guide, etc.) from their original source format (DocBook or AsciiDoc) to reStructuredText, except for the Simulation Manual which remains in LaTeX.
OMNeT++ 6.0 is the result of more than three years of work, and includes many essential new features that we would already have a hard time without. The present changelog summarizes all changes made during the 15+ pre-releases.
We briefly summarize the changes below in each part of OMNeT++ before going into the details.
The most prominent new feature is the new Python-based Analysis Tool in the IDE. The use of Python under the hood allows for arbitrarily complex computations to be performed on the data, visualizing the result in the most appropriate form chosen from a multitude of plot types, and producing publication quality output, all while using an intuitive user interface that makes straightforward tasks easy and convenient. Custom computations and custom plots are also easily accessible. The tool is able to handle large quantities of data. The Python APIs are also available outside the IDE (e.g. for standalone scripts), and a command-line tool for viewing and exporting charts created in the IDE also exists (
opp_charttool
).The NED language now supports parameters that carry C++ objects as values (type
object
), which can be used to parameterize modules with structured data (e.g. nontrivial configuration), packet prototypes, function objects, etc. Structured data may come from NED functions likereadCSV()
orreadJSON()
which parse data files, or may be specified directly in NED or ini files using JSON syntax. The syntax of ini files has even been adjusted to make it more convenient to write multi-line JSON values in it. Further new functionality includes the string match operator=~
, the "spaceship" operator<=>
, and support for Universal Function Call Syntax (UFCS). Incompatible changes include the change in the interpretation of parameter names that are not qualified with thethis
orparent
keywords, and the necessity to mark module parameters with@mutable
that are allowed to be set at runtime. Embedding NED files into simulation binaries for easier dissemination has also become possible.Message descriptions (msg files) have undergone even bigger changes. An import system has been added to make the content of a msg file available in others. The generated code and class descriptors can now be widely customized via properties. Targeted C++ blocks have been introduced for injecting C++ code into various places in the generated source files. Altogether, these (and further, smaller) features facilitate writing significantly cleaner msg files, especially in large projects like INET.
The format of ini files have been made more flexible: the
Config
word in section headers is now optional, and long lines can be broken up to multiple lines without using trailing backslashes (just indent the continuation lines).In the simulation kernel, the most important change is the introduction of the Transmission Updates API, which allows in-progress packet (frame) transmissions to be modified, i.e. aborted, shortened, or extended. This API is necessary for implementing L2 features like frame preemption or on-the-fly frame aggregation. Other changes include the addition of utility APIs like
scheduleAfter()
,rescheduleAt()
andrescheduleAfter()
, refinements around module deletion and the introduction of thepreDelete()
virtual member function, refinements in the signals and listeners APIs, improved expression evaluation support, and the addition of string-handling utility functions, just to name a few.Regarding statistics recording, perhaps the most significant addition is the
demux
filter, which allows splitting a single stream (of emitted values) to multiple streams. The filter makes it possible to record statistics subdivided by some criteria, e.g. to record statistics per TCP connection, per remote IP address, per traffic class, etc., in INET. Further improvements include the addition of thewarmup
filter and theautoWarmupFilter
statistic attribute that allow computed statistics to be calculated correctly also in the presence of a nonzero warm-up period. Result files now hold more metadata: parameter values and configuration entries are now also (optionally) recorded. This change, together with other, smaller adjustments, cause new result files not be understood by previous versions of OMNeT++.A significant amount of work has been put into improving the looks and functionality of Qtenv: material-style icons, HIDPI support, dark theme support, and countless small features that improve usability, especially around the Object Inspector and the Log View. For example, it is now possible to set the Messages view of the Log to display all timestamps as a delta to a user-specified reference timestamp; or, the Object Inspector now allows selecting a different display mode for a tree node. One important change is that method call animations are now disabled by default.
The Sequence Chart tool in the IDE has been significantly improved, both visually and functionally, with the goal of allowing the user to configure the chart in a way that facilitates understanding of the sequence of events in the simulation. The tools provided for that purpose are the possibility to hide unnecessary elements (unrelated arrows, events, etc), support for user-defined coloring, interactively collapsible compound module axes, horizontally expanded events so that the arrows of nested method calls do not overlap, and more. The eventlog file format has also changed in a non-backward-compatible way, due to the addition of extra elements that allow the Sequence Chart tool to be faster and more scalable.
Generating documentation from NED and MSG files has been made possible from the command line as well, using the new
opp_neddoc
tool. Functionality has been extended with the possibility of incorporating external information into the generated pages.The C++ debugging experience has been made more pleasant in several ways. For example, the "Debug on Error" and "Debug Next Event" functionality in Qtenv may now invoke the integrated debugger of the Simulation IDE, which is especially useful when the simulation was launched from the IDE. The User Guide also contains a hint on how to configure simulations to invoke VS Code as debugger.
Due to improvements in the toolchain and the build process, Windows users may see the linking time of large models like INET Framework to drop dramatically (1-2 orders magnitude, e.g. from several minutes to several seconds). On macOS, Apple Silicon, is currently supported with x86-64 emulation.
Now, the details:
NED:
Semantics change: Within a submodule's or connection's curly brace block, the interpretation of parameter, gate, and submodule references that don't use an explicit
parent
orthis
qualifier has changed. They no longer refer to the enclosing compound module's item, but to the item of (or within) the local submodule or channel object. The interpretation of item references outside subcomponent blocks has remained unchanged. An example:The set of forms accepted by
exists()
andsizeof()
has been expanded. Notably,exists()
can now be used to check the existence of an item in a submodule vector (as submodule vectors may now contain holes, due to@omittedTypename
). Also, theindex()
syntax has been removed,index
is only accepted without parens.Note that referencing a submodule's submodule from NED (i.e. the
a.b
orthis.a.b
syntax within a submodule block) is generally wrong, because the network is built top-down, and submodules are only created after parameters have already been set up. (An exception is using it in the values ofvolatile
parameters, because they are evaluated later.)Error messages have been revised and expanded to be more helpful and facilitate porting NED code from 5.x.
To write NED which is compatible with both OMNeT++ version 5.x and 6.0, qualify all references within subcomponent blocks with explicit
parent
orthis
, and require OMNeT++ 5.7 which is the first and only 5.x version that understands theparent
keyword.NED grammar: Added
object
as parameter type. Parameters of this type may hold objects subclassed fromcOwnedObject
that they can take ownership of.NED parameters of type
object
may have a@class()
property, with the syntax@class(classname)
or@class(classname?)
. The property specifies that the parameter should only accept objects of the given type and its subclasses. The referenced class must be registered viaRegister_Class()
orRegister_Abstract_Class()
. Parameters declared without the question mark in@class()
don't acceptnullptr
as value, while the ones with question mark do.The NED expression syntax has been extended to accept JSON-style constructs, i.e. arrays and dictionaries (termed "object" in JSON), and the
nullptr
keyword. The array syntax is a list of values enclosed in square brackets, for example[1, 2, 3]
, and the array is accessible as acValueArray
object in C++. The dictionary syntax uses curly braces:{"foo" : 1, "bar" : 2 }
, and dictionaries are presented ascValueMap
objects. If a dictionary is prefixed by a name, then the name is interpreted as a class name, and values are interpreted as fields of the object:cMessage { name: "hello", kind: 1}
.Object parameters allow simple values (int, double, bool, string) as well. C++-wise, they are stored in the parameter in
cValueHolder
-wrappedcValue
objects.New NED functions have been introduced:
get()
(return an element of an array or dictionary),size()
(returns the size of an array or dictionary),eval()
(evaluates a NED expression given as string),dup()
(clones an object).dup()
simply calls an object's C++dup()
method; it is useful because module parameters of typeobject
only accept objects they fully own, which can be worked around usingdup()
. An example:object a = [1,2,3];
object b = dup(a); // without dup() it is an error: value is owned by parameter 'a'
As
dup()
invoked on containers only duplicates the objects owned by the container, you may need extradup()
call when referring to objects owned by other parameters. Example:NED grammar: Made operator precedence more similar to C/C++. Relational operators (
==, !=, <, <=, >, >=
) used to be on the same precedence level; now==
and!=
have lower precedence than the rest.NED grammar: Added the
=~
(match) and<=>
(comparison, a.k.a. "spaceship") operators, theundefined
keyword, andbool()
as conversion function.String constants are now accepted with apostrophes too. This makes it possible to write quotation marks in strings without the need to escape them.
For quantities (numbers with measurement units), the rules have changed slightly. When specifying quantities with multiple terms, a minus sign is only accepted at the front, to reduce the chance of confusion in arithmetic expressions. I.e.
-5s100ms
is valid as a quantity string (and means -5.1s), but5s-100ms
is no longer.Also, the plain "0" constant is no longer accepted at places where a quantity with a measurement unit is expected. Reason: it was confusing when the expected unit was dB or dBm. E.g. in
omnetpp.ini
, should**.power = 0
be interpreted as 0W or 0dBm?Added support for Universal Function Call Syntax (UFCS) to NED, which means that now any function call may also be written as if the function was a method of its first argument (provided it has one). That is,
f(x,..)
can now be also written in the alternative formx.f(...)
. This results in improved readability in certain cases, and allows chaining function calls.xmldoc()
(and other file-reading functions) now interpret the file name as relative to the directory the expression comes from. Whenxmldoc()
occurs in an included ini file, the file name is now interpreted as relative to the directory containing the included ini file (as opposed to being relative to the main ini file or the working directory.) Ifxmldoc()
occurs in a NED file, the file name is relative to the directory where that NED file was loaded from.NED functions for reading (from file) and parsing (from string) of CSV, JSON and XML files:
parseCSV()
,readCSV()
,parseExtendedCSV()
,readExtendedCSV()
,parseJSON()
,readJSON()
,parseExtendedJSON()
,readExtendedJSON()
,parseXML()
,readXML()
. The "extended" variants support expressions in the file, which will be evaluated during parsing. The XML functions are aliases to the existingxml()
/xmldoc()
functions. Bonus file-related functions:readFile()
,workingDir()
,baseDir()
,resolveFile()
,absFilePath()
.The body of a parametric submodule now allows assigning apparently nonexistent parameters. For example, in the example below, the
sleepTime
assignment does not cause an error ifFooApp
has asleepTime
parameter butIApp
does not:Implemented
@omittedTypename
property.@omittedTypename
allows one to specify a NED type to use whentypename=""
is specified for a parametric submodule or channel.@omittedTypename
can be specified on a module interface or channel interface, or on a submodule or connection. It should contain a single (optional) value. The value names the type to use. If it is absent, the submodule or channel will not be created. (The connection will be created without a channel object.)The
@mutable
property was introduced for parameters. If the module (or channel) is prepared for a parameter to change its value at runtime (i.e. the new value takes effect), then it should be marked with@mutable
. If@mutable
is missing, then trying to change the parameter will now result in a runtime error ("Cannot change non-mutable parameter".)The motivation is that in a complex model framework, there is usually a large number of (module or channel) parameters, and so far it has not been obvious for users which parameters can be meaningfully changed at runtime. For example, if a simple module did not implement
handleParameterChange()
or thehandleParameterChange()
method did not handle a particular parameter, then the user could technically change that NED parameter at runtime, but the change did not take effect. This has often caused confusion.Parameters of
ned.DelayChannel
andned.DatarateChannel
are now marked@mutable
.To allow running existing simulation models that have not yet been updated with
@mutable
annotations, we have added theparameter-mutability-check
configuration option. Settingparameter-mutability-check=false
will give back the old behavior (not raising an error).Added the
expr()
operator to NED, with the purpose of allowing models to accept formulas or expressions which it could use e.g. to determine the processing time of a packet based on packet length or other properties, decide whether a packet should be allowed to pass or should be filtered out based on its contents (filter condition), or to derive x and y coordinates of a mobile node in the function of time.The argument to
expr()
is a NED expression which will typically contain free variables, (like x and y inexpr(x+y)
). Theexpr()
operator creates an object that encapsulates the expression, so it can be assigned to parameters of the typeobject
. On the C++ side, the module implementation should query the parameter to get at the expression object (of typecOwnedDynamicExpression
), and then it may bind the free variables and evaluate the expression as often as it wishes.In
xml()
andxmldoc()
element selectors,$MODULE_INDEX
,$PARENTMODULE_NAME
and similar variables now evaluate to the empty string if they are not applicable, instead of raising an error that was often problematic.Improved error reporting during network building: when an error occurs during assigning a parameter from a NED file, the error message now includes the location of the assignment (file:line in NED file).
MSG:
Made the hitherto experimental operation mode and feature set of the message compiler official. This feature set was originally added around OMNeT++ 5.3, and could be enabled by passing the
--msg6
option toopp_msgtool
. There was also a no-op--msg4
option that selected the old (OMNeT++ 4.x compatible) operation. Most of the OMNeT++ 6.0 pre-releases shipped with the new operation mode being the default (i.e.--msg6
became a no-op), with features continually being added and refined. Then, finally, the old code and the--msg4
option were removed altogether.The new operation mode represents a complete overhaul of the message compiler, with significant non-backward-compatible changes to the MSG language. These features were largely motivated by the needs of INET 4.
The message compiler is now aware of the OMNeT++ library classes, as if they were imported by default. Declarations come from
sim_std.msg
.Added import support. A message file can now reference definitions in other message files using the
import
keyword. Type announcements are no longer needed (in fact, they are ignored with a warning), and there is now much less need forcplusplus
blocks as well.Classes without an
extends
clause no longer havecObject
as their default base class. IfcObject
should be the base class,extends cObject
needs to be added explicitly.Field getters now return
const
reference. Separateget..ForUpdate()
getters that return non-const
are generated to cover uses cases when the contained value (typically an object) needs to be modified in-place.Added targeted
cplusplus
blocks, with the syntax ofcplusplus(<target>) {{..}}
. The target can beh
(the generated header file -- the default),cc
(the generated C++ file),<classname>
(content is inserted into the declaration of the type, just before the closing curly bracket), or<classname>::<methodname>
(content is inserted into the body of the specified method). For the last one, supported methods include the constructor, copy constructor (useFoo&
as name), destructor,operator=
,copy()
,parsimPack()
,parsimUnpack()
, etc., and the per-field generated methods (setter, getter, etc.).Enum names can now be used as field type name, i.e.
int foo @enum(Foo)
can now be also written asFoo foo
.Support for
const
fields (no setter generated/expected).Support for pointer and owned pointer fields. Owned pointers are denoted with the
@owned
field property. Non-owned pointers are simply stored and returned; owned pointers imply delete-in-destructor and clone-on-dup behavior. Owned pointer fields have a remover method generated for them (removeFoo()
for afoo
field, orremoveFoo(index)
if thefoo
field is an array). The remover method removes and returns the object in the field or array element, and replaces it with anullptr
. Additionally, if the object is acOwnedObject
,take()
anddrop()
calls are also generated into the bodies of the appropriate methods. There is also an@allowReplace
property that controls whether the setter method of an owned pointer field is allowed to delete the previously set object; the default is@allowReplace(false)
.More convenient dynamic arrays: inserter, appender and eraser methods are now generated into the class. For example
insertFoo(index,value)
,appendFoo(value)
, anderaseFoo(index)
are generated for afoo[]
field.Support for pass-by-value for fields. Annotate the field with
@byValue
for that.@byValue
and many other properties can also be specified on the class, and they are inherited by fields that instantiate that type.Additional C++ base classes may be specified with the
@implements
property.The
@str
property causes anstr()
method to be generated; the expression to be returned from the method should be given in the value of the property.The
@clone
property specifies code to duplicate (one array element of) the field value.The
@beforeChange
class property specifies the name of a method to be called from all generated methods that mutate the object, e.g. from setters. It allows implementing objects that become immutable ("frozen") after an initial setup phase.The
@custom
field property causes the field to only appear in descriptors, but no code is generated for it at all. One can inject the code that implements the field (data member, getter, setter, etc.) via targetedcplusplus
blocks.The
@customImpl
field property, suppresses generating implementations for the field's accessor methods, allowing custom implementations to be supplied by the user.Added the
@abstract
field and class property. For a field, it is equivalent to theabstract
keyword; for classes, it marks the whole class as abstract.Abstract fields no longer require the class to be marked with
@customize
.Message files now allow more than one
namespace <namespace>;
directive. Thenamespace;
syntax should be used to return to the toplevel C++ namespace.The names of generated method can be overridden with the following field properties:
@setter
,@getter
,@getterForUpdate
,@sizeSetter
,@sizeGetter
,@inserter
,@eraser
,@appender
,@remover
, etc.Data types can be overridden with the following properties:
@cppType
,@datamemberType
,@argType
,@returnType
,@sizeType
.Changed C++ type for array sizes and indices, i.e. the default of
@sizeType
, fromint
tosize_t
.Added support for setting pointer members and array sizes via class descriptors. (
cClassDescriptor
had no facility for that.) This involves adding two methods tocClassDescriptor
(setFieldArraySize()
andsetFieldStructValuePointer()
), and support for the@resizable()
and@replaceable
field attributes that tell the message compiler to generate the respective code in the class.The
@toString
and@fromString
properties specify a method name or code fragment to convert the field's value to/from string form in class descriptors (getFieldValueAsString()
andsetFieldValueFromString()
methods ofcClassDescriptor
). In the absence of@toString
, previous versions converted the value to string by writing it to a stream usingoperator<<
; now thestr()
method of the object is used if it has one. If neither@toString
norstr()
exist, an empty string is returned.Likewise, the
@toValue
and@fromValue
properties specify a method name or code fragment to convert the field's value to/fromcValue
form in class descriptors ((getFieldValue()
andsetFieldValue()
methods ofcClassDescriptor
)).Better code for generated classes, e.g. inline field initializers, and use of the
=delete
syntax of C++11 in the generated code.Better code generated for descriptors, e.g. symbolic constants for field indices.
The list of reserved words (words that cannot be used as identifiers in MSG files; it is the union of the words reserved by C++ and by the MSG language) has been updated.
A complete list of supported properties (not all of them are explicitly listed above) can be found in an Appendix of the Simulation Manual.
Ini files:
It is now possible to break long lines without using a trailing backslash. Continuation lines are marked as such by indenting them, i.e. an indented line is now interpreted as a continuation of the previous line. (It is not possible to break a line inside a string constant that way.) Breaking lines using a trailing backslash way still works (and it can also be used to break string constants, too). Indentation-based line continuation has the advantage over backslashes that it allows placing comments on intermediate lines (whereas with backslashes, the first
#
makes the rest of the lines also part of the comment).The
Config
prefix in section headers is now optional, that is, the heading[Config PureAloha]
may now be also written as[PureAloha]
, with the two being equivalent.Simulation kernel / Modules, channels, programming model:
Added the
scheduleAfter()
,rescheduleAt()
,rescheduleAfter()
methods tocSimpleModule
. They are mainly for convenience, but usingrescheduleAt()
instead ofcancelEvent()
+scheduleAt()
will eventually allow for a more efficient implementation.Change in the parameter change notification mechanism: Calls to the
handleParameterChange()
method during initialization are no longer suppressed. Because now every change results in a notification, the umbrellahandleParameter(nullptr)
call at the end of the initialization is no longer needed and has been removed. The consequence is thathandleParameterChange()
methods need to be implemented more carefully, because they may be called at a time when the module may not have completed all initialization stages. Also, if an existing model relied onhandleParameter(nullptr)
being called, it needs to be updated.Improvements in the multi-stage initialization protocol with regard to dynamic module creation. Modules now keep track of the last init stage they completed (
lastCompletedInitStage
). During an init stage, initialization of modules is restarted if creation/deletion is detected during iteration; modules already initialized in the previous round are recognized and skipped with the help oflastCompletedInitStage
.cModule
now keeps track of submodule vectors as entities, and not just as a collection of submodules with vector indices, meaning that we can now distinguish between nonexistent and zero-size submodule vectors. Random access of vector elements has also became more efficient (constant-time operation). Several new methods have been added as part of this change:hasSubmoduleVector()
,getSubmoduleVectorSize()
,addSubmoduleVector()
,deleteSubmoduleVector()
,setSubmoduleVectorSize()
,getSubmoduleVectorNames()
.As part of the above change, several
cModule
andcModuleType
methods have been added or updated. A partial list:cModule
, thehasSubmodule()
,getSubmoduleNames()
,hasGateVector()
,hasGates()
methods have been added for consistency between submodule and gate APIs.getGateNames()
method has been changed fromstd::string<const char*>
tostd::vector<std::string>
, for consistency withgetSubmoduleNames()
.cModule
: addedsetIndex()
andsetNameAndIndex()
.cModule
,cGate
:getIndex()
,getVectorSize()
,gateSize()
and similar methods now throw exception for non-vector submodules/gates.cModule
: add separateaddGateVector()
method instead misusingaddGate()
for creating gate vectors, also for consistency withaddSubmoduleVector()
.cModuleType::create()
, thevectorSize
parameter ofcreate()
has been removed.cModuleType::createScheduleInit()
, an index argument was added to allow creating submodule vector elements.cModule
: addedaddSubmodule()
method which flows more naturally thancModuleType::create()
.There have been changes in submodule and channel iterators.
SubmoduleIterator
has been rewritten due to the change in how submodule vectors are represented, which may affect the iteration order in some cases. Iterators now throw an exception if a change occurs in the list of submodules/channels during iteration. Their APIs have also changed a little:operator--
was removed, andinit(m)
was renamed toreset()
.Optimized
cModule::ChannelIterator
by lettingcModule
maintain a linked list of channels (cChannel
), so thatChannelIterator
doesn't have to search through the whole compound module to find them.Module name and full name (i.e. "name[index]") are now stringpooled, which reduces memory usage in exchange for a small build-time extra cost. In addition, string pools now use
std::unordered_map
instead ofstd::map
, which results in improved performance.cComponent
: addedgetNedTypeAndFullName()
andgetNedTypeAndFullPath()
. They are especially useful in constructing error messages in NED functions.Simulation kernel / Signals and notifications:
intpar_t
was renamed tointval_t
, anduintval_t
was added. Both are guaranteed to be at least 64 bits wide.Signal listeners changed to use
intval_t
anduintval_t
instead oflong
andunsigned long
. This change was necessary becauselong
is only 32 bits wide on Windows. This affects methods ofcListener
and subclasses likecResultFilter
andcResultRecorder
.Emitting
nullptr
as a string (const char*
overload ofemit()
) is disallowed. The reason is thatnullptr
cannot be represented instd::string
, which causes problems e.g. in result filters and recorders.Added two new model change notifications:
cPostModuleBuildNotification
,cPostComponentInitializeNotification
.Minor changes in some model change notification classes. In
cPreModuleAddNotification
, thevectorSize
field was removed (as it was redundant), and incPostModuleDeleteNotification
, the interpretation of the index field has changed a little: if the deleted module was not part of a module vector, index is now set to -1 instead of 0.Simulation kernel / Utilities:
Two utility functions were added to
cObject
:getClassAndFullPath()
andgetClassAndFullName()
. They are mostly useful in logging and error messages.cMatchExpression
: Thefield =~ pattern
syntax replacesfield(pattern)
. Also removed the implicit OR syntax. The old syntaxes looked confusing, and made it difficult to tell apart the concise notation from expression-style notation.Added
opp_component_ptr<T>
. It implements a smart pointer that points to acComponent
(i.e. a module or channel), and automatically becomesnullptr
when the referenced object is deleted. It is a non-owning ("weak") pointer, i.e. the pointer going out of scope has no effect on the referenced object.opp_component_ptr<T>
can be useful in implementing modules that hold pointers to other modules and want to be prepared for those modules getting deleted. It can also be useful for simplifying safe destruction of compound modules containing such modules.New classes:
opp_pooledstring
,opp_staticpooledstring
. They provide pool- backed string storage (reference-counted and non-reference-counted, respectively). In turn, thecStringPool
class was removed; use either of the pooled string classes or oropp_staticpooledstring::get(const char *)
instead.Several string functions have been made available for models. A representative partial list:
opp_isempty()
,opp_isblank()
,opp_nulltoempty()
,opp_trim()
,opp_split()
,opp_splitandtrim()
,opp_join()
,opp_stringendswith()
,opp_substringbefore()
, etc.The
cStringTokenizer
class has been rewritten. It now supports features like optional skipping of empty tokens, optional trimming of tokens, optional honoring of quotes, optional honoring of parens/braces/brackets (i.e. the input string is not broken into tokens in the middle of a parenthesized expression).Simulation kernel / Visualization support:
Added display name support to modules. Display name is a string that optionally appears in Qtenv next to (or instead of) the normal module name, in order to help the user distinguish between similarly-named submodules. For example, application-layer modules
app[0]
,app[1]
, etc. in INET may be given descriptive names like "file transfer", "video", "voice", or "CBR", and have them displayed in Qtenv. Display names may be set using thedisplay-name
per-module configuration option, or programmatically by callingsetDisplayName()
.Added the
g=<group>
(layout group) display string tag, which makes it possible to apply predefined arrangements like row, column, matrix or ring to a group of unrelated submodules. This layouting feature was previously only available for submodule vectors. When "g" tags are used, submodules in the same group are now regarded for layouting purposes as if they were part of the same submodule vector.Made it possible to specify display strings in the configuration. The value given in the
display-string
per-component configuration option is merged into the component's display string in the same way inheritance or submodule display strings work: it may add, overwrite or remove items from it.Added text alignment support to text and label figures:
cFigure::Alignment
enum,getAlignment()
/setAlignment()
incAbstractTextFigure
.Added the
toAlpha()
method and a constructor takingColor
tocFigure::RGBA
.Simulation kernel / Transmission updates:
The initial
send()
is interpreted as: "packet transmission begins now, packet content and duration are, as things are now, going to be this".Following that, an "update" (or any number of updates) can be sent. An update is a packet with the updated ("actual") content, and with a "remaining transmission duration" attached. Updates may only be sent while transmission is still ongoing.
As an example, aborting a transmission is done by sending a packet with a truncated content and a remaining duration of zero.
Transmission updates are paired with the original packet they modify using a transmissionId. The transmissionId is normally chosen to be the packet ID of the original transmission. Channels should understand updates and handle them accordingly.
Receivers that receive the packet at the end of the reception, which is the default operating mode, will only receive the final update. The original packet and intermediate updates are absorbed by the simulation kernel.
Receivers that receive the packet at the start of the reception (see
cGate::setDeliverImmediately()
, previously calledsetDeliverOnReceptionStart()
) should be prepared to receive all of the original packet and the updates, and handle them appropriately. Tx updates can be recognized fromcPacket::isUpdate()
returningtrue
.cPacket::getRemainingDuration()
returns the remaining transmission duration, andcPacket::getDuration()
the total transmission duration.As a safeguard against unprepared modules accidentally processing tx updates as normal full-blown packets, the module is only given tx updates if it explicitly declares that it is able to handle them properly. The latter is done by the module calling
setTxUpdateSupport(true)
before receiving packets, e.g. ininitialize()
.Non-transmission channels treat tx updates in the same way as they treat any other messages and packets (they ignore the
cPacket::isUpdate()
flag).Details and related changes follow.
send()
andsendDirect()
now accept aSendOptions
struct where optional parameters such as delay can be passed in.sendDelayed()
and othersend()
/sendDirect()
variants now convert their extra args to aSendOptions
, and delegate to the "standard"send()
/sendDirect()
versions.SendOptions
was introduced as a means to handle combinatorial explosion ofsend()
variants.For methods that participate in the send protocol (
cGate::deliver()
,cModule::arrived()
,cChannel::processMessage()
),SendOptions
was added.cDatarateChannel
now allows the sender to explicitly specify the packet duration inSendOptions
, overriding the duration that the channel would compute from the packet length and the channel datarate.cDatarateChannel
's datarate is now optional: set it to 0 ornan
to leave it unspecified. This change was necessary to support transmitting frames with per-frame data rate selection. If the datarate is unspecified, the packet duration must be supplied in the send call, otherwise a runtime error will be raised.cDatarateChannel
: non-packet messages now pass through without interfering with packets.cDatarateChannel
: disabled channels now let transmission updates through, so that it is possible for the transmitter module to abort the ongoing packet transmission.Tx updates (without duration/remainingDuration) are allowed on paths without transmission channels.
In
cChannel::processMessage()
,result_t
was renamedcChannel::Result
, and it is now a proper return value (not an output parameter).remainingDuration
was added tocChannel::Result
.cDatarateChannel
now optionally allows multiple concurrent transmissions, with or without any bookkeeping and associated checks. This is useful for modeling a channel with multiple subchannels or carriers. The operating mode has to be selected programmatically, with the channel'ssetMode()
method. Possible modes areSINGLE
,MULTI
andUNCHECKED
.The
forceTransmissionFinishTime()
method of channels has been deprecated. It was always meant as a temporary device to allow implementing aborting frame transmissions, and now with the arrival of the new transmission update API there is no reason to use it any more. Simulations using it should be migrated to the new API.Renamed
setDeliverOnReceptionStart()
tosetDeliverImmediately()
.Added
cSimpleModule::supportsTxUpdates()
flag.cPacket
now carries aremainingDuration
field.cPacket
: eliminatedFL_ISRECEPTIONSTART
;isReceptionStart()
now usesremainingDuration
as input; added a similarisReceptionEnd()
method.cPacket::str()
overhaul to reflect new fields and uses.In the APIs, send delay and propagation delay, which were sort of combined into a single value, are now distinct values, handled separately.
Simulation kernel / Module deletion:
Added the
preDelete()
method tocComponent
. This is an initially empty virtual function that the user can override to add tasks to be done before the module (or channel) is deleted. WhendeleteModule()
is called on a compound module, it first invokespreDelete()
for each module in the submodule tree, and only starts deleting modules after that.preDelete()
can help simplify network or module deletion in a complex simulation that involves model change listeners.cIListener
's destructor now unsubscribes from all places it was subscribed to. This change was necessitated by the followingdeleteModule()
change.deleteModule()
: Module destruction sequence was changed so that when deleting a compound module, the compound module's local listeners are notified about the deletion of the submodules.deleteModule()
internals refactored. The motivation was to avoid doing things like firing pre-model-change notifications from a halfway-deleted module. Now we do every potentially risky thing (such as deleting submodules and disconnecting gates) fromdoDeleteModule()
, and only delete the module object when it is already barebones (no submodules, gates, listeners, etc). With this change, the deletion sequence is now pretty much the reverse of the setup sequence.Now it is allowed for modules to be deleted (including self-deletion) and created at will during initialization.
Simulation kernel / Expressions, object parameters, JSON values:
Under the hood, all expression parsing and evaluation tasks now use the same new generic extensible expression evaluator framework. It is used for NED expressions, object matching, scenario constraint, statistics recording, result selection in the Simulation IDE and in
opp_scavetool
, incDynamicExpression
andcMatchExpression
, etc. In the new framework, expression parsing and the translation of the AST to an evaluator tree are done in separate steps, which makes the library very versatile. Evaluators include support for shortcutting logical and conditional operators, constant folding, and anundefined
value (anything involvingundefined
will evaluate toundefined
).cNedValue
was renamed tocValue
(compatibility typedef added), as it is now a generic value container used throughout the simulation kernel (cPar
,cExpression
,cClassDescriptor
, etc.), i.e. it is no longer specific to NED.cValue
'sdoubleValue()
andintValue()
methods now throw an exception when called on a value that has a measurement unit, in order to reduce usage mistakes. If the value has a unit, call eitherdoubleValueInUnit()
/intValueInUnit()
, ordoubleValueRaw()
/intValueRaw()
plusgetUnit()
.cValue
changed to holdany_ptr
(see later) instead ofcObject*
. This change involves several changes, e.g. typeOBJECT
renamed toPOINTER
, andpointerValue()
added.cPar
: Added support for object parameters. New type constant:OBJECT
. New methods:setObjectValue()
,objectValue()
,operator=(cObject*)
,operator cObject*
.cPar
: AddedcValue
-based generic access:getValue()
,setValue()
.Store origin (file:line) info in
cPar
parameters (more precisely, incDynamicExpression
), so we can report it on evaluation errors. Most visible change:cPar::parse()
gained an extraFileLine
argument. Also,cDynamicExpression
now hasget/setSourceLocation()
.Added
cValueArray
andcValueMap
classes for representing JSON data in NED expressions. A third class iscValueHolder
, a wrapper aroundcValue
, which is only used when a non-object value (double, string, etc) is assigned to a NED parameter of the typeobject
. All three classes subclass fromcValueContainer
. Note that behavior of thedup()
methods ofcValueArray
andcValueMap
is consistent with that ofcArray
andcQueue
, i.e. only those objects that are owned by the cloned container are duplicated.NED functions that take or return values of type
object
are now allowed.NED functions can now be defined with the alternative signature:
cValue f(cExpression::Context *context, cValue argv[], int argc)
in addition to the existing signature
cValue f(cComponent *contextComponent, cValue argv[], int argc)
The
cExpression::Context
argument allows one to access the context component, and also the directory where the ini file entry or the NED file containing the expression occurred (the "base directory").Define_NED_Function()
accepts both signatures. The base directory is useful for functions likexmldoc()
that want to access files relative to the location of the NED expression.cNedFunction
now allows to search for NED functions by name AND accepted number of args.cDynamicExpression
has been reimplemented using the new internalExpression
class, and support for user-defined variables, members, methods, and functions was added. As a consequence, the public interface of the class has significantly changed as well.Added the
cOwnedDynamicExpression
class which holds the result of a NEDexpr()
operator.cOwnedDynamicExpression
is bothcOwnedObject
andcDynamicExpression
(multiple inheritance). To make this possible, thecObject
base class was removed fromcExpression
.cClassDescriptor
: Use exception instead of returningfalse
for indicating error. The return types of the following methods changed frombool
tovoid
:setFieldValueAsString()
,setFieldArraySize()
,setFieldStructValuePointer()
.cClassDescriptor
: Added support for setting pointer members and array sizes via class descriptors. New methods:setFieldArraySize()
,setFieldStructValuePointer()
.cClassDescriptor
: AddedgetFieldValue()
/setFieldValue()
methods to allow accessing fields in a typed way, usingcValue
. Previously existing methodsgetFieldValueAsString()
/setFieldValueAsString()
only allowed string-based access. In MSG files, the@toValue()
and@fromValue()
properties can be used to provide code to convert objects or fields tocValue
.cClassDescriptor
: Methods changed to useany_ptr
instead ofvoid*
for passing the object. (any_ptr
is a smart pointer class that provides type safety forvoid*
pointers.) Pointers need to be put into and extracted fromany_ptr
using the newtoAnyPtr()
/fromAnyPtr()
functions. They have specialized versions for each type (via templates and overloading). For new types, the message compiler generatestoAnyPtr()
/fromAnyPtr()
in the header file. For the simulation library classes, these methods come fromsim_std_m.h
(generated fromsim_std.msg
);sim_std_m.h
is now part of<omnetpp.h>
.Simulation kernel / Fingerprints:
Due a bugfix in
cHasher::add(const char *)
, fingerprints that involve hashing strings changed their values.The implementation of
cHasher::add(const std::string&)
was changed to be consistent with theadd(const char *)
overload. This may cause fingerprint changes in models that use it.Changed the way fingerprints are computed from figures. Most importantly, fingerprints are now affected by all visual properties, not just geometry information. This change only affects fingerprints that contain the 'f' (=figures) ingredient.
The introduction of the new expression evaluation framework also somewhat affects fingerprints. The fact that logical operators and inline-if are now shortcutting may change the fingerprint of some simulations, due to consuming fewer random numbers during expression evaluation.
Simulation kernel / Miscellaneous:
The
getModuleByPath()
method was changed to never returnnullptr
, even if an empty string is given as path. Instead, it will throw an exception if the module was not found. This change makes this method consistent with other getter methods in the simulation library, and allowsnullptr
checks to be removed from model code that uses it. A new method,findModuleByPath()
was added for cases when an optionally existing module needs to be found. These methods, initially defined oncModule
, have been moved tocComponent
so that they can be called on channels too.Signature change of the
cVisitor::visit(cObject *obj)
virtual method: it can now request end of iteration via returningfalse
(hence, return type changed fromvoid
tobool
) instead of throwingEndTraversalException
. ExistingcVisitor
subclasses in model code will need to be adjusted.cPar
: ImplementedisMutable()
and the mechanism behind the new@mutable
property.cProperty
: AddedgetNumKeys()
method;updateWith()
made public.cConfiguration
: RemovedgetParameterKeyValuePairs()
. Instead,getKeyValuePairs()
made smarter with an extraflags
parameter to be able to handle the various use cases.cMessage
: AllowedisMessage()
to be called from subclasses.cEnvir
: New result recording related methods:recordComponentType()
,recordParameter()
.cEnvir
: AddedgetConnectionLine()
, which returns the coordinates of a connection arrow. This is for certain custom animations.cEnvir
: AddedpausePoint()
, an animation-related experimental API.Result filters: Two new methods in the
cResultListener
interface:emitInitialValue()
andcallEmitInitialValue()
.cResultFilter
,cResultRecorder
: Groupedinit()
args into aContext
struct, The oldinit()
methods have been preserved as deprecated (and invoked from the newinit()
) in case an existing filter/recorder overrides them. Note that potential external calls to the oldinit()
method won't work any more (they will have no effect), and need to be changed to the new version.Added
MergeFilter
, a result filter that allows multiple inputs, and multiplexes them onto its singe output. It is available (as themerge()
function) in thesource=
part of@statistic
.Fixed histogram loading issue in the output scalar file (.sca). Bin edges that are very close could become equal in the file if insufficient printing precision was set, rendering the file unreadable. The issue is now handled both during result file writing (if such condition is detected, bin edges are written with full [16-digit] precision) and reading (zero-width bins are merged into adjacent nonzero-width bin).
Simulation kernel / Cleanup:
Removed obsolete/deprecated classes and methods. A partial list:
cVarHistogram
,cLegacyHistogram
,cLongHistogram
,cDoubleHistogram
,cWeightedStdDev
,cDensityEstBase
;detailedInfo()
method;timeval_*()
functions;cHistogram
methodssetRangeAuto()
,setRangeAutoLower()
,setRangeAutoUpper()
,setNumCells()
,setCellSize()
;operator()
of iterator classes incArray
/cModule
/cQueue
;cFigure
/cCanvas
deprecated methodsaddFigureAbove()
andaddFigureBelow()
; manycAbstractHistogram
(ex-cDensityEstBase
) methods, etc. Instead of the removedtimeval_*()
methods, useopp_get_monotonic_clock_usecs()
oropp_get_monotonic_clock_nsecs()
, and perform the arithmetic inint64_t
.Refactoring: Some classes, methods and variables related to ownership management were renamed:
cDefaultOwner
->cSoftOwner
;defaultOwner
->owningContext
, etc.The
setPerformFinalGC()
method was removed. It was meant for internal use, and pretty much unused by model code.Removed the support for OMNeT++ 4.x fingerprints (
USE_OMNETPP4x_FINGERPRINTS
).WITH_OMNETPP4x_LISTENER_SUPPORT
was removed.Source code modernization: use in-class member initializers wherever possible. The source code now requires a C++14 compiler.
Internal classes, global variables, etc moved into the
omnetpp::internal
namespace.Runtime:
Accept expressions as value for (most) config options. For options that accept values both with and without quotes (types STRING, FILENAME, FILENAMES, PATH), a heuristic decides whether a string is to be taken literally or to be evaluated as an expression. Expressions may also use NED operators, module parameters and other NED expression features. For example, it is possible to use the module vector index in the value of the
display-name
option:**.app[0..3].display-name = "cbr-" + string(index)
Allow parameter values to be specified on the command line. For example,
--**.mss=512
is equivalent to inserting the**.mss=512
line near the top of the configuration inomnetpp.ini
.Do not complain about missing
omnetpp.ini
if a--network
command-line option is present.There were several improvements related to the NED path. The
NEDPATH
environment variable has been renamed toOMNETPP_NED_PATH
, but the old one is still recognized for backward compatibility. Multiple-n
options are now accepted. Also, theNEDPATH
environment variable used to be ignored when a-n
option was present, no longer so. Excluding packages from NED file loading has also been implemented. NED exclusions can be specified in multiple ways: the-x <packagelist>
command-line option, theOMNETPP_NED_PACKAGE_EXCLUSIONS
environment variable, and thened-package-exclusions
configuration option (they accept semicolon- separated lists).Change in NED loading: Now, if a package has files in several distinct source trees, only one of them may contain a
package.ned
file.There were also several improvements related the image path. The
-i <imgpath>
option command-line option has been added. It may occur multiple times. The image path is now defined jointly by theOMNETPP_IMAGE_PATH
environment variable,-i
command-line options, and theimage-path
configuration option../bitmaps
was removed from default image path, as it was virtually unused. The default value./images
now comes from the default value of the image-path configuration option.Added support for embedding NED files into a binary (an executable or library). The
cpp
subcommand ofopp_nedtool
generates C++ code that contains the content of NED files as string constants, which can then be compiled into the simulation binary. When the simulation program is started, these embedded NED files will be loaded automatically, and the original NED files will no longer be needed for running simulations. Optional garbling, which prevents NED source code from being directly readable inside the compiled binaries, is also available. Amakefrag
file can be used to integrate the NED-to-C++ translation into the build process. To see an examplemakefrag
file, view themakefrag
help topic inopp_nedtool
.Several global config options were changed to be per-run:
scheduler-class
,debug-on-errors
,print-undisposed
,fingerprintcalculator-class
.Added the
parsim-num-partitions
config option, which makes it possible to explicitly declare the number of partitions to be used with parallel simulation. (Before, it was explicitly taken by OMNeT++ from MPI or the respective communication layer.)Added the
config-recording
configuration option, which controls the amount of configuration options to save into result files.Allow recording actual module/channel parameter values into the output scalar file, via the new
param-recording
per-object boolean configuration option. Note that parameters will be recorded as "parameter" result items, not as scalars. For volatile parameters, the expression itself will be recorded (e.g.exponential(0.5)
), not any particular value drawn from it.Added support for result directory subdivision: the
resultdir-subdivision
boolean configuration option and the${iterationvarsd}
variable. The motivation is that the performance of various file managers (including Eclipse's Project Explorer) tends to degrade severely if there are more than a few thousand files in a single directory. In OMNeT++, this problem occurs when a parameter study produces a large number of result files. The common workaround is to "hash" the files into a subdirectory tree. (For example, git also uses this technique to store the contents of.git/objects
dir).In OMNeT++, such feature can be turned on by setting
resultdir-subdivision=
true
in the configuration. Since it is natural to use the iteration variables to define the directory hierarchy, directory subdivision makes use of the new${iterationvarsd}
configuration variable. This variable is similar to${iterationvarsf}
but it contains slashes instead of commas, which makes it suitable for creating a directory tree. Enabling directory subdivision will cause/${configname}/${iterationvarsd}
to be appended to the name of the results directory (seeresult-dir
config option), causing result files to be created in a subdirectory tree under the results directory.If you want to set up the directory hierarchy in a different way, you can do so by setting the
result-dir
config option and appending various variables to the value. E.g.:result-dir = "results/${repetition}"
Added the
${datetimef}
inifile variable, which contains the current timestamp in a form usable as part of a file name.Eventlog recording: Implemented snapshot and incremental index support to increase performance and scalability. This introduces significant (breaking) changes in the
elog
file format, and adds a set of associated configuration options; see the Sequence Chart section below for details.Added
%<
(trim preceding whitespace) to the list of accepted directivesfor log prefixes.
The obsolete command-line options
-x
,-X
,-g
, and-G
were removed.Made the
-q
option more permissive: if-c
is missing, assumeGeneral
Added the
-e
option, which prints the value of the given configuration option.opp_run -v
output now includes the system architecture OMNeT++ was built for(e.g.
ARCH_X86_64
orARCH_AARCH64
).-h resultfilters
and-h resultrecorders
now include the descriptions in the list of result filters and recorders.Added two new
-h
topics:latexconfigvars
,sqliteschema
. They are mainly used for producing info for the Appendices in the manual.In order to reduce OMNeT++'s external dependencies, we now use an embedded copy of Yxml as the default XML parser. Yxml (https://dev.yorhel.nl/yxml) is a small and fast SAX-style XML parser with a liberal license.
Support for using LibXML2 remained in place, but very few users will actually need it. Expat support has been removed. Note that no significant functionality is lost when Yxml is used instead of LibXML2. LibXML2 is only needed for Schema or DTD-based validation (and possibly, default value completion), which virtually no simulation models require. Also note that Yxml-based parsing scales much better than LibXML2, both performance-wise and regarding memory usage.
The bundled SQLite sources were upgraded to version 3.30.1.
Statistics recording:
Added the
warmup
filter. This filter discards values during the warm-up period, and is automatically inserted at the front of the result filter chains when thewarmup-period
config option is present.Added the
autoWarmupFilter
statistic attribute that allows one to disable auto-adding thewarmup
filter to a statistic. Example:@statisticfoo;
This will cause all values from the
foo
signal to be recorded, even values emitted during the warm-up period (if one is set).However, the real motivation behind this feature is to allow the user to add the warm-up filter at a non-default location in the filter chain, because the default location is not always correct.
For example,
@statistic[foo](source=min;record=vector)
is equivalent to@statistic[foo](source=min(warmup(foo));autoWarmupFilter=false;record=vector)
, and records (as vector) the minimum of the values which were emitted after the warmup period is over. In contrast, if we replacemin(warmup(foo))
withwarmup(min(foo))
, it will compute the minimum of ALL values, but only starts recording the result after the warmup period has expired.This is a crucial difference sometimes. For example, a statistic might record queue length computed as the difference of the number of messages that entered the queue and those that left it:
@statisticqueueLen; //INCORRECT
In this case, if a warmup period is set, the result may even go negative because the
pkIn
andpkOut
signals that arrive during the warmup period are ignored, and ifpkOut
arrives after that, we are at -1. The correct solution is to add thewarmup
filter after the difference between arrivals and departures have been computed:@statisticqueueLen; //OK
The
autoWarmupFilter
option exists because either location for the warmup filter (beginning or end of the chain, or even mid-chain) may make sense for certain statistics. The model author needs to decide per-statistic which one is correct.Added the
demux
filter, which allows splitting the stream of values arriving from a signal to multiple streams. For example, if values from afoo
signal are tagged with the labelsfirst
,second
andthird
, then the following statistics:@statisticfoo;
will produce three scalars:
first:foo:count(demux)
,second:foo:count(demux)
, andthird:foo:count(demux)
. The labels are taken from the (full) name of the details object specified in theemit()
call.This filter is especially useful if you intend to save multiple instances of the same statistics from the same module (e.g. per-connection TCP statistics).
In result files, the
,vector
suffix is now suppressed in the titles of vector results (similarly also,histogram
and,stats
), as they simply echo the result item's type. (They were there in the first place because recording mode is automatically appended to result titles@statistic(title=...)
after a comma; it is now suppressed for the mentioned recording modes.)Added the
merge
filter which multiplexes several inputs onto a single output. It is available in thesource=
part of@statistic
.Result filters: The
count
andsum
filters now record the initial zero value as well.Result files now include two new result attributes for each item:
recordingmode
, which is the item in the@statistic(record=...)
list that produced the given result item, andmoduledisplaypath
, the module/channel path that contains display names instead of the normal names where available.sumPerDuration
filter: fix computation when invoked during warmup period.Cmdenv:
cmdenv-fake-gui
boolean configuration option, which enables "fake GUI" functionality during simulation. "Fake GUI" means thatrefreshDisplay()
is periodically invoked during simulation, in order to mimic the behavior of a graphical user interface like Qtenv. It is useful for batch testing of simulation models that contain visualization. Several further configuration options exist for controlling the details:cmdenv-fake-gui-after-event-probability
,cmdenv-fake-gui-before-event-probability
,cmdenv-fake-gui-on-hold-numsteps
,cmdenv-fake-gui-on-hold-probability
,cmdenv-fake-gui-on-simtime-numsteps
,cmdenv-fake-gui-on-simtime-probability
,cmdenv-fake-gui-seed
.Qtenv:
Modernized look: Material-style SVG-based icons, HIDPI support, dark theme support.
New actions on the main toolbar: "Debug next event", "Debug on errors", "Show animation parameters". ("Load NED file" was removed from the toolbar as it was rarely needed, but it's still available from the menu.)
The default digit separator used in the main simulation time and event number displays was changed to space.
A lot of effort was made to refine packet animation, also with regard to the new "transmission updates" API. For example, the animation filter now affects deliveries as well, and transmissions on ideal channels are now shown as a full-length line. Transmission updates are drawn as "notches" on the message line.
Turned off animating method calls by default. The rationale is that method call animations usually expose low-level (C++ implementation level) details on the GUI, which are rarely of interest to a casual user.
Added the possibility to disable method call visualization locally (for that module type) via the context menu, even when the global switch in the Preferences dialog is turned on.
Added support for showing a submodule's display name under the icon instead of, or in addition to, the normal name. The format can be selected in the context menu.
The view mode (grouped/flat/inheritance/children) in the Object Inspector used to be tied to the type (class) of the object displayed in the inspector. Since that resulted in too much mode switching while the user navigated the object tree, and the switching logic was not easily discoverable by the user, we removed the feature of per-type remembering of view modes. The view mode now only changes when the user explicitly switches in on the UI.
In the Object Inspector, added the possibility to select display mode (Children/Grouped/Flat/Inheritance) per-node. If display mode override is specified for a node, it will affect the whole subtree. The display mode for the selected tree can be changed via hotkey (Ctrl+B) or via the context menu.
The "Set Sending Time as Reference" option was added to the messages view context menu. This option makes it possible to set a reference time, and display all other times as a delta compared to it.
In the messages view, there was a slight change in the notation used for the source and destination modules of the message, in order to make it unambiguous. Use explicit "." and "^" to indicate the location of the module. Also, it now uses arrows of uniform lengths everywhere.
The "Allow Backward Arrows for Hops" option was added to the messages view context menu. When this option is enabled, it allows the use of backward arrows to ensure a consistent relative ordering of modules in the log. For example, if two modules A and B exchange messages, this option will cause the window to display them as "A-->B" and "A<--B", as opposed to the default "A-->B" and "B-->A". This sometimes makes the log easier to follow.
Added support for new columns in the packet log view: TxUpdate, Durations, Length, Info. This was implemented in the
cDefaultMessagePrinter
class which is part of the simulation library. This change makes it possible to see if a packet is a transmission update (except if the simulation installs its own packet printer like INET does).In the messages view, simulation time is now formatted with digit grouping on.
In the log, the banners of component init stages that do not print anything are now suppressed.
Added the "Fira Code" font as embedded resource, and set it to be used by default for the log window. The reason is that it provides nice "-->" arrow ligatures in the Messages view.
Prevent manually enabled "Debug on Errors" setting from being turned off by (lack of) configuration option.
Fix osgEarth viewpoints ignoring SRS (PR #851).
Countless small improvements and bug fixes.
Raised the minimum required Qt version to 5.9.
Tkenv:
Tools:
The names of all command-line tools now begin with
opp_
.Added
opp_ide
, an alternative to theomnetpp
command that launches the Simulation IDE.Added
opp_neddoc
, a tool that makes it possible to generate HTML documentation from NED files from the command line.opp_neddoc
works by launching the IDE in headless mode.opp_nedtool
was rewritten for convenience and features. The main points are the following:cpp
subcommand), for embedding NED files into an executable or library.*_n.ned
,*_n.xml
).@listfile
and@@listfile
support.opp_msgtool
was rewritten in the style ofopp_nedtool
. Details:--msg6
the default mode,--msg4
was removed.-T
(type of next file) and-h
(here) options have been removed.builtindefs
help page has also been added, which prints the built-in declarations.opp_scavetool
had several improvements. A brief summary:**
) in addition to normal wildcards (*
,?
). Double asterisks can match any number of directory levels. Example:results/**.vec
matches all.vec
files anywhere under theresults/
directory. (When specifying wildcard arguments on the command line, be sure to quote them so that the shell does not expand them beforeopp_scavetool
gets invoked.)--start-time <time>
,--end-time <time>
.--<key>=<value>
notation as well, not only with-x
.runattr:
prefix. Theattr:
prefix now only matches result attributes.opp_scavetool
and exporters. The recommended way of processing output vectors is with Python and NumPy.help
subcommand was refined.Added
opp_charttool
, a tool for "running" ANF files on the command line, e.g. for image or data export. Filtering options (-i
,-n
) allow multiple charts to be selected for exporting. Thetemplates
subcommand lists the available chart templates.opp_featuretool
: Extensive refactoring as well as refinement of its operation and command-line options. In general, the tool has become more forgiving: a missing.featurestates
file or extra/missing entries in it no longer causes an error or warning. Missing file and file entries are initialized with the default enablement state; extra entries are preserved (in the hope they'll be useful, e.g. after switching to a different topic branch). The content of the.nedexclusions
file is now also automatically adjusted without stopping with an error. User-visible changes are the following:validate
andrepair
subcommands (all commands implicitly validate and repair now)..oppfeatures
file: Detect and report duplicate feature IDs and unresolved feature dependencies..featurestate
file instead of fail/warn about them. Reason: they often occur when switching between branches.isenabled -v
prints list of disabled features to stdout, not to stderropp_makemake
: Themakefrag
file is now included instead of copied into the generated makefile. Also, ahelp
target has been added to the generated makefiles: typingmake help
now prints the list of accepted targets (all
,clean
, etc.) and user-settable makefile variables (MODE
,V
,CFLAGS
, etc.), complete with helpful descriptions and usage examples.opp_test
: The set of possible test outcomes has been refined. Possible outcomes are nowPASS
,FAIL
,ERROR
,SKIP
andEXPECTEDFAIL
.SKIP
means that the test was not performed, because e.g. it would test an optional feature which is currently disabled;ERROR
means that the test was not performed because of an unrecoverable error (i.e. crash or exception). The diagnostic output for failed tests is now a colorized diff instead of a simple printout of the expected and the actual contents. It is possible to designate a test case as an "expected failure", by specifying%expected-failure: <reason>
in the test file. This is useful if we know that a certain test case is correct, but it is not possible to fix it for some reason.IDE / Analysis Tool:
The Analysis Tool in the IDE has been rewritten, using a new approach. The number one goals were to allow ARBITRARY computations to be performed on the data, VISUALIZE the result in the most appropriate form chosen from a multitude of chart/plot types, and produce PUBLICATION QUALITY output. Additional goals were an intuitive user interface that makes straightforward tasks easy and convenient, scalability that allows the processing of a large amount of simulation results inside the IDE, and facilities to make (most of) the UI's functionality available on the command line as well.
The key technologies the new Analysis Tool employs are Python, NumPy, Pandas, and Matplotlib. The use of Python and Pandas gives access to advanced data manipulation and analysis capabilities, while Matplotlib offers dozens of plot types out of the box, endless customizations, and proven high-quality output. A large effort was made to properly integrate these technologies into the IDE, so that using the Analysis Tool provides a superior user experience, and brings the power of Python close to users without necessarily requiring them to write code in Python.
Common charting tasks are accessible with a few mouse clicks, via predefined Chart Templates that can be configured using dialogs. The heart of all Chart Templates is Python code that performs all of the computation and plotting. The Python code behind a chart can be viewed and freely edited using an integrated language-aware editor. Matplotlib plots appear inside the Analysis Tool's UI, and they are live (i.e. not just images): zooming, panning, and interacting with possible embedded controls in the plot all work seamlessly. IDE-native plots can also be chosen as an alternative to Matplotlib, as they provide increased scalability at the cost of being less flexible and featureful.
Special attention was paid to scalability. The UI is now easily capable of dealing with at least several tens of thousands of result files, and several million result items.
The OMNeT++ Python API for querying, transforming and plotting simulation results is available in the form of Python packages for use in Python scripts outside the IDE as well. There is also a command-line tool (
opp_charttool
) that can "run" Analysis (anf) files e.g. for image export.opp_charttool
can be integrated e.g. into the build process of a paper written in LaTeX.The documentation of the Analysis Tool's user interface can be found in the User Guide. A reference of the Python API has a dedicated Appendix in the Simulation Manual, while the "Result Recording and Analysis" chapter in the same Manual provides some practical guidance on how to use the API.
IDE / Sequence Chart Tool:
The visualization of events have been horizontally expanded on the chart, now it uses long rounded rectangles instead of small circles. This change allows the visualization of method calls without their arrows overlapping. If method calls are hidden then the chart falls back to the old behavior where events are small circles.
The set of displayed axes can be explicitly configured independently from the set of displayed events. The chart now also supports displaying events on a compound module axis if the corresponding submodule axis is hidden. Collapsing and expanding module axes can be done using the mouse.
The chart now also displays a set of axis headers on the left side that shows the module hierarchy in a compact and interactive way.
All parts of the sequence chart can be independently shown/hidden.
The selection has been extended with support for axes and method call arrows.
A new time measurement feature has been added that allows measuring the time difference between multiple selected events and other interesting points in time.
Several automatic configuration presets have been added (e.g. network level, full detail, default) to make the configuration for the most common use cases easier.
A new pattern-matching-based user-defined colorization (e.g. message sends, method calls, axes, events) feature has been added. This feature allows creating more easily understandable sequence charts by encoding certain model properties as colors.
The chart can display diagnostics information such as eventlog file statistics and operation statistics.
Added support for SVG export.
IDE / NED Documentation Generator:
The documentation generator now allows you to inject your own documentation fragments (possibly generated by 3rd-party tools) at various points in the documentation.
Modern look for the generated pages (Material design).
It is now possible to specify excluded directories during documentation generation, in order to be able to exclude samples, showcases etc. that are not integral part of the documentation.
Now generates
nedtags.xml
andmsgtags.xml
files which are compatible with thedoxytags.xml
file that Doxygen generates. This allows crosslinking to the NED documentation from a Sphinx-based documentation, using the doxy-link plugin.Generate usage and inheritance diagrams only if they are meaningful.
Use SVG files as the usage/inheritance diagram image. Removed map files as SVG already contains proper links.
Generate "Implementors" table for interfaces. The Implementors table includes indirect implementors as well.
Fix: Inheritance diagrams were missing in module interface pages, even if they had implementors. This bug made INET documentation much less useful.
The functionality of the documentation generator is now also available from the command line (
opp_neddoc
).IDE / Inifile Editor:
Added support for ignorable options. User can mark custom config options as ones to be ignored by the editor.
Config option values that contain expressions are no longer falsely flagged as errors.
The confusing "Unused entry (does not match any parameters)" warning that often appeared falsely for INET simulations due to deficiencies in analyzing the network structure has been re-worded to include the possibility that it is false, and has also been demoted from being "warning" to "info".
Eliminated the asynchronous/delayed form page reread in Form mode, which often caused editing glitches.
IDE Miscellaneous:
Install Simulation Models dialog: Added support for changing the project name and location on download.
Turned on showing the line numbers ruler in source editors by default.
Added an XML editor, Terminal (a view that contains a shell prompt), PyDev (Python editor), and the Eclipse Marketplace client to the IDE.
The simulation launcher now passes NED exclusions to the simulation program as
-x
options. NED exclusions typically come from disabled project features, e.g. in INET.Added SVG export capability to the NED Editor.
Updated to Eclipse 4.22, CDT 10.5 and PyDev 9.2.
The JRE is now provided by the Eclipse JustJ project, so the IDE no longer requires Java to be installed on the host OS.
Added support for ARM-based Linux distros.
C++ Debugging:
Better debugging experience by fine-tuning the compiler options, especially with the clang compiler.
Added LLDB pretty printers for various OMNeT++ types. They can be useful if you use LLDB-based external debuggers like XCode or VS Code. You should manually import them from the LLDB debugger console with the following command:
command script import <OMNETPP_ROOT>/python/omnetpp/lldb/formatters/omnetpp.py
Allow Qtenv's "Debug on Error" and "Debug Next Event" functionality to use the integrated debugger of the Simulation IDE. This required multiple changes. First, the IDE was extended to accept an URL which, when opened in the IDE, causes the integrated debugger to start a debug session and attach to a process given with its PID. This URL is:
omnetpp://cdt/debugger/attach?pid=<pid>
The URL can also be opened from the command line, by running the
omnetpp
command with the URL as argument. The command opens the URL in the existing IDE instance if it is already running, or starts a new one if it does not.The second change was to update the default value of the OMNeT++
debugger-attach-command
configuration option to use the above command. (Previously it has used various other debuggers which were likely to be found on the host OS: GDB, Nemiver, VS Code, etc.)Hint: You can force Qtenv to use Visual Studio Code as your external debugger by setting the following environment variable:
export OMNETPP_DEBUGGER_COMMAND="code --open-url "vscode://vadimcn.vscode-lldb/launch/config?{request:'attach', pid:'%u'}""
Alternatively, you can specify the same value (
code --open-url ...
) to the "debugger-attach-command" configuration option inomnetpp.ini
.Result file format changes:
There were a number of changes in the format of result files (.sca and .vec files), so the file format version has been bumped from 2 to 3. (The file format is recorded at the top of each result file in a
version
line.) The set of changes is relatively small; see details below.Iteration variables are no longer saved as run attributes but in separate
itervar
lines, in order to be able to tell them apart with certainty.param
lines (which recorded parameter assignment entries in the configuration) have been replaced with the more generalconfig
lines.config
lines record all configuration entries, not just parameter assignments.In version 2, concrete parameter values (if requested) were recorded as scalars, whereas in version 3 they are recorded as a separate result item type, in
par
lines. This allows the recording of volatile parameters (as expressions) and non-numeric values as well.Component NED type names are now recorded, as
typename
pseudo parameters.The
sum
andsqrsum
fields of weighted statistics are no longer recorded, as they are irrelevant.SQLite result file format changes:
SQLite result files underwent a similar change in the database schema. Files in the old format are no longer understood. A brief summary of changes follows.
The
runParam
table was renamed torunConfig
, and its columns were also similarly renamed:paramKey
,paramValue
andparamOrder
becameconfigKey
,configValue
andconfigOrder
, respectively.Iteration variables are in a new table called
runItervar
, with columnsrunId
,itervarName
anditervarValue
.Two new tables were added for representing the new result item types:
parameter
(with the columnsparamId
,runId
,moduleName
,paramName
andparamValue
), andparamAttr
(with the columnsparamId
,attrName
andattrValue
). Note thatparamValue
contains values in the syntax it would have to be written in a NED file or inomnetpp.ini
, i.e. string constants include the quotation marks.Eventlog file format and configuration:
The eventlog file format has been changed substantially. You won't be able to open older eventlog files with this version of the IDE, nor new files in previous IDE versions.
The most prominent change is the introduction of snapshot and index chunks in addition to the already recorded event chunks. The former contains a complete snapshot of the relevant simulation state without referring to any other line in the file. The latter provides the set of changes in the relevant simulation state since the last index or snapshot chunk. The contents of the index chunk is expressed as references to other lines of the eventlog file. This change in the eventlog format provides the foundation for a better user experience in the IDE especially for large eventlog files.
Several new eventlog-recording-related configuration options have been added:
The
eventlog-snapshot-frequency
configuration option specifies how often snapshots are recorded in the eventlog file. Snapshots help various tools to handle large eventlog files more efficiently. Specifying greater value means less help, while smaller value means bigger eventlog files.The
eventlog-index-frequency
configuration option specifies how often indices are recorder in the eventlog file. An index is much smaller than a full snapshot, but it only contains the differences since the last index. Specifying greater value means less help, while smaller value means bigger eventlog files.The
eventlog-max-size
configuration option specifies the maximum size of the eventlog file in bytes. The eventlog file is automatically truncated when this limit is reached.The
eventlog-min-truncated-size
configuration options specifies the minimum size of the eventlog file in bytes after the file is truncated. Truncation means older events are discarded while newer ones are kept.The
eventlog-options
configuration option allows for recording only certain categories (e.g. text, message, module, method call, display string), to reduce the eventlog file size.Build environment:
If a file called
setenv_local
is present in the installation root, it is automatically sourced from thesetenv
script.setenv_local
can be used to set up user specific environment variables.The content of the
$PLATFORM
makefile variable has changed. Until now, it contained a<platform>.<architecture>
pair (e.g.win32.x86_64
) which was misleading. From now on,Makefile.inc
provides$PLATFORM
(e.g.win32
) and$ARCH
(e.g.x86_64
) as separate variables.makefrag
files must be updated if$PLATFORM
variable was used in them.To build OMNeT++ with Akaroa support,
WITH_AKAROA=yes
must be specified in theconfigure.user
file. The configuration script no longer tries to autodetect Akaroa without the user explicitly requesting it.osgEarth support is now disabled by default. You must explicitly set
WITH_OSGEARTH=yes
in theconfigure.user
file. Some Linux distibutions no longer include osgEarth so you may need to build it manually from sources.Debug builds are now compiled with -O0 for maximum debuggability. Release builds are compiled with
-O2 -ffp-contract=off
to disable fused multiply-add operations. This ensures that floating point operations will generate exactly the same results in DEBUG and RELEASE mode and their accuracy would not depend on unpredictable optimizations.Windows Support:
On Windows, the toolchain (compiler, libraries, etc.) can now be found in
tools/win32.x86_64
.Setting of environment variables has been moved into the
setenv
script. It is automatically sourced whenmingwenv.cmd
orvcenv.cmd
is started.On Windows, libraries and other dependencies used by simulations, such as Qt, OSG, osgEarth, etc., are now separated from the rest of the toolchain binaries (compiler, etc.). You can find them in the
opt
subdirectory of thetools/win32.x86_64
folder.On Windows, when creating a shared library, the build system now generates a proper import library and also a module definition file (
<targetname>.dll.a
,<targetname>.def
). External projects must link against that library instead of linking directly with the<targetname>.dll
file. (Note that the linker automatically uses the.dll.a
files if they are present in the library path and falls back to use the pure.dll
file only if the import library is not present. It means that you don't have to do anything extra to use these files apart from making them available along your.dll
files.)The Windows toolchain now contains the (much faster) LLD linker. LLD is also used on other platforms instead of the GNU linker, if available. For large projects, LLD is dramatically faster than the standard GNU linker. In one instance, the use of LLD, together with other changes that were partly done in INET, reduced INET linking time on Windows from 380s to 2s in DEBUG mode, and from 90s to 5s in RELEASE mode on one of our dev boxes.
macOS support:
On macOS, the toolchain (compiler, libraries, etc.) can now be found in
tools/macos.x86_64
.Rudimentary support for Apple silicon:
source setenv
now automatically launches a (nested) x86_64 emulation shell on ARM-based Macs.Sample simulations:
Added "openstreetmap", an example simulation that displays a city map, with some animated car traffic on it. Map data come from an OSM file exported from openstreetmap.org.
Added "petrinets", an example simulation demonstrating how to implement stochastic Petri nets, a well-known formalism for the description of distributed systems.
Added the "wiredphy" sample simulation to demonstrate transmission updates.
The "fifo" example simulation was extended with a TandemQueues network and related configurations in omnetpp.ini.
The "resultfiles" folder project now contains scalar and vector result files from the Fifo1, Fifo2, and the new TandemQueues simulations.
Documentation:
Simulation Manual has been updated. The largest changes were in the "Message Descriptions" and "Result Analysis" sections (which were practically rewritten). There are also two new appendices: "Python API for Chart Scripts", and "Message Class/Field Properties".
User Guide: The chapter about the Analysis Tool ("Result Analysis") has been rewritten.
Install Guide has been updated. New sections in the macOS chapter: "Enabling Development Mode in the Terminal", "Running OMNeT++ on Apple Silicon". We also added instructions on installing OMNeT++ on WSL (Windows Subsystem for Linux) on Windows 10, which is important because we found that running OMNeT++ on WSL is considerably faster than using it with the MinGW toolchain.
Converted all of our structured documents (User Guide, Install Guide, etc.) from their original source format (DocBook or AsciiDoc) to reStructuredText, except for the Simulation Manual which remains in LaTeX.