What is the overhead of using SLProtocolExt instead of SLProtocol? Since SLProtocolExt is superset of SLProtocol, object of type ConcreteSLProtocolExt is naturally larger then ConcreteSLProtocol. How big of an performance impact is this and what are the cases where this overhead needs to be considered?
Once decision is made to use SLProtocolExt instead of SLProtocol, does number of QActions that use SLProtocolExt matter, or does every QAction use the same instance of ConcreteSLProtocolExt, which gets instantiated on the call to the first QAction that needs it? More generally does new ConcreteSLProtocol object get instantiated for every call to QAction?
Hi,
The overhead of SLProtocolExt is that all parameter types are added on the memory heap, these need to be constructed first, and for somebody that needs to debug an SLScripting memory dump it will be harder for them to dig through all the items: imagine if a protocol.xml has 5000 parameters that somebody that is checking the heap sees these 5000 items next to the basic types like string, int,...
Every QAction has their own SLProtocol object, this is not shared. A perfect example of this is the protocol.GetTriggerParameter() call, when all QActions would be using the same SLProtocol object then the result of this call would be the same for every QAction. Further, a new SLProtocol object gets instantiated at every QAction run.
To summarize: using SLProtocol over SLProtocolExt is preferred, specially when the SLProtocolExt members are not being used, as SLProtocol is faster to load when starting a QAction and will not take up as much space on the heap in memory.
[Edit]: summary after taking a deeper look (see comments):SLProtocolExt is a 'relatively' small performance hit in most cases and its fine to use if it's for readability and you actually use its features.
So if using the SLProtocolExt functionality is preferred then feel free to do so, but it’s a pity to define SLProtocolExt and then only use a basic GetParameter or SetParameter call that an SLProtocol object also offers. Executing one protocol.SetParameters call is also still preferred over multiple protocol.SetParameter calls, which does not happen when assigning values to single parameters when using SLProtocolExt.
Regards,
When looking at the interface description of SLProtocolExt under https://docs.dataminer.services/develop/api/types/Skyline.DataMiner.Scripting.SLProtocolExt.html , there is written: suppose a protocol defines a table with name “Overview”, then the ProtocolExt interface will contain the following property:
public interface SLProtocolExt : SLProtocol
{
public OverviewQActionTable overview {get; set; };
}
The “OverviewQActionTable” is a new (class) type, similar like there are string or int types. Such a type will become visible on the heap.
Single parameters will be of the object type, so not their own type, but will have their own setter-getter implementation that will need to be generated and will be properties of the SLProtocolExt interface and class implementation.
The SLProtocolExt provides a more readable way of coding, but when having for example
protocol.First = 1; // Sets the value of the read parameter with name “First”.
protocol.Second = 2;
Then in this case it is more readable, but is not performant because 2 protocol.SetParameter (inter-process) calls need to happen in the background. It’s better to combine this into one protocol.SetParameters(new int[Parameter.First, Parameter.Second], new object[1,2]); call. That one is performant and makes use of the available “Parameter” class and does not need SLProtocolExt but can perfectly work with the SLProtocol object.
Hi Laurens. I’m actually not sure if extra memory is being allocated when using SLProtocolExt (for parameters). When looking at the implementation, it seems that all properties are implemented as methods, without backing field.
Example:
/// PID: 39 | Type: read
public System.Object Requestpatch {get { return GetParameter(39); }set { SetParameter(39, value); }}
Only for tables a small object is being allocated. The impact of these object is likely very small, and will never cause performance problems in practice. Personally I prefer more readable code over such micro-optimizations.
I took a deeper dive into the memory heap. For single parameters there is indeed no backing field because the get and set call methods in the background. For table parameters there is a backing field of the type Skyline.DataMiner.Scripting.QActionTable that contains 3 properties (at this moment): link back to the SLProtocol object, tableId integer and tableName string. For one element this might not seem much, but when looking at a memory dump of SLScripting at a production setup there are a lot of tables across all elements on a DMA and those are a lot of objects that we are seeing on the memory heap. If using the SLProtocolExt functionality is preferred then feel free to do so, but it’s a pity to define SLProtocolExt and then only use a basic GetParameter or SetParameter call that an SLProtocol object also offers. Executing one protocol.SetParameters call is also still preferred over multiple protocol.SetParameter calls, which does not happen when assigning values to single parameters when using SLProtocolExt.
Hi Laurens,
Thank you for the explanation. The part I don’t understand is “all parameter types” and “5000 items next to the basic types like string, int”. Does this mean that every parameter gets it’s own type in SLScripting? When I take a look at QAction_Helper all parameters are defined as of type “object”, but I guess it is possible that they are just boxed.