17 Replies Latest reply on May 12, 2011 10:41 AM by andreas

    Asynchronous Summaries

    andreas

      *** this thread is the continuation of this other discussion thread, where the solution was to perform Summary calls in Asynchronously rather than Synchronously***

       

      Dan,

       

      there is a tremendous performance improvement of asynchronous operations versus synchronous operations, especially if you have to connect to the PI Server remotely. Personally I observed improvements in the range of 2x to 10x by running many asynchronous summaries in parallel versus synchronous summaries in a series.

       

      Think about that - if you have 100 summaries to calculate, in a synchronous world you send the first calculation, wait for the response, send the next calculation and so on. At the end you have waited 100 times for the round trip plus a single thread did all the work on the PI Server. In an asynchronous world you send the 100 calculations to the PI server, wait for the answer and get the result - so you did not wait for the 100 round trips and many threads did work on the PI Server for you. By running multiple asynchronous calls you take advantage of multi threading on the PI Server without you having to deal with a multi threaded PI SDK application.

       

      Hope this helps

        • Re: Asynchronous Summaries
          jnissisolutions

          Andreas,

           

          Yes, I will attempt asynchronous calls.  There are a few things that I am a bit concerned about in coding it up...

           

          1.) overwhelming the server....  I will have 1000s of ExpressionSummaries calculation calls... Each call is calculating a formula based on a 1hr and 15min time interval for a longer time period (on the average 2 months). 

           

          2.) orderly capture of the results... When each calculation is completed, I need to do further processing with each specific result.  I haven't thought through the best way to capture which async call (thread) completed first to continue with the rest of that specific process sequence.  Any suggestions?

           

          3.) error processing... each asynchronous call will need to catch the same type of exceptions I would normally.

           

          Dan

            • Re: Asynchronous Summaries
              andreas

              Hi Dan,

               

              actually in a first step I would not go for "real" asynchronous processing, e.g. sending the calculations and waiting for the event in a callback.

               

              The simplest aproach would be looping through all your summaries, sending bunches of ~50 (this is most likely hardware specific - but in my tests the performance and the load on the server did not improve with larger bunches) summaries to the server and wait until they are done, send the next bunch and so one. So you will already take advantage of the asynch calls while you do not have so much code changes. Here is an example to illustrate:

              Dim _nvsSum(iMaxtags) As PISDKCommon.NamedValues
              Dim _ipiD2 As PISDK.IPIData2

              For i = 0 To _PointList.Count - 1

                  _PIPoint(i) = _PointList.Item(i + 1)
                  _PIAsynchStatus(i) = New PISDKCommon.PIAsynchStatus

                  Try
                      
              _ipiD2 = _PIPoint(i).Data
                      _nvsSum(i) = _ipiD2.Summaries2(strStartTime, _
                               strEndTime, _
                               "", _
                               PISDK.ArchiveSummariesTypeConstants.asTotal, _
                               PISDK.CalculationBasisConstants.cbEventWeightedIncludeBothEnds, _
                               _PIAsynchStatus(i))
                  Catch ex As Exception
                      MsgBox(ex.ToString, MsgBoxStyle.Information, _PIPoint(i).Name)
                      Return
                  
              EndTry

                  j = (i + 1) Mod iAsyncGroup

                  If (j = 0) Or (i = _PointList.Count - 1) Then
                      
              For k = i + 1 - iAsyncGroup To i
                          Do
                          LoopWhile _PIAsynchStatus(k).ProgressPercent < 100
                      Next
                  
              EndIf

              Next

              Dim _PIValues As PISDK.PIValues

              For i = 0 To _PointList.Count - 1
                  _PIValues = _nvsSum(i)("Total").Value
                  v = v + _PIValues(1).Value
              Next

              Hope this helps,

            • Re: Asynchronous Summaries
              jnissisolutions

              Andreas,

               

              I got a chance to code this up and it is working fine.  I am having some problems though between each bundle that is processed.  Some of the post processing of each item requires another call to the PISDK.  So in general the process is...

               

              Run through all items

               

                    Bundle up 50

               

                    Process the 50 asynch

               

                    Wait for the 50 to be complete

               

                    Process each result set.

               

              Within that result set, an individual lookup using the statement

               

                  piCalcVals = piCalcVal.TimedCalculate(piTimes, checkExpression, piasync);

               

                  where piTimes = object[1] with a PITime in it.  checkExpression is a string = "BadVal('tagname'). piasync = null

               

              This works many time for other occurances before a specific one that stops it each time.  At first I thought it was a problem with the tag at that point in time, but the tag is available.  I'm not sure what to make of it.  The error message is...

               

              Failed to retrieve events from server [-10722] PINET: Timeout on PI RPC or System Call

               

              This really has me spinning.  Prior to coding this up for asynch, the same call worked for all the tags involved.

               

              Thanks,

               

              Dan

               

                          

                • Re: Asynchronous Summaries
                  cescamilla

                  I see you are mixing calles to async and sync calls, there is a chance that the sync call is locking out async executions, so, mixing those two is not recommended. Have you tried doing this completely async?

                   

                  Also, please check on the PI SMT the connections under Network Manager Statistics and then select PINetMgr.

                   

                  ---

                   

                  EDIT: I just checked and stand corrected, async calls will NOT be blocked by sync calls.

                  • Re: Asynchronous Summaries
                    andreas

                    Dan,

                     

                    I have not encountered such an issue. I tried the following code

                    if (_i == MyAsyncCalls - 1)
                    {
                        //_paAsync[_i] = new PISDKCommon.PIAsynchStatus();
                        _paAsync[_i] = null;
                    }
                    else
                    {
                        _paAsync[_i] = new PISDKCommon.PIAsynchStatus();
                        //_paAsync[_i] = null;
                    }
                    try
                    {
                        _piNdVals[_i] = _IPICalc.ExpressionSummaries(_dtStart,
                                      _dtEnd,
                                      "",
                                      "'" + _PIPt.Name + "' + 'CDT158'",
                                      PISDK.ArchiveSummariesTypeConstants.asAverage,
                                      PISDK.CalculationBasisConstants.cbTimeWeighted,
                                      PISDK.SampleTypeConstants.stRecordedValues,
                                      "",
                                      _paAsync[_i]);
                    }

                     

                    to mix syn and async calls - this works fine so far. Could you do some adjustments on the PI SDK timeouts to see if that changes something? Does it always happen for the same tag?

                     

                    regards,

                      • Re: Asynchronous Summaries
                        cescamilla

                        Dan, could you post your code? specifically the parts where you are doing the async calls and the sync call. :)

                          • Re: Asynchronous Summaries
                            jnissisolutions

                             

                             

                            Cristobal,

                            Sorry about the delay... Time away.  Here is the code for the async calls...

                                                    PISDKCommon.PIAsynchStatus[] piQtrStatus = new PISDKCommon.PIAsynchStatus[processPickUp.Count];
                                                    PISDKCommon.PIAsynchStatus[] piHrStatus = new PISDKCommon.PIAsynchStatus[processPickUp.Count];

                                                    int qtrCount = 0;
                                                    int hrCount = 0;
                                                    foreach (PeakProcItem peakProcItem in processPickUp)
                                                    {
                                                        try
                                                        {
                                                            startTime.LocalDate = peakProcItem.startDateBundle;
                                                            endTime.LocalDate = peakProcItem.endDateBundle;

                                                            piQtrStatus[qtrCount] = new PISDKCommon.PIAsynchStatus();
                                                            peakProcItem.maxNamedQtr = piCalcVal2.ExpressionSummaries(startTime, endTime,
                                                            null, peakProcItem.formulaQTR, PISDK.ArchiveSummariesTypeConstants.asMaximum,
                                                            PISDK.CalculationBasisConstants.cbTimeWeightedContinuous,
                                                            PISDK.SampleTypeConstants.stInterval, "15m", piQtrStatus[qtrCount]);
                                                            qtrCount++;
                                                        }
                                                        catch (Exception ex)
                                                        {
                                                            //MessageBox.Show(ex.Message,"ERROR");
                                                        }

                                                        try
                                                        {
                                                            piHrStatus[hrCount] = new PISDKCommon.PIAsynchStatus();
                                                            peakProcItem.maxNamedHr = piCalcVal2.ExpressionSummaries(startTime, endTime,
                                                            null, peakProcItem.formulaHR, PISDK.ArchiveSummariesTypeConstants.asMaximum,
                                                            PISDK.CalculationBasisConstants.cbTimeWeightedContinuous,
                                                            PISDK.SampleTypeConstants.stInterval, "1h", piHrStatus[hrCount]);
                                                            hrCount++;
                                                        }
                                                        catch (Exception ex)
                                                        {
                                                            //MessageBox.Show(ex.Message, "ERROR");
                                                        }
                                                    }

                                                    for (int j = 0; j < qtrCount; j++)
                                                    {
                                                        while (piQtrStatus[j].ProgressPercent < 100) ;
                                                    }
                                                    for (int j = 0; j < hrCount; j++)
                                                    {
                                                        while (piHrStatus[j].ProgressPercent < 100) ;
                                                    }

                                                    foreach (PeakProcItem peakProcItem in processPickUp)
                                                    {
                                                        peakProcItem.processPeakItem();
                                                    }

                                                    foreach (PeakProcItem peakProcItem in processPickUp)
                                                    {
                                                        processBundle(peakProcItem);
                                                    }
                                                }

                            During the processBundle method, a call to this method occurs...

                                    private Double? calcVar(String varTag, DateTime findDate)
                                    {
                                        Double? retVal = null;
                                        DateTime oldDate = new DateTime(1901, 1, 1);
                                        if (findDate < oldDate) return retVal;
                                        string findTime = findDate.ToString("dd-MMM-yy HH:mm:ss");
                                        PITimeServer.PITime findPITime = new PITimeServer.PITime();
                                        findPITime.LocalDate = findDate;
                                        String calcExpression = "TagVal('" + varTag + "','" + findTime + "')";
                                        String checkExpression = "BadVal('" + varTag + "')";

                                        piServer2.Timeout = 60;

                                        String duration = "";
                                        PISDK.PIValues piCalcVals = new PISDK.PIValues();
                                        PISDK.IPICalculation piCalcVal = (PISDK.IPICalculation)piServer;
                                        object[] piTimes = new object[1];
                                        piTimes[0] = new object();
                                        piTimes[0] = findPITime;
                                        object zero;
                                        zero = new object();
                                        zero = 0.0;
                                      
                                        try
                                        {
                                            piCalcVals = piCalcVal.TimedCalculate(piTimes, checkExpression, piasync);

                                            if (piCalcVals[1].Value.Equals(zero))
                                            {
                                                piCalcVals = piCalcVal.TimedCalculate(piTimes, calcExpression, piasync);
                                                if (piCalcVals[1].Value != null)
                                                    retVal = Convert.ToDouble(piCalcVals[1].Value);
                                            }
                                            else
                                            {
                                                retVal = null;
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            retVal = null;
                                        }
                                        return retVal;

                             

                             

                            I have tried a variety of things... using a separate server instance, changing the timeout, etc... In all cases it stops on the TimedCalculate call.  I first tried Calculate, then I switched to TimedCalculate, then I add the code to test for the calculate expression for badvalue.  This works for a about 250 occurances of the run, but for some reason timesout on that command. That's why I became suspicious of the combination of sync and async.

                             

                            Thanks for your help,

                             

                            Dan

                          • Re: Asynchronous Summaries
                            jnissisolutions

                            Andreas,

                             

                            Not always on the same tag, I thought it did for awhile, but that changed as I tested for bad value.  My timeout is currently at 60.  The tag that it is currently stopping on has no particular surprises.  I bring it up in processbook for it's entire history and it looks fine. 

                             

                            See my previous post to Cristobal for the code.

                             

                            Thanks, Dan