DynamicCastExperiment

Experiment to implement the transaction polymorphism

Introduction

Each master may need (or know) a different protocol. In the case more then one master is connected to the same multiport target, there must be a way to use different types of transactions from each master.

TLM WG proposes the concept of extensions to implement the different types. But this concept have more then one way to implement. One of them is (1) to use the original object-oriented way to deal with multiple types in run-time (dynamic_cast in a hierarchy of classes). The other is (2) to do a static C++ type check, trying to avoid the cost of dynamic_cast.

We expected that (2) would be faster then (1), because dynamic_cast was taken as a slow operation. But the results of this experiment shows the contrary. Dynamic cast is really the better way to implement it.

The "valid bit" experiment (2)

The problem with (2) is that each master may use a different transaction struct but slave must receive always the same type. So, one way to do it is making the slave receive a super-set (union) of attributes used by both masters and masters setting which attributes are in use using a "valid bit".

A transaction type can be defined by just inheriting required and optional attributes. The code to define a protocol is like this:

  1. class MAddr;
  2. class MData;
  3. class MLock;
  4.  
  5. // protocol used by initiator
  6. class lock_transaction: public required<MAddr>, public required<MData>, optional<MLock> {};

Master should fill the attributes they want but also set the "valid bit". The valid bit is set when the attribute is extracted from the transaction with the function set_valid<ATTRIBUTE>(TRANSACTION). Slaves should only extract the attribute from the transaction when this attribute exists in the transaction and when it has its valid bit set. Using the function get_attribute<ATTRIBUTE>(TRANSACTION). For example:

  1. //in the master
  2. MLock* mylock = set_valid<MLock>(trans1);
  3. mylock->lock = true;
  4.  
  5. //in the slave
  6. if (MLock* mylock = get_attribute<MLock>(trans1) {
  7.    //process attribute mylock, as it exist and was set by master
  8. }

The dynamic_cast experiment (1)

This experiment used the plain old polymorphism technique.

Benchmarks

A loop of 10 million times sending a transaction from one master to one slave took, for each experiment:

(1) 16.70s

(2) 27.79s

Source code

[[[media:wiki/pages/GreenBus(2f)Design(2f)DynamicCastExperiment/attachments/benchmark---DYNAMIC_CAST_MANY_TYPES.tgz|benchmark---DYNAMIC_CAST_MANY_TYPES.tgz]]Experiment (1)]

[[[media:wiki/pages/GreenBus(2f)Design(2f)DynamicCastExperiment/attachments/benchmark---VALID_BIT_MANY_TYPES.tgz|benchmark---VALID_BIT_MANY_TYPES.tgz]]Experiment (2)]

NOTE: Tests run with output redirected to /dev/null