SimStream

The SimStream simulation software for video streaming is a project in progress and the software on this page is subject to change. There are no guarantees for this software and you can use it on your own risk. SimStream is free software and is licensed under the terms of GNU General Public License.

Online Resources

On This Page

  1. The Basics
    1. What is SimStream?
    2. Architecture and Main Components
  2. Simulator Core
    1. The Run-Time
      1. Simulation Events, Calls and Execution Flow
      2. The Events List
      3. The Simulation Model
    2. Objects and Cross-Communication
      1. Object Delegates
      2. Object Events
      3. Object Calls
    3. Timers
  3. Networking Library
    1. Packets
    2. Protocols
      1. IP, Addressing and Routing
      2. IP Multicast
      3. Transport Layer
    3. Network Nodes
      1. Hosts
      2. Routers
    4. Streaming
      1. Connectionless Streaming
      2. Connection-Oriented Streaming
      3. Congestion Control
  4. Streaming Library
    1. Application-Layer Multicast
    2. On-Demand Streaming
  5. Simulation of Large-Scale P2P Streaming
    1. The Problem
    2. Implementation Aspects
    3. Findings

I. The Basics

In this chapter you will learn the basics of the SimStream simulation software:

  • What is SimStream and what are the main features?
  • What is the software architecture and the basic components?
  • How can you use the basic components to create a simple simulator?

Go to top | Go to contents

I.1. What is SimStream?

The streaming simulator, or SimStream for short, is a packet-level time-discrete network simulator, designed to be efficient for simulating large scale streaming applications. A particular requirement of these applications is that they need to simulate a large number of hosts and packets leading to extensive simulation times for many scenarios.

Compared with existing network simulators, SimStream reduces the complexity and computing times with the following key aspects:

  • Uses native executable code written in C++
  • Uses index-based addressing making packet routing and forwarding a constant-time operation
  • Uses delegate-based communication between simulator components

Go to top | Go to contents

I.2. Architecture and Main Components

SimStream consists of the following main components:

  • The core
  • A set of add-on libraries
  • A set of implemented simulators

The figure I.a illustrates the main components and sub-components.

Figure I.a

Figure I.a. SimStream architecture and simulators currently implemented

The simulator core

The simulator core is the central part of the simulator that can be used to create any type of time-discrete simulations, not necessarily computer network simulations. The core uses an event scheduling mechanism to serialize the execution of tasks according to their temporal order within the simulation. The core provides a set of core services, interfaces and libraries.

  • The core services includes the simulator run-time that executes the simulation tasks. In addition, the run-time manages the simulation virtual time and schedules new tasks in the form of simulation events and simulation calls stored in an events and calls list.
  • The core interfaces provide the foundation to build a simulator. They contain an interface for simulation events and an interface for the simulation model.
  • The core libraries provide two classes of essential elements. The first, contains several entities such as delegates, calls and events, that allow flexible cross-object communication within the simulation. The second, provides timers.

The simulation libraries

The simulation libraries bring an extensive set of functionality that is required to implement network simulations for multimedia streaming. Although the libraries are not at all essential when developing a fully customized simulation from scratch, they provide common used elements such as basic implementation of several network protocols, network entities such as hosts, routers and links, streaming client and server application layers, streaming encoders and decoders, etc. In addition, commonly-used routines such as data collection, output formatting, cross-platform random number generators and shuffling are also available.

The libraries provide evolving functionality, and typically contain any set of objects and functions that is general enough to be used in more than one simulator.

The simulators

The simulators is a list of customized simulator implementation that are part of the current version of SimStream. Each of this simulators uses the core and various elements from the simulation libraries to implement its desired objectives. The following tables illustrates the current simulators and their purpose.

Simulator Objective
P2P Streaming with Single ALM-tree Simulation of a multiple channel IPTV service with hybrid IP-multicast and P2P streaming. The P2P overlay uses a single ALM tree with push-based forwarding for each channel.
P2P Streaming with Multiple ALM-trees Simulation of a multiple channel IPTV service with hybrid IP-multicast and P2P streaming. The P2P overlay uses more than one ALM tree with push-based forwarding for each channel.
P2P Streaming with Mesh Simulation of a multiple channel IPTV service with hybrid IP-multicast and P2P streaming. The P2P overlay uses a mesh structure for each channel with segment-level pull-based forwarding. Segment scheduling is done according to the DoNET/Coolstreaming algorithm.
Unicast Connection Measurement Simplified simulation of a multiple channel IPTV service for the purpose of measuring the hop-based distance between hosts.
Multicast Connection Measurement Simplified simulation of a multiple channel IPTV service for the purpose of measuring the size of the IP multicast tree.
TFRC Flow Throughput Measurement Simulation of TFRC flow congestion control.

Go to top | Go to contents

II. Simulator Core

This chapter describes the core of the SimStream simulator:

  • The run-time and the scheduling of simulation of events, calls
  • The role of the simulation model
  • Simulation objects and cross-communication between them
  • Times and their usage

Go to top | Go to contents

II.1. The Run-Time

The run-time is the central part of the simulator. It manages the execution flow of the simulation tasks in the form of simulation events and simulation calls. In addition, it keeps track of the simulation virtual time, and provides the methods for the scheduling and cancellation of events and calls. The run-time is implemented by the following object class.

Class Description
CSim The simulator run-time.

Because all other objects within a simulation cannot call the run-time directly, for purposes such as scheduling events and obtaining the current virtual time, the run-time provides an abstract interface called the simulator handler that can be used for such purpose. At startup, the run-time passes a reference to this handler to the current simulation model, which then can pass it on to all other objects that need to call functions of the run-time. The simulator handler is implemented by the following object class.

Class Description
CSimHandler The handler to the simulator run-time.

Go to top | Go to contents

II.1.a. Simulation Events, Calls and Execution Flow

The main function of the run-time is to accept the scheduling of simulation tasks from the simulation model or one of its sub-components, and execute them. The simulator tasks come in two flavors:

  • Simulation events, and;
  • Simulation calls.

Both the simulation events and simulation calls are objects that contain information about tasks to execute at any step during the simulation. In the following, we shall describe both, emphasizing the similarities and differences between them.

Simulation Events

The simulation events are typically the most common used type of task objects to control the flow of the simulation. By far, the majority of tasks from a simulation consists of events.

All events have a temporal variable that indicates to the run-time when they should be executed on the virtual time scale, and some information about what the execution of the event should do. This information can be anything: data, code or both. The run-time executes the events by passing them to the simulation model, which in turn can use the custom information within the event to perform a specific action. To increase the performance of the simulation, the majority of events contain both the code and data to be executed. In this manner, the simulation model executes an event simply by calling its piece of code, rather than by trying to interpret the data from the event. The figure II.a illustrates the structure of a simulation event.

Figure II.a

Figure II.a. The structure of a simulation event

The generic interface for a simulation event is implemented by the following object class.

Class Description
CSimEvent The generic interface for a simulation event.

Simulation Calls

A simulation call is a light-weight version of a simulation event. Unlike events, calls do not have a temporal relationship between them, and all current calls are executed at the end of the current event. Simulation calls are object calls, and their sole purpose is to execute tasks that belong to the current event but cannot be executed as part thereof. All scheduled calls are synchronous with the event after which they are executing sharing the same virtual time, and they are executed directly from the run-time.

Example

One common example for using calls is represented by self clean-up tasks, for example an object deleting itself when receiving a certain event. When it is not safe to delete an object as part of a current event (because there may be other references to the object after the memory is freed), the call allows you to schedule this operation after the event has finished.

A second example is where, during an event, a large number of objects call methods of each other sequentially, which might lead to a stack overflow situation. In cases where the number of these type of calls is dependent on an input parameter, it is always safer to use calls. Calls are executed from the run-time context, and always in their scheduled order.

Execution Flow

The simulator run-time execution flow consists in executing scheduled events and calls. Simulation events are always executed first, each event followed by simulation calls, if available. If the code executed during an event schedules more than one call, all scheduled calls are executed after the event with the same virtual time. The figure II.b illustrates the execution flow of the simulator run-time.

Figure II.b

Figure II.b. Run-time execution flow

Go to top | Go to contents

II.1.b. The Events List

The event list is an ordered list maintained by the simulator run-time that stores simulation events. The events are ordered according to their execution time in a B-tree structure that allows insertion, access and removal of events in a logarithmic amortized time, O(log n). Therefore, the simulator event list performance depends on the number of events with different execution times that is stored in the event list at any given time. Events that share the same execution time are stored according to a FIFO rule, and executed in the same order.

The calls list

Unlike the events list, the calls list is a FIFO list that stores all calls that must be executed after the current event. Because a call is always executed after the current event, they are synchronous with the event that generated them and share the same virtual time. However, the FIFO list guarantees that calls are executed in their scheduled order.

The simulator events list and calls list are implemented by the following object classes.

Class Description
CSimEventList The simulator event list.
CSimCalls The simulator calls list.

Go to top | Go to contents

II.1.c. The Simulation Model

The simulation model is the implementation of an interface that instructs the run-time how to execute the simulation. The SimStream simulator allows the implementation of any number of simulation models for any time of event-based time-discrete simulations. All simulation models must implement the CSimModel interface.

The simulation model provides the following set of parameters to the run-time:

  • The maximum simulation time
  • A list with initial events (each event is allowed to have an arbitrary virtual execution time)

Upon startup, the run-time provides the simulator handler to the model via an initialization function, allowing the model to obtain the virtual time and to schedule events and calls During simulation, the run-time executes the events by passing them to the model via an execution function. The model understands the structure of each event and based on the data and code the event carries, executes the appropriate task. Upon completion of the simulation, the run-time calls a finalization function enabling the simulation model to execute post-simulation tasks such as writing simulation results to files. For more information, see the run-time.

The figure II.c summarizes the interconnection between the simulator run-time and the simulation model.

Figure II.c

Figure II.c. Information flow between the run-time and the simulation model. The arrows indicate the direction of the information flow and counter-indicate the direction of the function call.

On the usage of the simulator core

The simulator core is designed for discrete time-domain simulations. However, time-independent scenarios may still take advantage of the SimStream libraries simply by bypassing the core. These scenarios do not require events, the usage of the run-time or the implementation of the simulation model. Instead, they can take advantage of the existing libraries and provide their own internal logic on how to use them.

SimStream includes two examples of time-independent simulators that bypass the core and use only a subset of required libraries:

  • Measurement of unicast connections: uses the networking libraries to calculate the average unicast path length between pairs of random hosts.
  • Measurement of multicast connections: uses the networking libraries to calculate the average multicast tree size with respect to the membership group size.

The abstract interface for a simulation model is implemented by the following object class.

Class Description
CSimModel The abstract interface for a simulation model.

Go to top | Go to contents

II.2. Objects and Cross-Communication

SimStream is a simulator implemented in C++. For this reason, all components are implemented as C++ classes, and all variables (with the exception of the fundamental data types such as int, char or double) or objects or pointers to objects. This approach decreases the gap between the real-life objects that must be simulated and their actual implementation.

To this end, all simulated real-life objects such as hosts, routers, packets, software (protocol layers, clients, servers, video players, etc.) are defined as C++ classes. Similar to the real-life objects they are trying to mimic, many of these classes require the ability to interact with each other on a reciprocal bases. An example of such interaction is represented by an upper protocol layer needing to interact with a lower protocol layer, while the lower protocol layer needs to interact to the same upper protocol layer. In addition, this level of interaction should be accomplished while the two classes are relatively separated from one another and they communicate only through a set of well defined interfaces.

However, the C++ programming language has not been designed with such a degree of inter-object communication in mind. One possible solution is to use inheritance where the base class defines the ground functionality while the derived classes implement the most complex features. A first drawback of this approach is that many different classes will be intricate linked to each other, defeating the initial purpose of separating the functionality in different objects in the first place. Then, the derived classes will be limited to the functions available in the base class, or the base class may become unnecessarily complex to accommodate the requirements from all derived classes.

The figure II.d is an example of the required level of inter-object communication. The figure illustrates the common protocol stack implemented in SimStream hosts and routers. Each set of common functions is implemented in a separate object class. This approach makes different components reusable (e.g. the blue components are used by both hosts and routers, while the orange components are only used by routers), while avoiding to add complexity to objects that do not require it (e.g. unlike in practice, IP unicast routing tables for incoming packets are not implemented by hosts, keeping the simulator optimized).

Example

Figure II.d

Figure II.d. Example of inter-object communication: implementation of the protocol stack of hosts and routers in SimStream. The arrows indicate the flow of information and/or the direction of the function calls.

This degree of interdependence, which can be far more complex when adding new protocols, makes it very difficult to use C++ class inheritance. In addition, the inheritance must follow the dependency between classes resulting sometimes in a counter-intuitive implementation. For instance, the figure II.e illustrates a possible dependency diagram for the components listed in figure II.d, in which upper layer protocols such as IGMP and PIM-SM must be base classes, while IP forwarding must be derived classes.

Example

Figure II.e

Figure II.e. A possible inheritance diagram for the C++ classes that implement the protocol stack from figure II.d.

Apart from class inheritance, there may be several other solutions to pass object parameters between classes. One is to use a global dispatcher with parameters as generic pointers (void*). The disadvantage of this approach is that class objects must register with the dispatcher, increasing the execution complexity, and the developer must keep track of the parameters data type, increasing the development effort.

To avoid these disadvantages, the SimStream simulator core provides a set of constructs that enables type-safe fast inter-object communication. These allow different classes to call each others' member functions directly, as in the following scenario.

Example

Figure II.f

Figure II.f. Implementing IP and UDP layer functions in separate classes and the required interaction between them. Code sample II.a illustrates the C++ classes for this scenario.

class CLayerIp
{
// other declarations
public:
    void Recv(CPacketIp ip)
    {
        // call Recv() for the object of class CLayerUdp
    }

    void Send(CPacketIp ip)
    {
        // send packet to lower layer
    }
};
class CLayerUdp
{
// other declarations
public:
    void Recv(CPacketUdp udp)
    {
        // receive packet from lower layer
    }

    void Send(CPacketUdp udp)
    {
        // call Send() for the object of class CLayerIp
    }
};

Code sample II.a. C++ classes for for the scenario from figure II.f.

The types of constructs for inter-object communication are:

In actuality, these constructs are C++ template classes. They use pointers to member functions to enable generic calls from one class to another, without any requirement on the class dependency.

Go to top | Go to contents

II.2.a. Object Delegates

A delegate is a template class that enables single function calls, that is a delegate wraps one object and one function. Any object that obtains an instance of the delegate, can use it to call the one function for the one object contained by the delegate.

On the use of delegates

The programmer must be extremely careful when using delegates, making sure that any delegate created for the function of an object is no longer used after the object has been destroyed.

A delegate has two components:

  • A generic part (in actuality the base class of the delegate), that is independent of the type of the contained object.
  • An explicit part (in actuality the derived class of the delegate), that is explicitly defined for a certain type of the contained object.

In addition, a delegate is explicitly defined for a certain function prototype (i.e. list of parameters and return type). An explicit delegate can be casted to a generic delegate of the same function prototype, but not the other way around.

Example

This example resumes the example from figure II.f, while emphasizing a single call using a delegate.

Figure IIg

Figure II.g. IP layer object calling a UDP layer object through a delegate.

class CLayerIp
{
private:
    // The generic part of the delegate defined for a function prototype with return type void
    // and 1 parameter of type CPacketUdp
    IDelegate1<void, CPacketUdp>* delegateGenericRecvUdp;
public:
    // Set the delegate for receiving UDP packets
    void SetDelegateRecvUdp(IDelegate1<void, CPacketUdp>* delegateGenericRecvUdp)
    {
         this->delegateGenericRecvUdp = delegateGenericRecvUdp;
    }
    // Receiving IP packets
    void Recv(CPacketIp ip)
    {
        ...
        // If the payload is UDP, send the packet to the UDP layer object using the delegate
        CPacketUdp* udp = ip.Payload();
        (*this->delegateGenericRecvUdp)(udp);
    }
};
...
CLayerIp* layerIp = new CLayerIp(...); // Create the IP layer
CLayerUdp* layerUdp = new CLayerUdp(...); // Create the UDP layer 

// Create the explicit part of the delegate defined for a class of type CLayerUdp
// and a function prototype with return type void and 1 parameter of type CPacketUdp
Delegate1<CLayerUdp, void, CPacketUdp>* delegateExplicitRecvUdp =
    new Delegate1<CLayerUdp, void, CPacketUdp>(
        layerUdp,         // the delegate wraps the object layerUdp
        &CLayerUdp::Recv  // and the function Recv of class CLayerUdp
        );

// Tell the delegate to the IP layer object: the explicit delegate is safely casted to the generic delegate
layerIp->SetDelegateRecvUdp(delegateExplicitRecvUdp);

// From now on, when the object layerIp calls:
(*this->delegateGenericRecvUdp)(udp);

// It will be equivalent to calling the function of the object the delegate contains:
layerUdp->Recv(udp);

Code sample II.b. Using a delegate to connect the objects from scenario presented in figure II.g.

Currently, the simulator core provides delegates for function prototypes with up to five parameters. The explicit version of these delegates are implemented by the following object classes.

Class Description
Delegate0 Explicit delegate with zero parameters.
Delegate1 Explicit delegate with one parameter.
Delegate2 Explicit delegate with two parameters.
Delegate3 Explicit delegate with three parameters.
Delegate4 Explicit delegate with four parameters.
Delegate5 Explicit delegate with five parameters.

The generic version of these delegates are implemented by the following object classes.

Class Description
IDelegate0 Generic delegate with zero parameters.
IDelegate1 Generic delegate with one parameter.
IDelegate2 Generic delegate with two parameters.
IDelegate3 Generic delegate with three parameters.
IDelegate4 Generic delegate with four parameters.
IDelegate5 Generic delegate with five parameters.

Go to top | Go to contents

II.2.b. Object Events

Coming soon!

Go to top | Go to contents

II.2.c. Object Calls

Coming soon!

Go to top | Go to contents

II.3. Timers

Coming soon!

Go to top | Go to contents

III. Networking Library

Coming soon!

Go to top | Go to contents

III.1. Packets

Coming soon!

Go to top | Go to contents

III.2. Protocols

Coming soon!

Go to top | Go to contents

III.2.a. IP, Addressing and Routing

Coming soon!

Go to top | Go to contents

III.2.b. IP Multicast

Coming soon!

Go to top | Go to contents

III.2.c. Transport Layer

Coming soon!

Go to top | Go to contents

III.3. Network Nodes

Coming soon!

Go to top | Go to contents

III.3.a. Hosts

Coming soon!

Go to top | Go to contents

III.3.b. Routers

Coming soon!

Go to top | Go to contents

III.4. Streaming

Coming soon!

Go to top | Go to contents

III.4.a. Connectionless Streaming

Coming soon!

Go to top | Go to contents

III.4.b. Connection-Oriented Streaming

Coming soon!

Go to top | Go to contents

III.4.c. Congestion Control

Coming soon!

Go to top | Go to contents

IV. Streaming Library

Coming soon!

Go to top | Go to contents

IV.1. Application-Layer Multicast

Coming soon!

Go to top | Go to contents

IV.2. On-Demand Streaming

Coming soon!

Go to top | Go to contents

V. Simulation of Large-Scale P2P Streaming

Coming soon!

Go to top | Go to contents

V.1. The Problem

Coming soon!

Go to top | Go to contents

V.2. Implementation Aspects

Coming soon!

Go to top | Go to contents

V.3. Findings

Coming soon!

Go to top | Go to contents

Last updated: December 29, 2010