Online Forums
Technical support is provided through Support Forums below. Anybody can view them; you need to Register/Login to our site (see links in upper right corner) in order to Post questions. You do not have to be a licensed user of our product.
Please read Rules for forum posts before reporting your issue or asking a question. OPC Labs team is actively monitoring the forums, and replies as soon as possible. Various technical information can also be found in our Knowledge Base. For your convenience, we have also assembled a Frequently Asked Questions page.
Do not use the Contact page for technical issues.
- Forum
- Discussions
- QuickOPC-UA in COM
- Reading, Writing, Subscriptions
- Slow read speed with C/COM client
Slow read speed with C/COM client
We can have a closer look at the "speed per byte payload" at some future point, however it is likely that the main contributing factor is our use of the .NET stack, which we cannot change.
Best regards
Please Log in or Create an account to join the conversation.
- pfp.meijers
- Topic Author
- Offline
- Senior Member
- Posts: 4
- Thank you received: 0
These are measurements from one PC using indicated client stacks to a another PC that runs an open62541 server.
(I tried to attach a picture with a graph showing the measurement results, but then I get an error page when submitting)
Please Log in or Create an account to join the conversation.
Yes, it is quite realistic that you get such results. There are two main reasons:
1) QuickOPC is actually based on the .NET stack, and has a COM layer on top. The other stacks you have tested are probably native C/C++. The .NET is slower.
2) We do some high-level stuff that others don't - the API is actually designed for implied correctness and usability, not for speed. To give you one typical example: You need to specify the full node id, including the namespace (as a string), in each call to EasyUAClient.ReadXXXX method. This makes it easy to write correct programs, because the namespace string is what is stable and should be persisted. Looking up the namespace index each time slows things down. However the other toolkits tend to work with namespace index, which is faster, however the index is internal to the low-level communication, and the server is free to change the namespace index of any namespace with each session. Consequently there are many incorrect clients out there that would misbehave if the server does this. And this is just one example.
The test you have used (with a single 4-byte variable) is actually the most harsh that can be made, and not very realistic. No matter which toolkit you use, you should combine as many nodes as possible into a single call. I believe that if you repeat the measurements with e.g. 1000 nodes in each call, the results will be better for QuickOPC (though probably still not as fast as native C/C++ toolkits).
Best regards
Please Log in or Create an account to join the conversation.
- pfp.meijers
- Topic Author
- Offline
- Senior Member
- Posts: 4
- Thank you received: 0
>open62541Client.exe
43092 transactions, 1.00002 seconds, 4 B/transaction, 0.172365 MB/s, transaction min/avg/max/stddev: 1.72427e-005/2.26865e-005/0.000447488/5.0568e-006 seconds
>uaClient.exe
20400 transactions, 1.00002 seconds, 4 B/transaction, 0.0815985 MB/s, transaction min/avg/max/stddev: 3.85907e-005/4.84989e-005/0.00148862/1.62604e-005 seconds
>qopcClient
2723 transactions, 1.00006 seconds, 4 B/transaction, 0.0108914 MB/s, transaction min/avg/max/stddev: 0.000229492/0.000366861/0.0061158/0.000284175 seconds
They all talk to the same server. Reading a single int32 variable value in a loop during 1 second. The transaction time statistics (durations of the do_ipc() call) are listed.
I added a first dummy transaction in the setup function to cancel out the initial overhead.
For a real application we indeed would use a monitoring approach (push, instead of pull). But for now I use this to measure communication speed of the stack.
Please Log in or Create an account to join the conversation.
And, here are some factors that may influence the performance:
1. First time you read, a connection process must take places. Therefore the first operation can take considerably longer, and that would be normal.
2. How frequently do you call the operation (Read?). If you make a delay longer than a (configurable) "hold period" (default to couple of seconds), EasyUAClient would disconnect, and then the connection process (under #1 above) would have to take place again, making it slower.
3. The default read parameters (an object that can be passed to the ReadXXXX method) specify a max age of 1 second. This means that the server must obtain each value form the device if it does not have a "fresh enough" value, younger than 1 second. This, of course, can take time - this depends on the server, the protocol etc. The max age can be changed from your side.
Note that any periodic reads of the same tags over and over are not a good idea in OPC world, performance-wise. Such read loop is better replaced by a subscription.
Best regards
Please Log in or Create an account to join the conversation.
- pfp.meijers
- Topic Author
- Offline
- Senior Member
- Posts: 4
- Thank you received: 0
For some reason it is much slower than expected.
Maybe I am doing something fundamentally wrong?
See code below.
The setup_ipc() function is called once and next the do_ipc() function is called in a loop many times, measuring its duration. The ipc.h file contains global variables such as server, port, variable name, array size/count, etc. which are set by the application.
#include <stdio.h>
#include <tchar.h>
#include <sstream>
using namespace std;
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
#include <atlbase.h>
#include <atlstr.h>
#include <atlsafe.h>
#import "libid:BED7F4EA-1A96-11D2-8F08-00A0C9A6186D" // mscorlib
using namespace mscorlib;
#import "libid:ecf2e77d-3a90-4fb8-b0e2-f529f0cae9c9" // OpcLabs.BaseLib
using namespace OpcLabs_BaseLib;
#import "libid:E900F89A-5ED5-4E71-8E2C-D006DA67975C" // OpcLabs.BaseLibExtensions
using namespace OpcLabs_BaseLibExtensions;
#import "libid:3b7714a0-a5e9-4b81-b663-d6faa9030ba8" // OpcLabs.EasyOpcUAInternal
using namespace OpcLabs_EasyOpcUAInternal;
#import "libid:E15CAAE0-617E-49C6-BB42-B521F9DF3983" // OpcLabs.EasyOpcUA
using namespace OpcLabs_EasyOpcUA;
extern "C"
{
#include "ipc.h"
}
static CComSafeArray<VARIANT> arguments(array_count);
static _EasyUAClientPtr client;
extern void setup_ipc()
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
client = _EasyUAClientPtr(__uuidof(EasyUAClient));
stringstream s;
s << "opc.tcp://" << server_address << ":" << port_nr;
string server_url(s.str());
s.str("");
s << "ns=" << namespace_index << ";s=";
if(variable_name == NULL || variable_name[0] == '\0')
{ s << "var" << array_size;
}
else
{ s << variable_name;
}
string node_id(s.str());
for (int i = 0; i < array_count; i++)
{ _UAReadArgumentsPtr readArg(_uuidof(UAReadArguments));
readArg->EndpointDescriptor->UrlString = server_url.c_str();
readArg->NodeDescriptor->NodeId->ExpandedText = node_id.c_str();
arguments.SetAt(i, _variant_t((IDispatch*)readArg));
}
}
extern void cleanup_ipc()
{
CoUninitialize();
}
extern int do_ipc(int measuring)
{
LPSAFEARRAY pArguments = arguments.Detach();
CComSafeArray<VARIANT> results = client->ReadMultipleValues(&pArguments);
arguments.Attach(pArguments);
if(verbose)
{ for(int i = results.GetLowerBound(); i <= results.GetUpperBound(); i++)
{ _ValueResultPtr valueResult = results[i];
_variant_t variant = valueResult->value;
VARIANT* pVariant = &variant;
if(array_size == 1)
{ int val = pVariant->lVal;
printf("%d\n", val);
}
else
{ SAFEARRAY* pArray = (SAFEARRAY*)(pVariant->parray);
int* val = (int*)(pArray->pvData);
for(int j = 0; j < array_size; j++)
{ printf("%d ", val[j]);
}
printf("\n");
}
}
}
return 1;
}
Please Log in or Create an account to join the conversation.
- pfp.meijers
- Topic Author
- Offline
- Senior Member
- Posts: 4
- Thank you received: 0
Please Log in or Create an account to join the conversation.
- Forum
- Discussions
- QuickOPC-UA in COM
- Reading, Writing, Subscriptions
- Slow read speed with C/COM client