Professional OPC
Development Tools

logos

OPC Read/Write issues in VS2005 C++

More
05 Dec 2011 08:01 #683 by support
Hello, thanks for the measurements. I know what is happening.
What is taking the most time (2.5 seconds) are basically process context switches and data marshalling between your application and EasyOPC process. This happens every time you access objects from EasyOPC. For example, obtaining a properly-typed interface from a VARIANT, accessing a property (such as Exception or Vtq or Value) etc. There is nothing wrong with your code - it was our conscious decision to design the interfaces in this way. In COM automation, about the only more effective way would be to return directly arrays of the actual things you need, so that would make an array of values, array of timestamps, array of qualities, array of error codes, array of message texts etc. That is possible but gives a terribly looking code.
Fortunately, you can eliminate the above process context switches by using to in-process EasyOPC. To do so, open the EasyOPC Options Utility, and on the System Parameters tab, uncheck "Local server" and check "In-process server".
The downside of the in-process component is that in some environments and situations, it is difficult to achieve a shutdown that is properly coordinated with the host. Hopefully, since you are in C++, this should not be a blocking problem.
Regards

Please Log in or Create an account to join the conversation.

More
04 Dec 2011 13:22 #680 by p.bangert
I did more careful timings. The single lineCComVariant vResults(EasyDAClientPtr->ReadMultipleItems(machine.c_str(), server.c_str(), CComVariant(LPSAFEARRAY(*ItemInArray)), vMissing));takes about 1.5 seconds each subsequent time. The following code takes another 2.5 seconds each timefor(i = ResultArray.GetLowerBound(0); i < ResultArray.GetUpperBound(0); ++i){ IDAVtqResultPtr DAVtqResultPtr(ResultArray); if(DAVtqResultPtr->Exception == NULL) { IDAVtqPtr DAVtqPtr(DAVtqResultPtr->Vtq); value = (float) DAVtqPtr->Value.dblVal; } else { ICOMExceptionPtr COMExceptionPtr = DAVtqResultPtr->Exception; _tprintf(_T("%d: failure: %s\n"), i, COLE2T(COMExceptionPtr->Message)); }}so it seems that the actual reading time concurs with yours given that my network adds some overhead. However getting the result out of the data structure is expensive. Am I doing something wrong? I should note that the number of exceptions is low, so that the part in the else clause does not matter much.The OPC Server that I'm connecting to is part of a package called RecordData, which is an internal developement of a power provider in Germany, so it is not a standard commercial OPC server. I will try to do it with subscriptions and see how far I get.

Please Log in or Create an account to join the conversation.

More
02 Dec 2011 09:33 #676 by support
I made a test with 1000 items, using our simulation server, locally. The time to read these 1000 items (on subsequent reads) is around 1 second. Doing this over network, and with server that may (or may not) have lower performance, is therefore likely to give a time that is considerably higher than 1 second.
I understand that you are looking for better performance, so I plan to do more tests in order to see whether this can be improved further, in a hope that if they help with my test, they may be beneficial to your situation, too.
I know that your network is fast; have you, however, made a test where the OPC server and OPC client are both on the same machine, so that we have trusted information about whether the bottleneck has to do with the communication, or something else (performance of the client or the server)?
Can you please tell me which OPC server are you connecting to? I find it hard to believe that it does not support subscriptions. It would be very unusual (and clearly not compliant with OPC); in addition, I think that the server must at least "pretend" that it does support them, because we are calling functions that are related to subscriptions, and if they were failing, you would be getting error messages.
As you know, repeated reads are inefficient, so I am trying to figure out why we cannot go "the right way". The expected sustained throughput with subscriptions (locally) can be 4000 changes per second or more.
Instantiating unnecessary objects inside the loop is not particularly good, but I do not think it has a substantial influence in this case. I still suggest that you move the creation of EasyDAClient object outside the loop. I suppose that the times you are giving are just for the read method call (these other things should not be significant anyway, but should be ruled out in the timing nevertheless).

Please Log in or Create an account to join the conversation.

More
01 Dec 2011 09:26 #673 by p.bangert
Thank you for your helpful suggestions.Ad 1. I made those changes and it did not improve. The times are the same as before. The very first time that I start my program, the first read loop takes about 16 seconds, after that the loop takes about 4 seconds. However when I then start my program a second time, even the first loop execution takes about 4 seconds and then remains at that level ...Ad 2. Using your method, I retrieved an error. It occurs particularly with 2 of my over 1000 items and says: "Topic not updated for the first time (timeout)."Ad 3. Using your example, the writing operation now writes. Thank you.With regard to the timing problem, could it be related to having to instantiate various object on every execution of the loop, e.g. the IEasyDAClientPtr or the CComSafeArray ResultArray among several others?

Please Log in or Create an account to join the conversation.

More
01 Dec 2011 08:11 #672 by support
Hello.
Ad 1. I am assuming that those 4.2 seconds are for 2nd and subsequent invocations of the method (the first invocation causes various startup tasks and can take longer than subsequent ones). If all invocations take so long, there might be various reasons for this. I do not want to enumerate them all here, so let's start with one, and if that is not the reason, we will continue investigating deeper. Please start by doing this experiment: Run the EasyOPC Utility, and on the OPC-DA Globals tab, under Client Parameters, change "Trocessing interval timeouts" from 50 to 150, and change "Topic processing total timeout" from 1000 to 5000. These are tunings that could help the performance with larger number of items. After making this change, press OK, and make sure that the EasyOPC process is not running (easyopcl.exe in Task Manager), so that when you start your application, it gets a chance to pick up the new values. Please repeat your measurements then and let me know the results.
Ad 2. The code in ReadMultipleItems example is not complete with regard to error handling. The proper approach would be to test the DAVtqResultPtr->Exception for null-ness. Only if it is NULL, the DAVtqResultPtr->Vtq is valid and can be accessed. If the Exception is not null, obtain IComException interface from it, and handle it, using fields such as Message and HResult. You will see an example of it in the example I will send for point 3 below. I will need to know the details of that exception (Message, HResult, ...) in order to tell you more about what is happening.
Ad 3. Please see this thread: www.opclabs.com/Support/Online ... for example that writes multiple values and works.
Best regards

Please Log in or Create an account to join the conversation.

More
30 Nov 2011 16:29 #670 by p.bangert
Hi there,I am new to both DCOM, OPC and QuickOPC development ... so I apologize in advance for trivialities. My task is to read several values from an OPC server, to do some processing and to write some values back to the same server. This loop is repeated every few seconds essentially forever.For development I am using C++ in VS2005, so I started with the example called Examples\CPP\VS2008\Win32\ReadMultipleItems. After some initial troubles, I can compile and run this and it works. However, I'm having three issues at a second look ...1. I looped the code in that example's main function to read 1027 items each time. It takes 4.2 seconds to execute on each loop. The OPC server is on another machine but the network is fast. Is this normal? What can I do to hurry this up? I would like to do it in under 1 second. One point may be to declare the various members somewhere outside but I am not familiar enough with DCOM to do this and have it still work ... help?2. The function "->Vtq" on line 37 of that example rarely but sometimes fails returning an exception in debug mode. No text is output just a FAILED macro returns an opc_issue exception ... what can I do? How can these errors be caught and nicely dealt with?3. I attempted to rewrite the same example to do writing ... I failed. Basically, I have an array of doubles that I have to write out. The conversion of that to VARIANT and so on is something that I probably messed up. I'm trying to use the function ReadMultipleItemValues and this crashes. Can someone show how to convert an array of doubles to the right VARIANT array that will work with this function.Basically what I am looking for is the ReadMultipleItems example broken into two bits - initialization of everything and the core suitable for looping - and then also extended for writing an array of values and possibly for error checking.Btw, the OPCserver I have to link to does not support subscribing to values, so I really must poll them all on every loop ...Thank you very much!

Please Log in or Create an account to join the conversation.

Moderators: support
Time to create page: 0.183 seconds

      

 Recommend this on Google