13 Replies Latest reply on Sep 15, 2011 6:43 PM by ken

    PI SDK - PIValues Performance testing

    benji7

      I'm trying to get some better performance out of PIValues.  I’m not sure if there is something I’m overlooking or if PIValues are just really slow in certain situations.

       

       

       

      I’ve written this short C# console application in VS 2010 using .NET 3.5.  It times how long it takes to iterate through a PIValues collection.  The constants at the top determine which tag is used, the start/end times, and the interval.  A simple for loop is used to increase iterations as desired.

       

       

       

      I tested the below code on my system (a VM using a modern Intel CPU), and it took about 40 seconds for the first timed loop running a debug build in the debugger (default settings in VS2010).

       

       

       

      When iterating through a PIValues array populated from RecordedValues, it’s more than an order of magnitude faster (0.3 seconds) than one populated with Summaries2.  

       

       

       
      static void Main(string[] args)
              {
                  // short code to test the performance of PIValues
                  // Tested on PISDK 1.3.8.388
      
                  try
                  {
                      const string DEFAULT_PI_POINT = "cdt158";
                      const string SUMMARIES2_START_TIME = "*-1d";
                      const string RECORDEDVALUES_START_TIME = "*-7d";
                      const string END_TIME = "*";
                      const string DURATION = "60s";
                      const int MAXCOUNT = 10; // for-loop iterations
      
                      // use default PI Server
                      PISDK.PISDK piSDK = new PISDK.PISDK();
                      Server server = piSDK.Servers.DefaultServer;
                      Console.WriteLine("Connected to PI Server: " + server.Name);
                      Console.WriteLine("Using test PI Point: " + DEFAULT_PI_POINT);
                      Console.WriteLine("Summaries2 Start time: " + SUMMARIES2_START_TIME);
                      Console.WriteLine("RecordedValues Start time: " + RECORDEDVALUES_START_TIME);
                      Console.WriteLine("End time: " + END_TIME);
                      Console.WriteLine("Summaries2 Interval: " + DURATION);
      
                      // choose PI Point
                      PIPoint piPoint = server.PIPoints[DEFAULT_PI_POINT];
      
                      // IPIData2 interface and namedValues storage for filtered values result
                      PISDK.PIData piData = piPoint.Data;
                      PISDK.IPIData2 ipiData2 = (PISDK.IPIData2)piData;
                      PISDKCommon.NamedValues namedValues;
      
                      // summary values
                      namedValues = ipiData2.Summaries2(SUMMARIES2_START_TIME, END_TIME, DURATION, PISDK.ArchiveSummariesTypeConstants.asTotalAndAvg, PISDK.CalculationBasisConstants.cbTimeWeighted);
      
                      // extract "Total" or "Average" from namedValues
                      PIValues piValuesSummaries2 = (PISDK.PIValues)namedValues["Average"].Value;
      
                      PIValues piValuesRecordedValues = piPoint.Data.RecordedValues(RECORDEDVALUES_START_TIME, END_TIME, BoundaryTypeConstants.btInside, string.Empty, FilteredViewConstants.fvShowFilteredState, null);
      
                      if (piValuesSummaries2.Count > 0)
                      {
                          Stopwatch st1 = new Stopwatch(); // StopWatch Start
                          Console.WriteLine("@@@ Iterating Summaries2 collection of " + piValuesSummaries2.Count + " PIValues, looping " + MAXCOUNT + " times.");
                          st1.Start();
      
                          // expensive loop
                          for (int i = 0; i < MAXCOUNT; i++)
                          {
                              foreach (PIValue piValue in piValuesSummaries2)
                              {
                                  // Do useful stuff here. 
                              }
                          }
                          st1.Stop(); // StopWatch End
                          Console.WriteLine("@@@ Elapsed time: " + st1.Elapsed.ToString());
                      }
      
                      if (piValuesRecordedValues.Count > 0)
                      {
                          Stopwatch st2 = new Stopwatch(); // StopWatch Start
                          Console.WriteLine("@@@ Iterating RecordedValues collection of " + piValuesRecordedValues.Count + " PIValues, looping " + MAXCOUNT + " times.");
                          st2.Start();
      
                          // expensive loop
                          for (int i = 0; i < MAXCOUNT; i++)
                          {
                              foreach (PIValue piValue in piValuesRecordedValues)
                              {
                                  // Do useful stuff here. 
                              }
                          }
                          st2.Stop(); // StopWatch End
                          Console.WriteLine("@@@ Elapsed time: " + st2.Elapsed.ToString());
                      }
                  }
                  catch (Exception ex)
                  {
                      Console.WriteLine(ex.Message);
                  }
              }
      

       

        • Re: PI SDK - PIValues Performance testing
          Ahmad Fattahi

          Benji,

           

          It's good to hear from you! How do the numbers of objects in the collections compare to each other? In other words, you are looping through how big of a collection in each case?

           

          Another thing is to see if there is any server calls being made in either loop. I doubt there is any but it may be worth double-checking.

            • Re: PI SDK - PIValues Performance testing
              benji7

              Hi Ahmad,

               

              Below is the output from 1 run on my system. The number of objects may vary on your system, but the relative performance should be pretty consistent.  No server calls exist during the timed section.

               

              If you have a few minutes, could you run the test on your system so that we can compare results?  Just paste the code into a VS2010 C# Console application and add the PISDK reference.

               

              Thanks.

               

              Connected to PI Server: pidev
              Using test PI Point: cdt158
              Summaries2 Start time: *-1d
              RecordedValues Start time: *-7d
              End time: *
              Summaries2 Interval: 60s
              @@@ Iterating Summaries2 collection of 1440 PIValues, looping 10 times.
              @@@ Elapsed time: 00:00:40.6814078
              @@@ Iterating RecordedValues collection of 1720 PIValues, looping 10 times.
              @@@ Elapsed time: 00:00:00.2927190
              

               

                • Re: PI SDK - PIValues Performance testing
                  ken

                  The reason the PIValues collection coming back from the Summaries2 call takes longer to access is that it has a NamedValues collection attached to each value. This is in the ValueAttributes property of the PIValue.

                   

                  For the RecordedValues call, unless you specifically ask for value attributes (like substituted, annotated, annotations, or questionable), nothing is returned from the server and the ValueAttributes collection isn't created on the client.

                   

                  In the case of the Summaries2 call, this collection contains things like: EarliestTime, PercentGood, TimeOfMaxVal, etc. This is described on the help page for IPIData2.Summaries2.

                   

                  As each value of the PIValues collection that came back from the Summaries2 call is instantiated (in the Foreach loop), this NamedValues collection has to be created.

                   

                  In the case of the PIValues collection that came back from the RecordedValues call, there are no attributes, so this collection doesn't have to be created. That improves performance significantly.

                   

                  This is a known issue (PLI 8682OSI8). We have considered offering a Summaries call that doesn't return this extra information (which would improve performance), but there is no schedule as of yet for adding this feature. It would require a change on the Server to allow the specification of which summary attributes are returned.

                   

                  Ken Coates

                    • Re: PI SDK - PIValues Performance testing
                      benji7

                      Ken,

                       

                      =PIAdvCalcDat("cdt158","04-Sep-11 14:25:00","08-Sep-11 14:25:00","1m","average","time-weighted",0,1,193,"pidev")

                       

                      DataLink is able to display calculated values quickly, so there must be a workaround.  The above takes roughly 2 seconds to appear in Excel.

                        • Re: PI SDK - PIValues Performance testing
                          ken

                          The test program above loops through the Summaries PIValues collections 10 times. For your 2 second example in Excel, that would mean 20 seconds total (10 x 2) which is similar to the performance quoted above.

                          • Re: PI SDK - PIValues Performance testing
                            jlakumb

                            I confirmed that PIAdvCalcDat UDF in DataLink is also making a Summaries2 call in PI SDK.  Looks like there is something else going on.  To isolate this, it might be helpful to get a PI SDK trace and check timing of the actual SDK calls.

                              • Re: PI SDK - PIValues Performance testing
                                ken

                                Jay,

                                 

                                As I pointed out, the test program loops 10 times, iterating through the collection each time. So any results we get from DataLink need to be multiplied by 10 to get in the ballpark of the results from the test program.

                                 

                                Ken Coates

                                  • Re: PI SDK - PIValues Performance testing
                                    jlakumb

                                    Thanks, Ken.  I wrote my note before I saw yours (need to remember to refresh the page first next time).

                                     

                                    Benji, in the actual production code, how many tags will you be querying in this call? If it is for a large number (say 1000s), then it is likely the new bulk RPC in PI Server 2012 will be helpful. I just wanted to provide some indication that we are trying to solve this issue (but perhaps in a different way than what is described in PLI 8682OSI8: Allow user to specify what summaries value attribute to return).

                                      • Re: PI SDK - PIValues Performance testing
                                        ken

                                        I've tested the above program with a pre-release version of PI-SDK 1.4.0.413 and the Summaries2 call loop is now 48 times faster than under 1.3.8.388.

                                         

                                        The ratio (Summaries2/RecordedValues) between the two loops went from 125 - 1 to 2.7 - 1.

                                         

                                        So once 1.4.0 is released (soon), there should be a big performance improvement for MTA programs accessing PIValues that have ValueAttributes.

                                         

                                        The reason is that the ValueAttributes collection attached to a PIValue object is now a free threaded version of NamedValues (called MTNVS). The MTNVS emulates the NamedValues collection so you won't have to change your program. Internally it is free threaded so you won't incur the marshaling overhead when you have an MTA program like the C# example above.

                                         

                                        Further, if you are returning PIAnnotations as part of the PIValue in the Value attributes (say in a RecordedValues call), that is also free-threaded.

                                         

                                        Ken Coates

                                         

                                         

                                          • Re: PI SDK - PIValues Performance testing
                                            benji7

                                            I have 1.4.0 411 (Beta 1).  Were the Summaries2 improvements in that build as well?  

                                             

                                            I expect to start testing PI-SDK 1.4.0 with SDK buffering in the next couple weeks.  I can confirm if I see the same sort of performance improvements in Summaries2 that you describe.

                                             

                                            Thanks Ken!

                                             

                                            Jay, I'll have to get back to you regarding the SDK tracing and the quantity of tags we’ll be querying.

                                              • Re: PI SDK - PIValues Performance testing
                                                ken

                                                Hmmm. I didn't realize you were using 1.4.0.411. The improvements (MTNVS) are already in that version.

                                                 

                                                My tests were run on a Windows 7 x64 VM which I thought had more than one processor assigned to it, but I just checked and it only had 1. So my results may not be valid for comparing NamedValues vs. MTNVS performance.

                                                 

                                                Yet, when I run it on my development machine (4 cores) running 1.4.0.413, I get similar results for the ratio between Summaries2 & RecordedValues (3.4 - 1). My output is below.

                                                 

                                                There may be some other improvements in this code with 1.4.0.413 versus 1.4.0.411, so give it a try and see what you get.

                                                 

                                                ----------------------------

                                                 

                                                Connected to PI Server: KenVista
                                                Using test PI Point: cdt158
                                                Summaries2 Start time: *-1d
                                                RecordedValues Start time: *-7d
                                                End time: *
                                                Summaries2 Interval: 60s
                                                Session ID: 1, PINetMgrBuild: 3.4.375.99, Status [0] Success
                                                 got RPC client table. UID is 20940 gen is 12
                                                @@@ Iterating Summaries2 collection of 1440 PIValues, looping 10 times.
                                                @@@ Elapsed time: 00:00:03.1445353
                                                @@@ Iterating RecordedValues collection of 1714 PIValues, looping 10 times.
                                                @@@ Elapsed time: 00:00:00.9005685