Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse Titan » Advanced TTCN-3 usage: working with record of structures when performance matters(In theory performance does not matter, in practice it does)
Advanced TTCN-3 usage: working with record of structures when performance matters [message #1735889] Thu, 23 June 2016 12:56 Go to next message
Kristof Szabados is currently offline Kristof SzabadosFriend
Messages: 60
Registered: July 2015
Member
In theory the performance of tests might not matter, but in practice it does.
For this reason let me share with you some information, that you can use to improve the internal quality of your TTCN-3 tests.

Lets take a look at 2 very common usages of the record of structure in TTCN-3: inserting elements and removing elements.

1)
In theory it does not matter in what order a record of structure is filled in.
So the below 2 functions should have the same performance.
The first function always adds 1 million elements to a record of, always extending it by 1; the second function adds the same 1 million elements, but inserting them from the back.

private const integer cg_limit := 1000 * 1000;
private type record of integer ROI;

private function f_push_FrontToBack(inout ROI pl_roi) {
  for ( var integer vl_i := 0; vl_i < cg_limit ; vl_i := vl_i+1 )
  {
    pl_roi[vl_i] := 1;
  }
}

private function f_push_BackToFront(inout ROI pl_roi) {
  for ( var integer vl_i := cg_limit; vl_i >= 0 ; vl_i := vl_i-1 )
  {
    pl_roi[vl_i] := 1;
  }
}


If you measure how these functions execute you will see very different performance profiles: the second function will be almost instantaneous compared to the first.

The reason:
When the second function assigns the first item to the 1 millionth position, TITAN allocates enough memory for storing 1 million elements. Further assignments will only copy the value to its final position, but there will be no memory allocation.
When the first function assigns the first value TITAN allocates memory for only one element. When the second and subsequent values are assigned, TITAN has to allocate a bigger memory region + move all existing stored values there + assign the new value ... operations much more expensive than the first solution.

If you do not know how much data you will have, use the first version to grow with your needs.
But if you can ave an estimate on the amount of data needed, use the second version as it is much faster.

/* in deeper detail: TITAN actually uses the realloc command to allocate the new memory region upon change, so most of the time the values are actually not moved. */
Re: Advanced TTCN-3 usage: working with record of structures when performance matters [message #1735906 is a reply to message #1735889] Thu, 23 June 2016 13:34 Go to previous message
Kristof Szabados is currently offline Kristof SzabadosFriend
Messages: 60
Registered: July 2015
Member
2)
In theory it also does not matter how you remove an element from a record of structure.

So the following 4 ways to remove an element should have the same properties:
private const integer cg_limit := 10 * 1000;
private type record of integer ROI;

private function f_popFromFront(
  inout ROI pl_roi )
return integer
{
  var ROI vl_roi := {};
  var integer vl_result;
  for ( var integer vl_i := 0; vl_i < sizeof(pl_roi) ; vl_i := vl_i+1 )
  {
    if (vl_i == 0) {
      vl_result := pl_roi[vl_i];
    } else {
      vl_roi[vl_i - 1] := pl_roi[vl_i];
    }
  }
  
  pl_roi := vl_roi;
  return vl_result;
}

private function f_popFromFront2(
  inout ROI pl_roi )
return integer
{
  var ROI vl_roi := {};
  var integer vl_result := pl_roi[0];
  var integer vl_size_of := sizeof(pl_roi)-1;
  for ( var integer vl_i := vl_size_of; vl_i > 0 ; vl_i := vl_i-1 )
  {
      vl_roi[vl_i - 1] := pl_roi[vl_i];
  }
  
  pl_roi := vl_roi;
  return vl_result;
}

private function f_popFromFront3(
  inout ROI pl_roi )
return integer
{
  var integer vl_result := pl_roi[0];
  var ROI vl_empty := {};

  pl_roi := replace(pl_roi, 0, 1, vl_empty);

  return vl_result;
}

private function f_popFromBack(
  inout ROI pl_roi )
return integer
{
  var integer vl_size := sizeof(pl_roi) - 1;
  var integer vl_result := pl_roi[vl_size];
  var ROI vl_empty := {};

  pl_roi := replace(pl_roi, vl_size, 1, vl_empty);

  return vl_result;
}


The first version removes the first element + copies all subsequent elements using conditional branching in a loop into a temporal variable to their shifted location + copies the temporal variable back to the parameter + returns with the originally first element.
The second version improves on this by not using conditional branching within the loop.
The third version simply saves the first element + replaces it with an empty record of (deleting the 0th element).
The final, 4th version saves and replaces the last element in the record of structure.

All 4 version solves the same problem (if you wish to implement a stack, they pop 1 element from it).
Yet they have very different performance.
On the machine I use currently:
- f_popFromFront takes around 18 sec.
- f_popFromFront2 takes around 11sec.
- f_popFromFront3 takes around 8 sec.
- f_popFromBack takes around 8 sec.
(before executing each I fill op the record of with 10*1000 1-s)

And they also have very different complexity characteristics.
While it takes some time to figure out what the first 2 versions do, it is easy to see that the last 2 versions basically call a built in function and thats it.
Previous Topic:Ignore any unsolicited message
Next Topic:Problem with JUnitLogger: unexpected AST node
Goto Forum:
  


Current Time: Fri Apr 26 19:45:08 GMT 2024

Powered by FUDForum. Page generated in 0.03920 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top