10 Replies Latest reply on Mar 16, 2015 3:28 PM by Arco

    Best coding pattern for interface with other service (PI SDK)

    Arco

      Hello all,

       

      I was wondering what is the best coding pattern for my case.

      We have written an interface between a system and PI using the PI SDK.

      We have problems with the performance and are reviewing our code to see if we can optimize it.

      What are we doing ?

      First we load about 2300 PI Points with a certain pointsource into a dictionary. The key of the dictionary items ist the instrumenttag of the PI Point.

      We are doing that so on the way back to PI we can find the corresponding PI Point easily.

      We register ourselves with the other service with a list of instrument tags. After that we become value changes as events from the other system.

      There can be about 500 to 1000 events per second. These events are added to a .NET BlockingCollection.

      Another process is reading from this BlockingColletion in a parallel foreach loop. The value of the instrumenttag is used to find the corresponding PI Point in the dictionary.

      Then the value of the PI Point is updated.

      This mechanism has worked fine for months but since our servers (VMWare) are moved to another ESX host the above mentioned service has delays when writing to the buffer subsystem.

      Ofcourse we are looking to all the variables and trying to optimize the code is one of them.

      Does anyone have any ideas of a better approach to this use case?

      Any help would be appreciated.


      Arco Stolk


        • Re: Best coding pattern for interface with other service (PI SDK)
          dng

          Hi Arco,

           

          Let's first identify the bottleneck of the above process. When you mentioned that the service has "delays when writing to the buffer subsystem", how were the delays measured and where were the delays? Did you see delays between the time when the events occurred in the other system to the time it reaches the PI buffer subsystem? Or were there delays further upstream? Also, what kind of delays are we looking at (seconds, minutes)?

           

          Based on the information so far, the only difference with your service (from the time when it was working fine) is that the service was moved to another host. Perhaps a good place to start would be looking at the differences between the two server. Are system resources different on this host? Is network latency greater from your other system to this new host?

           

          If we can identify the bottleneck in the current configuration, we will be able to give better suggestions on how to improve the application.

          • Re: Best coding pattern for interface with other service (PI SDK)
            bshang

            Hi Arco,

             

            I agree with Daphne that the bottleneck needs to be characterized. Some questions I have are:

            1) Which machines were moved? Interface, PI server, or both?

            2) Were there any changes in the physical locations or networks among the different machines (data source, interface, server)?

            3) Is the delay during startup, real-time operation, or both?

            4) Is it possible to introduce some instrumentation/tracing into the existing app? Outputting the timing for certain method calls can determine the bottleneck.

             

            I think it would be helpful to get an idea of what changed when the servers were moved, as that will help narrow down the issues.

            • Re: Best coding pattern for interface with other service (PI SDK)
              Arco

              Hi Daphny, Barry,

               

              thanks for thinking with me.

              Our team of VM Ware experts are trying to find out what is wrong on a server level.

              I, as a developer, would like to know if my coded solution is a valid way to write updates on PI Points.

              Yes, my code worked fine for almost a year, but maybe I was lucky because the old environment was performant.

              With the help of tracing I pinpointed the delays happening on the UpdateValue of a PI Point.

               

              I load a Dictionary<string, PIPoint> with 2300 PI Points. The key of the dictionary is the Location5 field.

              I register these PI Points to the other service. After that I get value changes for these points, 500 to a 1000 a second.

              These value changes are loaded into a BlockingCollection which I process like this:

               

                           Parallel.ForEach(this.optisek2PIQueue.GetConsumingPartitioner(), po, currentItem =>

                          {

                              PIPoint outputTag;

                              bool available = PIPointsDictionary.TryGetValue(item.PVID, out outputTag);

               

                              if (available)

                              {

                                  var value = ConvertDoubleString(item.Value);

                                  var timestamp = TimeConversion.optiSekTime2DateTime(item.Timestamp);

                                  log.Debug(outputTag.Name + "," + item.PVID + "," + value.ToString() + "," + timestamp.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss fff"));

                                  outputTag.Data.UpdateValue(value, Convert.ToDouble(item.Timestamp, Culture), DataMergeConstants.dmReplaceDuplicates);

                                  log.Debug(outputTag.Name + "," + item.PVID + "," + value.ToString() + "," + timestamp.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss fff"));

                              }

                         });

               

              I can see all value changes of the other system are written into the BlockingCollection in milliseconds.

              When I outcomment the line of code where I update the PI Point I can see the value updates from the other system are processed in the for each loop in the same millisecond so that does not seem to be the problem.

              The updatevalue shows delays. Not always, but often. The delays can grow to minutes.

               

              I have read somewhere that the PI SDK is not multithreaded enabled. Is that so? What would be a better solution?

              Would using the AF SDK be a better solution?

                • Re: Best coding pattern for interface with other service (PI SDK)
                  xwang

                  Hi Aroc,

                   

                  How about add the argument about AsyncStatus please?  If you have read the menu of PI SDK, there is an optoinal argument for PI AsynchStatus object.  Could you please try that to test if there are still delay report from updatevalue() function?

                   

                  Xi Wang

                  PI Developer Club

                    • Re: Best coding pattern for interface with other service (PI SDK)
                      Arco

                      Hi Xi Wang,

                       

                      according to the PI SDK helpfile I have here this PIAsyncStatus is "Not Implemented; if used, this parameter is ignored.".

                      I use version 1.4.4.484 of the PI SDK.

                       

                      Arco

                        • Re: Best coding pattern for interface with other service (PI SDK)
                          xwang

                          Hi Aroc,

                           

                          Oh, this is a bad news...  I believe you have known the problem should be caused by many connections to PI Server in a short time range.  As you know, each UpdataValue() will consume one connection.  Therefore, how do you think to use UpdataValues() please?  To use this function, you have to create a PIValues object to record some PIValue object.  This method could reduce the connection number to PI Server, as you could send many PI Values at one time.

                           

                          Xi Wang

                          PI Developer Club

                            • Re: Best coding pattern for interface with other service (PI SDK)
                              Arco

                              Hi Xi Wang,

                               

                              using UpdateValues is no option. I cannot collect the data for a PI Point and write on a later moment.

                              It is important that value updates are written a soon as possible, preferably in the same second.

                               

                              Arco

                                • Re: Best coding pattern for interface with other service (PI SDK)
                                  xwang

                                  Hi Arco,

                                   

                                  It is very hard to confirm this real time value archived in PI Server actually.  However, how do you think my method following please?

                                  1. make a scan frenquency for all of your PI tags, like 1 second or 2 seconds

                                  2. let your program to get the data for these PI tags with the scan frenquency

                                  3. let your program to tranlsate the data to PIValue object with the timestamp for the data generated

                                  4. Packed those PIValue objects to PIValues, and use UpdataValues() method to update the value to PI Server

                                   

                                  Though it will be some delay for one or two seconds, I think this should be the best function for your goal.

                                   

                                  Xi Wang

                                  PI Developer Club

                          • Re: Best coding pattern for interface with other service (PI SDK)
                            dng

                            Hi Arco,

                             

                            To answer your question about multi-threading in PI SDK vs. AF SDK, I would like to first point you a few resources:

                            • In the PI SDK help file, search for "thread" and you will find a detailed discussion of threading in PI SDK.
                            • There is a white paper named "Optimizing your PI SDK Application" (available here). There are sections on asynchronous calls and using multi-threading in PI SDK.

                            In a nutshell, PI SDK is COM-based and most objects are instantiated in STA. COM dictates that an object in an STA can only execute on one thread (STAs have thread affinity). Calls from other threads must be marshaled to the object's STA, and thread marshaling involves overhead. There could also be issues with thread safety. For building a .NET application, we definitely recommend using AF SDK over PI SDK. AF SDK is .NET-based, and all our new development effort will focus on AF SDK (PI SDK will be maintained but not be actively developed on).

                             

                            Also, check out this previous thread for performance gain when switching over the AF SDK:

                             

                            EDIT: Looking at your issue a little more, are you spawning a new thread for each data write? 500 - 1000 a second? If so, does a bulk write solution as Xi proposed (even per second or a few times a second) help?

                            In addition, is each data getting written in parallel to the PI Data Archive? You might get a lot of out-or-order events then. (Note that this should only affect the archiving rate on the PI Data Archive (not UpdateValue), just bringing it up for discussion.)