Avatar

Please consider registering
guest

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

— Forum Scope —




— Match —





— Forum Options —





Minimum search word length is 3 characters - maximum search word length is 84 characters

sp_Feed Topic RSS sp_TopicIcon
TriggerEvent performance
January 27, 2021
0:32, EET
Avatar
Xavier
Member
Members
Forum Posts: 43
Member Since:
March 26, 2014
sp_UserOfflineSmall Offline

Hi,

I have my own Alarm Type extending AlarmConditionTypeNode (type created with UaModeler and code generated with the SDK 4.4.2), and I notice that when I call super.triggerEvent(time, receiveTime, userEventId); it takes most of the time 125ms (between 110 and 200 ms). I can multithread the call to be a bit better, but still it can take several minutes to trigger 5 000 alarms.

It’s not new with the SDK 4.4 but it was not just a big issue for me before Wink.

With the sample console server, “my alarm” has not this issue. Do you know what could be done to improve this or if I have a way to override this method to be more efficient even if less generic?

Thanks

Here is the log for one triggerEvent lasting 187 ms. The debug log level is enabled for the EventData class, it seems that’s where half the time is lost (I don’t know where the remaining time is spent):

00:15:37.153 EventData: node=NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2, NodeClass=Object, BrowseName=2:ALARM-VARIABLE_08750_FORMULA_2; Type={NodeId=ns=2;i=1040, NodeClass=ObjectType, BrowseName=2:MyAlarmMultiThresholdType, IsAbstract=false}
00:15:37.153 addPropertyFields: node=2:ALARM-VARIABLE_08750_FORMULA_2; properties=[NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:ConditionClassId, NodeClass=Variable, BrowseName=ConditionClassId; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=17, NodeClass=DataType, BrowseName=NodeId, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=(null), statusCode=GOOD (0x00000000) "", sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:EventId, NodeClass=Variable, BrowseName=EventId; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=15, NodeClass=DataType, BrowseName=ByteString, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=[16] 0x000000000000036c000000000000036b, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:15:37.1530000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:15:37.1530000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:Time, NodeClass=Variable, BrowseName=Time; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=294, NodeClass=DataType, BrowseName=UtcTime, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=01/26/21 23:15:37.1530000 GMT, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:15:37.1530000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:15:37.1530000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:SuppressedOrShelved, NodeClass=Variable, BrowseName=SuppressedOrShelved; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=1, NodeClass=DataType, BrowseName=Boolean, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=(null), statusCode=GOOD (0x00000000) "", sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:EventType, NodeClass=Variable, BrowseName=EventType; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=17, NodeClass=DataType, BrowseName=NodeId, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=ns=2;i=1040, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:SourceNode, NodeClass=Variable, BrowseName=SourceNode; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=17, NodeClass=DataType, BrowseName=NodeId, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=i=2253, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:Severity, NodeClass=Variable, BrowseName=Severity; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=5, NodeClass=DataType, BrowseName=UInt16, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=0, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:15:37.1530000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:15:37.1530000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:InputNode, NodeClass=Variable, BrowseName=InputNode; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=17, NodeClass=DataType, BrowseName=NodeId, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=i=0, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:Retain, NodeClass=Variable, BrowseName=Retain; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=1, NodeClass=DataType, BrowseName=Boolean, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=true, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:15:37.1530000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:15:37.1530000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:Message, NodeClass=Variable, BrowseName=Message; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=21, NodeClass=DataType, BrowseName=LocalizedText, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=() Un message d’alarme, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:ClientUserId, NodeClass=Variable, BrowseName=ClientUserId; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=12, NodeClass=DataType, BrowseName=String, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=(null), statusCode=BAD (0x80000000) "", sourceTimestamp=01/26/21 23:15:37.1530000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:15:37.1530000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:BranchId, NodeClass=Variable, BrowseName=BranchId; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=17, NodeClass=DataType, BrowseName=NodeId, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=(null), statusCode=GOOD (0x00000000) "", sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:ReceiveTime, NodeClass=Variable, BrowseName=ReceiveTime; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=294, NodeClass=DataType, BrowseName=UtcTime, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=01/26/21 23:13:24.6750000 GMT, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:15:37.1530000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:15:37.1530000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:ConditionClassName, NodeClass=Variable, BrowseName=ConditionClassName; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=21, NodeClass=DataType, BrowseName=LocalizedText, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=(null), statusCode=GOOD (0x00000000) "", sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:SourceName, NodeClass=Variable, BrowseName=SourceName; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=12, NodeClass=DataType, BrowseName=String, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=Server, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:ConditionName, NodeClass=Variable, BrowseName=ConditionName; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=12, NodeClass=DataType, BrowseName=String, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=ALARM-VARIABLE_08750_FORMULA_2, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0)]
00:15:37.153 basePath=null
00:15:37.153 browsePath=[ConditionClassId]; v=null
00:15:37.153 browsePath=[EventId]; v=[16] 0x000000000000036c000000000000036b
00:15:37.153 browsePath=[Time]; v=01/26/21 23:15:37.1530000 GMT
00:15:37.153 browsePath=[SuppressedOrShelved]; v=null
00:15:37.153 browsePath=[EventType]; v=ns=2;i=1040
00:15:37.153 browsePath=[SourceNode]; v=i=2253
00:15:37.153 browsePath=[Severity]; v=0
00:15:37.153 browsePath=[InputNode]; v=i=0
00:15:37.153 browsePath=[Retain]; v=true
00:15:37.153 browsePath=[Message]; v=() Un message d’alarme
00:15:37.153 browsePath=[ClientUserId]; v=null
00:15:37.153 browsePath=[BranchId]; v=null
00:15:37.153 browsePath=[ReceiveTime]; v=01/26/21 23:13:24.6750000 GMT
00:15:37.153 browsePath=[ConditionClassName]; v=null
00:15:37.153 browsePath=[SourceName]; v=Server
00:15:37.153 browsePath=[ConditionName]; v=ALARM-VARIABLE_08750_FORMULA_2
00:15:37.153 addComponentFields: components=[UaReference: ReferenceTypeId=i=47 SourceId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2 TargetId=i=9027 ReferenceType=HasComponent SourceNode=2:ALARM-VARIABLE_08750_FORMULA_2 TargetNode=Enable, UaReference: ReferenceTypeId=i=47 SourceId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2 TargetId=i=9028 ReferenceType=HasComponent SourceNode=2:ALARM-VARIABLE_08750_FORMULA_2 TargetNode=Disable, UaReference: ReferenceTypeId=i=47 SourceId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2 TargetId=i=9029 ReferenceType=HasComponent SourceNode=2:ALARM-VARIABLE_08750_FORMULA_2 TargetNode=AddComment, UaReference: ReferenceTypeId=i=47 SourceId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2 TargetId=i=9111 ReferenceType=HasComponent SourceNode=2:ALARM-VARIABLE_08750_FORMULA_2 TargetNode=Acknowledge, UaReference: ReferenceTypeId=i=47 SourceId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2 TargetId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:AckedState ReferenceType=HasComponent SourceNode=2:ALARM-VARIABLE_08750_FORMULA_2 TargetNode=AckedState, UaReference: ReferenceTypeId=i=47 SourceId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2 TargetId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:ActiveState ReferenceType=HasComponent SourceNode=2:ALARM-VARIABLE_08750_FORMULA_2 TargetNode=ActiveState, UaReference: ReferenceTypeId=i=47 SourceId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2 TargetId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:Comment ReferenceType=HasComponent SourceNode=2:ALARM-VARIABLE_08750_FORMULA_2 TargetNode=Comment, UaReference: ReferenceTypeId=i=47 SourceId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2 TargetId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:EnabledState ReferenceType=HasComponent SourceNode=2:ALARM-VARIABLE_08750_FORMULA_2 TargetNode=EnabledState, UaReference: ReferenceTypeId=i=47 SourceId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2 TargetId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:LastSeverity ReferenceType=HasComponent SourceNode=2:ALARM-VARIABLE_08750_FORMULA_2 TargetNode=LastSeverity, UaReference: ReferenceTypeId=i=47 SourceId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2 TargetId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:Quality ReferenceType=HasComponent SourceNode=2:ALARM-VARIABLE_08750_FORMULA_2 TargetNode=Quality, UaReference: ReferenceTypeId=i=47 SourceId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2 TargetId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.2:AlarmProperties ReferenceType=HasComponent SourceNode=2:ALARM-VARIABLE_08750_FORMULA_2 TargetNode=2:AlarmProperties]
00:15:37.153 addPropertyFields: node=Enable; properties=null
00:15:37.153 basePath=[Enable]
00:15:37.184 addComponentFields: components=[]
00:15:37.184 addPropertyFields: node=Disable; properties=null
00:15:37.184 basePath=[Disable]
00:15:37.215 addComponentFields: components=[]
00:15:37.215 addPropertyFields: node=AddComment; properties=[NodeId=i=9030, NodeClass=Variable, BrowseName=InputArguments; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=296, NodeClass=DataType, BrowseName=Argument, IsAbstract=false, ValueRank=1ArrayDImensions=[0], MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=[Argument [Name="EventId", DataType="i=15", ValueRank="-1", ArrayDimensions="[]", Description="() The identifier for the event to comment."], Argument [Name="Comment", DataType="i=21", ValueRank="-1", ArrayDimensions="[]", Description="() The comment to add to the condition."]], statusCode=GOOD (0x00000000) "", sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)]
00:15:37.215 basePath=[AddComment]
00:15:37.215 browsePath=[AddComment, InputArguments]; v=[Argument [Name="EventId", DataType="i=15", ValueRank="-1", ArrayDimensions="[]", Description="() The identifier for the event to comment."], Argument [Name="Comment", DataType="i=21", ValueRank="-1", ArrayDimensions="[]", Description="() The comment to add to the condition."]]
00:15:37.231 addComponentFields: components=[]
00:15:37.231 addPropertyFields: node=Acknowledge; properties=[NodeId=i=9112, NodeClass=Variable, BrowseName=InputArguments; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=296, NodeClass=DataType, BrowseName=Argument, IsAbstract=false, ValueRank=1ArrayDImensions=[0], MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=[Argument [Name="EventId", DataType="i=15", ValueRank="-1", ArrayDimensions="[]", Description="() The identifier for the event to comment."], Argument [Name="Comment", DataType="i=21", ValueRank="-1", ArrayDimensions="[]", Description="() The comment to add to the condition."]], statusCode=GOOD (0x00000000) "", sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)]
00:15:37.231 basePath=[Acknowledge]
00:15:37.231 browsePath=[Acknowledge, InputArguments]; v=[Argument [Name="EventId", DataType="i=15", ValueRank="-1", ArrayDimensions="[]", Description="() The identifier for the event to comment."], Argument [Name="Comment", DataType="i=21", ValueRank="-1", ArrayDimensions="[]", Description="() The comment to add to the condition."]]
00:15:37.262 addComponentFields: components=[]
00:15:37.262 addPropertyFields: node=AckedState; properties=[NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:AckedState.0:FalseState, NodeClass=Variable, BrowseName=FalseState; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=21, NodeClass=DataType, BrowseName=LocalizedText, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=-1,000000, AccessLevel=3, UserAccessLevel=3, Historizing=false, Value=DataValue(value=() Unacknowledged, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:AckedState.0:TrueState, NodeClass=Variable, BrowseName=TrueState; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=21, NodeClass=DataType, BrowseName=LocalizedText, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=-1,000000, AccessLevel=3, UserAccessLevel=3, Historizing=false, Value=DataValue(value=() Acknowledged, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:AckedState.0:Id, NodeClass=Variable, BrowseName=Id; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=1, NodeClass=DataType, BrowseName=Boolean, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=false, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0)]
00:15:37.262 basePath=[AckedState]
00:15:37.262 browsePath=[AckedState, FalseState]; v=() Unacknowledged
00:15:37.262 browsePath=[AckedState, TrueState]; v=() Acknowledged
00:15:37.262 browsePath=[AckedState, Id]; v=false
00:15:37.262 addComponentFields: components=[]
00:15:37.262 addPropertyFields: node=ActiveState; properties=[NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:ActiveState.0:FalseState, NodeClass=Variable, BrowseName=FalseState; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=21, NodeClass=DataType, BrowseName=LocalizedText, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=-1,000000, AccessLevel=3, UserAccessLevel=3, Historizing=false, Value=DataValue(value=() Inactive, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:ActiveState.0:TrueState, NodeClass=Variable, BrowseName=TrueState; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=21, NodeClass=DataType, BrowseName=LocalizedText, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=-1,000000, AccessLevel=3, UserAccessLevel=3, Historizing=false, Value=DataValue(value=() Active, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:ActiveState.0:Id, NodeClass=Variable, BrowseName=Id; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=1, NodeClass=DataType, BrowseName=Boolean, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=true, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:15:37.1530000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:15:37.1530000 GMT, serverPicoseconds=0)]
00:15:37.262 basePath=[ActiveState]
00:15:37.262 browsePath=[ActiveState, FalseState]; v=() Inactive
00:15:37.262 browsePath=[ActiveState, TrueState]; v=() Active
00:15:37.262 browsePath=[ActiveState, Id]; v=true
00:15:37.262 addComponentFields: components=[]
00:15:37.262 addPropertyFields: node=Comment; properties=[NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:Comment.0:SourceTimestamp, NodeClass=Variable, BrowseName=SourceTimestamp; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=294, NodeClass=DataType, BrowseName=UtcTime, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=(null), statusCode=GOOD (0x00000000) "", sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)]
00:15:37.262 basePath=[Comment]
00:15:37.262 browsePath=[Comment, SourceTimestamp]; v=null
00:15:37.262 addComponentFields: components=[]
00:15:37.262 addPropertyFields: node=EnabledState; properties=[NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:EnabledState.0:FalseState, NodeClass=Variable, BrowseName=FalseState; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=21, NodeClass=DataType, BrowseName=LocalizedText, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=-1,000000, AccessLevel=3, UserAccessLevel=3, Historizing=false, Value=DataValue(value=() Disabled, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:EnabledState.0:TrueState, NodeClass=Variable, BrowseName=TrueState; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=21, NodeClass=DataType, BrowseName=LocalizedText, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=-1,000000, AccessLevel=3, UserAccessLevel=3, Historizing=false, Value=DataValue(value=() Enabled, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0), NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:EnabledState.0:Id, NodeClass=Variable, BrowseName=Id; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=1, NodeClass=DataType, BrowseName=Boolean, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=true, statusCode=GOOD (0x00000000) "", sourceTimestamp=01/26/21 23:13:08.7740000 GMT, sourcePicoseconds=0, serverTimestamp=01/26/21 23:13:08.7740000 GMT, serverPicoseconds=0)]
00:15:37.262 basePath=[EnabledState]
00:15:37.262 browsePath=[EnabledState, FalseState]; v=() Disabled
00:15:37.262 browsePath=[EnabledState, TrueState]; v=() Enabled
00:15:37.262 browsePath=[EnabledState, Id]; v=true
00:15:37.262 addComponentFields: components=[]
00:15:37.262 addPropertyFields: node=LastSeverity; properties=[NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:LastSeverity.0:SourceTimestamp, NodeClass=Variable, BrowseName=SourceTimestamp; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=294, NodeClass=DataType, BrowseName=UtcTime, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=(null), statusCode=GOOD (0x00000000) "", sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)]
00:15:37.262 basePath=[LastSeverity]
00:15:37.262 browsePath=[LastSeverity, SourceTimestamp]; v=null
00:15:37.262 addComponentFields: components=[]
00:15:37.262 addPropertyFields: node=Quality; properties=[NodeId=ns=2;s=INTERNAL.VARIABLE_08750_FORMULA_2.Datatype.ALARM-VARIABLE_08750_FORMULA_2.0:Quality.0:SourceTimestamp, NodeClass=Variable, BrowseName=SourceTimestamp; Type={NodeId=i=68, NodeClass=VariableType, BrowseName=PropertyType, IsAbstract=false, DataType=i=24, ValueRank=-2, ArrayDimensions=null, Value=(null)} DataType=NodeId=i=294, NodeClass=DataType, BrowseName=UtcTime, IsAbstract=false, ValueRank=-1, MinimumSamplingInterval=0,000000, AccessLevel=1, UserAccessLevel=3, Historizing=false, Value=DataValue(value=(null), statusCode=GOOD (0x00000000) "", sourceTimestamp=null, sourcePicoseconds=0, serverTimestamp=null, serverPicoseconds=0)]
00:15:37.262 basePath=[Quality]
00:15:37.262 browsePath=[Quality, SourceTimestamp]; v=null
00:15:37.262 addComponentFields: components=[]
00:15:37.262 addPropertyFields: node=2:AlarmProperties; properties=null
00:15:37.262 basePath=[2:AlarmProperties]
00:15:37.262 addComponentFields: components=[]
00:15:37.262 getFieldValue return:ns=2;i=1040
00:15:37.262 EventData: eventTypeId=ns=2;i=1040
00:15:37.340 WARN 10224 — [alarm-pool-0] f.c.a.s.s.node.MyAlarmTypeNode : Trigger duration: 187
January 27, 2021
11:29, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Hi,

Uh oh. That sounds a lot (I guess for both the number of alarms you are sending, but also for the time it takes). Though, events also have to do alot of steps per the specification. So a possible outcome can also be that it is somewhat the best the SDK 4.x can do. We have lately received multiple questions etc. regarding events, thus hopefully we can do something to help their usage (+improve performance).

When you say the MyAlarm in the samples has not had this issue, you mean that you can trigger that 5000 times and it wont take that long (or did you mean something else?). Because then I would look for differences (see below about things to look for).

Also what is sort of your expected performance here i.e. how much in which time you would like to send the events?

The main 3-4 steps that need to happen when making an event.

0. Creating the event (node). For Alarms this is already done since it exists in the address space (there are some special cases that might require new instances, but I’ll skip that), but since the alarms are quite complex types, this might take time in general.
1. Creating the EventData, this is the raw data of a possible event to be sent to a client
2. Propagating the EventData for all nodes in the event chain hierarchy upto the Server node (from which you can get all events)
3. For each MonitoredEventItem made to the nodes of 2. would evaluate the EventData vs. their client-defined EventFilter

1. Recursively traverses the full forward-hierarchical-references BrowsePaths (basically HasComponent, HasProperty) from the triggering node, thus the more you have of those the longer it goes in the current implementation. The 3. EventFilter is defined using the BrowsePaths. Does your own type have a lot more of these and/or is the sub-node-structure more deep? Also look for any… weird HasComponent references (e.g. theoretically if you would make a HasComponent to .. unrelated part of the address space having let’s say 100k nodes, it would also fetch the data of those)

2. We must recursive find all parent nodes for inverse HasEventSource/HasNotifier/HasCondition references and fire the event to those, if you have a long-object-chain of these it can take longer.

3. Each MonitoredEventItem listens on the UaNode (if there is one) for the events of 2. and evaluates the EventData per the WhereClause of the EventFilter. While normally I would assume clients to not do anything odd, the filter is .. maybe not exactly Turing complete itself but can get absurdly complicated if-else-statemachine if so desired (see e.g. https://reference.opcfoundation.org/v104/Core/docs/Part4/B.1.2/; the WhereClause is a ContentFilter instance). So check if a client is using anything complicated (like, most likely not, but is something I would still check).

Thus to improve performance I would say:
A)
We hopefully could improve each part internally, but some of these might require changes that can be only done if we jump to version 5.x (I like have some ideas, but each have some set of limitations, e.g. IF the whole address space, or at least related parts were only-immutable-updateable, we might be able to use the data as-is somehow better). Also I guess a future SDK could be smarter about 1. if it would know all EventFilters that could be relevant to the node (since it sort of doesn’t make sense to even fetch their data I think).

B)
Maybe you could somehow be able to skip e.g. step 2. Skipping step 1. is somewhat impossible, unless you have the data somewhere more easily accessible. As far as I’m aware in either case, you would need to handle step 3. manually by keeping track of all MonitoredEventItems (the same way the MyBigNodeManager keeps track of MonitoredDataItems and notifies them of new data) and then push the EventData there directly. Note that in this case you would need to also handle any possible event propagation manually. Also please note that if you attempt this, use the constructor of EventData that takes in the NodeId, since the UaNode one would do the recursive searching of all components and properties.

Preferably still we would get the performance increase directly to the SDK, since all of these are more complicated solutions.

Additionally do note that any one-shot Events (i.e. those that are not ConditionType subtypes) must be done with the createEvent method of the NodeManagerUaNode and then triggered OR manually deleted after making an EventData of it manually (The one-shot events are in the address space technically until triggered so that our set/get/nodeget codegen methods work; if it would not be deleted it would leak memory, but the triggerEvent knows to delete non-ConditionType events automatically).

I can try to profile if there is anything easy to be gained on the short term.

Let us know if any of that helped.

January 27, 2021
14:12, EET
Avatar
Jouni Aro
Moderator
Moderators
Forum Posts: 1009
Member Since:
December 21, 2011
sp_UserOfflineSmall Offline

Hi Xavier,

At least during the EventData creation, I can see several 30 ms pauses in the log. Is your application having high load for other threads? This could explain the difference between the SampleConsoleServer (which doesn’t do much) and yours.

The rest of the time goes to delivering the EventData for all MonitoredItems that are listening to the events as Bjarne explained. And that, of course takes longer the more items there are listening to the events. How many client connections do you have and are they all monitoring events?

Jouni

January 27, 2021
16:55, EET
Avatar
Xavier
Member
Members
Forum Posts: 43
Member Since:
March 26, 2014
sp_UserOfflineSmall Offline

Hi,

Thanks to your detailed answers and the source code I have some new elements:
– With EventData at DEBUG log level, even with the console server it takes 80ms, so I removed this log level,
– The performance is directly related to the size of my address space: if I test with a small configuration the time is way lower (probably why the sample console server is ok),
– The duration of “new EventData” and of “fireEvent” both increases when my addressSpace is bigger
– For my test I already use an alarm that just subclass the standard one without adding new properties.
– The test are done without any client connected: there should be no subscription BUT there are some internal listeners in the server (addEventListener).

I will continue to dig, I have to check my notification chain as explained by Bjarne and also to verify that during the new EventData there is no strange things.

Jouni, I think the gap of 15/30 ms in the logs is due to Windows where sometimes the clock only jumps by this amount, but not really sure…

January 27, 2021
17:55, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

If you did not add any new Components or Properties to your event type, my first impressions would be that EventData construction time should stay the same. So that is a bit odd. Would this issue also occur if you just use the standard type? That is to ask, does subtyping have any impact? If not it makes testing easier.

Can you please check do you increase the number of nodes anywhere where inverse HasEventSource, HasNotifier, HasCondition references (the event propagation) would be traversed? For example do you get to a node that way that would have like 1k, 10k or 100+k References?

SDK currently stores the HasProperty targets in a ConcurrentHashMap, since for them the BrowseName can be a key. All other References are stored in a ConcurrentSkipListSet, with the current reasoning having been that it sorts the references. Also it might be complicated to have a key (since BrowseNames are not unique, ReferenceTypes must be searchable by inheritance rules etc.) and a Map takes more memory, thus that is what it is. Though we seem to have one issue marked down that that collection can be slow under some conditions, which could happen here.

January 28, 2021
0:41, EET
Avatar
Xavier
Member
Members
Forum Posts: 43
Member Since:
March 26, 2014
sp_UserOfflineSmall Offline

For the first part, about EventData, I found out that the issue seems to be related to the method: enable, disable, acknowledge and addComment.
In EventData => addComponentFields => node.getReferences(Identifiers.HasComponent, false); when node is a method this call returns an empty array but I suspect that as (I believe) each alarm instance has a reference to the method in the Type Definition node the list of references can be huge.

In my current test I have 30 000 alarms and EventData takes around 30-40ms. I just added a check if node is a method to return immediatly and now it takes < 1 ms, I don’t know if this can have side effects.

The remaining of the time is spent as expected in the "fireEvent" method and the calls to "fireEventInParents".
For you question, my address space looks like this in my current test:

A folder type node with 1 HasNotifier with its children (total: 2 references)
– Object type A #1 with 1 HasEventSource with each child (total: 10k references)
— 10k objects type B with 1 HasCondition with its alarm (total: 1 reference for each instance)
—- 1 alarm for each object of type B
– Object type A #2 with 1 HasComponent + 1 HasEventSource with its children (total: 20k of each type of references)
— 20k objects type B with 1 HasEventSource with each child (total: 10k references)
—- 1 alarm for each object of type B

I made a test by removing my HasEventSource references and the whole trigger function now takes < 1 ms, I will try tomorrow with my real application.
But this means I have no way to subscribe easily to all the alarms under "Object type A #1"?

January 28, 2021
12:09, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Oh. That would explain it hopefully.

I guess in theory an EventFilter could target a component that would be under a Method node in some crazy custom type. Probably would not make much sense though, since the components/properties of a Method should be related to the calling the method and thus stateless. I’ll have to check, but I think we probably can make some optimization (that maybe could be turned of with a flag just in case).

In the meantime..

Do you use NodeManagerUaNode.createInstance() to make the alarm nodes? If yes you could try as a workaround to construct the NodeBuilderConfiguration of that to be TypeDefinitionBasedNodeBuilderConfiguration.builder(MethodInstantiationLogic.UNIQUE).build() (unless you have your own configurations). Then we should be making unique Method instances instead of the (default) shared instances. Normally making unique doesn’t make that much sense, but e.g. it might if different exec rigths are needed in different instances of an alarm (thus why this option exist, but also why by default it is shared).

I think the HasEventSources must be there per the specification, but lets see if the above fixes it at least temporarily so their removal does not need to be considered. Or is it still too slow just with the EventData creation “fixes”?

January 28, 2021
15:16, EET
Avatar
Xavier
Member
Members
Forum Posts: 43
Member Since:
March 26, 2014
sp_UserOfflineSmall Offline

I think with the EventData “fix” it’s enough, because for the other part I think I can always find another way to get the alarms without having the whole hierarchy.

I use createInstance, I will let you know if it also works to just change the builder configuration but do you think it will use more memory?

January 28, 2021
15:37, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Yes, since it would make new instances instead of refering to the Method node in the type (so ~3 nodes more per a Method per the type). Hopefully that would not be of too much problem, but let us know how it goes.

It would also be possible to make a bit more complicated TypeDefinitionBaseNodeBuilderConfiguration that doesn’t do it for all Methods but just Alarm based ones. In that case the base InstantiationStrategy to use would be the DefaultInstantiationStrategy by passing the same UNIQUE enum constant to it’s constructor and the in the TypeDefinitionBaseNodeBuilderConfiguration.Builder that woiuld be set for the relevant BrowsePaths (though, I think at the moment we have a limitation that it can only check 1-lvl deep paths so that might not work for every case, can explain more later as it would be quite lengthy topic).

I do see the need for the SDK to be more flexible on how the Attribute+Reference data is stored, but that probable requires some major updates. Hopefully some of them can provide better balance of CPU vs Memory usage, or maybe even letting SDK users to chose which one to prefer..

Filtering out Method nodes (or well, most likely it is better to just instead take only Object+Variable nodes) for EventData can probably be done to the next update (though needs some checking of the specification + testing to be sure).

January 28, 2021
16:55, EET
Avatar
Xavier
Member
Members
Forum Posts: 43
Member Since:
March 26, 2014
sp_UserOfflineSmall Offline

I tested with TypeDefinitionBasedNodeBuilderConfiguration.builder(MethodInstantiationLogic.UNIQUE).build() and it works well without having to modify the EventData class.

It doesn’t seem to have a big impact on memory 🙂

For me it’s okay this way.

February 1, 2021
10:26, EET
Avatar
Xavier
Member
Members
Forum Posts: 43
Member Since:
March 26, 2014
sp_UserOfflineSmall Offline

Hi,

Just a little side effect, when using the ‘TypeDefinitionBasedNodeBuilderConfiguration.builder(MethodInstantiationLogic.UNIQUE).build()’, with UaExpert I have an error when calling acknowledge from their Event View. But calling the acknowledge method directly on an alarm node works.
Log: ‘Call Acknowledge on Condition ‘NS2|String|MyAlarmNodeId’ returned BadMethodInvalid’

February 2, 2021
13:42, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Hi,

Uh oh, sorry, I think I forgot that edge-case, but I think this is the first time I’m aware it being a problem. Though that only can happen if the defaults are not used so it sort of masked this. I guess this could be categorized either as SDK bug or unimplemented support for a feature of OPC UA. Or alternatively that the specification conflict with itself. I guess I should ask the OPC Foundation for clarifications..

So once again this ended up being somewhat long explanation..

The Call Service definition in the current version allows Methods from the types be used directly, https://reference.opcfoundation.org/v104/Core/docs/Part4/5.11.2/ (for the objectId)
“In case of an Object the Object or the ObjectType of the Object or a super type of that ObjectType shall be the source of a HasComponent Reference (or subtype of HasComponent Reference) to the Method specified in methodId.” and for the methodId:
” NodeId of the Method to invoke.
If the objectId is the NodeId of an Object, it is allowed to use the NodeId of a Method that is the target of a HasComponent Reference from the ObjectType of the Object.”

However, the definition of the Methods itself in part 3 define (the way I see it) object-oriented-language-like distinction between static and non-static methods, https://reference.opcfoundation.org/v104/Core/docs/Part3/4.7/
“Methods are “lightweight” functions, whose scope is bounded by an owning (see Note) Object, similar to the methods of a class in object-oriented programming or an owning ObjectType, similar to static methods of a class. Methods are invoked by a client, proceed to completion on the Server and return the result to the client. The lifetime of the Method’s invocation instance begins when the client calls the Method and ends when the result is returned.

NOTE The owning Object or ObjectType is specified in the service call when invoking the Method.

Clients discover the Methods supported by a Server by browsing for the owning Objects References that identify their supported Methods.”

The way I see it, in my personal opinion, that the text added by the Foundation to the Part 4 Call description (in OPC UA 1.02 or 1.03 I think) contradict the Part 3 defintion of Methods. Method is either a static or not, it cannot be both (either ObjectType or Object nodes are used as objectId, both cannot be used for the same method). Though that being said, at least in Java it is possible (but gives warnings and doesn’t make sense) to call a static method via an java-object instance), so maybe that was what is intended. Or maybe the specification is worded like this to allow the Nano embedded profiles which might not have enough resources to have a Types section in the address space or something…

Anyway, I think we’ll do the EventData filtering fix (by default skip others than Object/Variable nodes for calculating the data) and then figure out a bit later what else to do. This way the UNIQUE option is not needed thus it eliminates this problem (since only shared instances are done, thus it wont matter).

Any opinions, suggestions or comments?

February 2, 2021
14:55, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

I made a mantis issue of this https://apps.opcfoundation.org/mantis/view.php?id=6453 (requires credentials, which might not be obtainable by everyone, not sure), but serves as a reference point for those who can see it.

February 2, 2021
23:54, EET
Avatar
Xavier
Member
Members
Forum Posts: 43
Member Since:
March 26, 2014
sp_UserOfflineSmall Offline

Thank you for the detailed answer. The issue with UaExpert is not really important to me, but I’m fine with using the UNIQUE trick at the moment and will switch once the EventData is faster 🙂

Forum Timezone: Europe/Helsinki

Most Users Ever Online: 518

Currently Online:
28 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

hbrackel: 135

pramanj: 86

Francesco Zambon: 81

rocket science: 77

ibrahim: 76

Sabari: 62

kapsl: 57

gjevremovic: 49

Xavier: 43

fred: 41

Member Stats:

Guest Posters: 0

Members: 680

Moderators: 16

Admins: 1

Forum Stats:

Groups: 3

Forums: 15

Topics: 1467

Posts: 6260

Newest Members:

sagarchau, elviralangwell4, Donnavek, Eddiefauth, DonaldPooma, fidelduke938316, Jan-Pfizer, DavidROunc, fen.pang@woodside.com, aytule

Moderators: Jouni Aro: 1009, Otso Palonen: 32, Tuomas Hiltunen: 5, Pyry: 1, Petri: 0, Bjarne Boström: 983, Heikki Tahvanainen: 402, Jukka Asikainen: 1, moldzh08: 0, Jimmy Ni: 26, Teppo Uimonen: 21, Markus Johansson: 42, Niklas Nurminen: 0, Matti Siponen: 321, Lusetti: 0, Ari-Pekka Soikkeli: 5

Administrators: admin: 1