4 Replies Latest reply on Aug 24, 2016 5:46 PM by Rick Davin

    Looking for ways to speed up AFAttribute.Step calls

    Mark.Derbecker

      I have code that iterates through all AFElements in an AFDatabase, then iterates through all AFAttributes and uses their Step flag. The call to Step is very slow, it appears to be doing a round-trip to the PI server and connecting/disconnecting to said server every time.

       

      My current sequence of calls is this:

       

      AFDatabase.FindElements() to get all the elements in the database

      AFElement.LoadElements() to load them all in one shot

      Loop through all elements

        Loop through all attributes for a given element

          Call AFAttribute.Step

       

      In a different piece of code, when I iterate through PI tags directly (no AF involved), I have the nifty FindPIPoints() API that takes in a list of PIPointAttributes and reduces the round-trips. But I don't see anything that accomplishes something similar for AF.

        • Re: Looking for ways to speed up AFAttribute.Step calls
          Rick Davin

          Hi Mark,

           

          There is no direct way to do what you want with AFAttributes, but it is still possible with extra code.  You would want to loop over all attributes that reference the PIPoint DataReferencePlugin and save these PIPoints into a PIPointList.  You can then make a bulk call to load the Step attribute for the PIPoint.  Then later as you loop over the AFAttributes, the Step should be fetched from the local cache if you keep the PIPointList in memory.

           

          BTW ... I am to blame for this feature back in AF 2.4.  If the attribute's PIPoint has been retrieved, Step returns the correct setting.  But if the underlying PIPoint has not been referenced then Step returned the wrong setting.  But it should not be loading and unloading the PIPoint on each call.  Once the PIPoint is fetched, it should stay in cache.

           

          Hope this helps,

          Rick

          2 of 2 people found this helpful
            • Re: Looking for ways to speed up AFAttribute.Step calls
              pmartin

              If you are looking for the code to do this, I just whipped this up quickly.  The only thing you need to know is that e is an element.

               

              PIPointList pl = new PIPointList(new AFAttributeList(((IEnumerable<AFAttribute>)e.Attributes).Where( a => a.DataReferencePlugIn != null && a.DataReferencePlugIn.ToString() == "PI Point")).GetPIPoint().Results.Values);
              pl.LoadAttributes(PICommonPointAttributes.Step);
              foreach(PIPoint p in pl) {
                Console.WriteLine(p.Step);
              }
              
              2 of 2 people found this helpful
                • Re: Looking for ways to speed up AFAttribute.Step calls
                  Mark.Derbecker

                  Thank you Paul and Rick. I'd like to report on my success based on your suggestion. I used the following code, which is a more verbose version of Paul's code:

                   

                  OSIsoft.AF.PI.PIPointList piPointsToLoad = new OSIsoft.AF.PI.PIPointList();
                  for (int i = 0; i < elements.Count; i++) {
                      OSIsoft.AF.Asset.AFElement element = elements.ElementAt(i);
                      IEnumerable<OSIsoft.AF.Asset.AFAttribute> attributes = element.Attributes;
                      IEnumerable<OSIsoft.AF.Asset.AFAttribute> attributesWithPIPoints = attributes.Where(
                          a => a.DataReferencePlugIn != null && a.DataReferencePlugIn.ToString() == "PI Point");
                      OSIsoft.AF.Asset.AFAttributeList attributeList = new OSIsoft.AF.Asset.AFAttributeList(attributesWithPIPoints);
                      ICollection<OSIsoft.AF.PI.PIPoint> piPointList = attributeList.GetPIPoint().Results.Values;
                      piPointsToLoad.AddRange(piPointList);
                  }
                  
                  piPointsToLoad.LoadAttributes(OSIsoft.AF.PI.PICommonPointAttributes.Step);
                  

                   

                  Before this change, the overall process on a small database took 1m40s. With this change, it is down to 26s, a decrease of 74%.