1 Reply Latest reply on Dec 19, 2017 8:42 PM by Rick Davin

    PI Server Cache

    PeterHuang

      Hi

       

      I'm currently using PI AF SDK to get the pi points using the following APIs

       

           PIPoint.FindPIPointsAsync

       

      and for each pi point, I call

       

           PIPoint.PlotValuesAsync

       

      In our current architecture, the UI layer pass one parameter at a time to the data access layer. As a result, I can call these two API using one parameter at a time. Even though FindPIPointsAsync takes multiple parameters.

      I understand that passing multiple parameter would be more efficient instead of passing one at a time, even though they are being called asynchronously, (with a waitall in the UI layerl). As passing multiple parameters require more design work so to justify the work. I'm ask to find the performance different between using one parameter vs multiple parameters for FindPIPointsAsync API call.

       

      During the test, I find out that the first time I fetch the data is very fast as compare to the subsequent calls ( 1 sec vs 150 ms).  I was instructed by someone from OSI to use AFCache to remove cache in the client, However, the cache issue remain and the only way to remove "cache issue" is by reboot the PI server.   I don't see any AF SDK that would allow me to remove the cache in the server. Please advise if  there any support to remove the cache in the server using AF SDK. If not, are there any other way that I can remove the server cache or work around the server cache issue such as set a registry key, change a configuration value or even stop/start one or more services, as the only way I can do it now is to reboot the PI server every time before the test and that is time consuming.

       

      On the side note, PlotValuesAsync work with one one point at a time. But PIPointList.PlotValues work with multiple points. I do not see an async version for PiPointList.PlotValues. It there just no real performance difference for using async with PiPointList.PlotValues that such api is not supported. Please advise. Thanks

       

      Peter

        • Re: PI Server Cache
          Rick Davin

          Hi Peter,

           

          At first I was a little confused about why someone at TechSupport would recommend that you issue an AFCache.Clear().  However, I found your case and see that their suggestion was based on a direct question from you: Is there any way we can remove the cache and make the calls the same for the purpose of measuring the API turn around time?

           

          For what you are really asking, the answer is NO.  There is a client-side cache controlled by AFCache, which you can Clear, but even immediately after doing so those items may still be accessed by AF SDK up until the .NET garbage collector destroys them (which is cleared documented at this link).  Still there is a server-side cache at play, which will still skew your benchmarks.  I cannot emphasize this next strongly enough: trying to disable that cache on the PI Data Archive is not recommended.

           

          One alternative is to throw away the first measurement and record the next.  Problem is this benchmarks an already full cache.

           

          Another alternative is to wait 15 minutes between invocations to give the cache a long enough grace period to timeout.  If this is on a fairly isolated test box where you are the lone user, items may still persist in the cache even after timing out.  Whichever route you take, I suggest you record 5-10 trial runs and average the time.

           

          That said, your biggest leap of performance will be with bulk calls on groups of tags rather than many repeated calls on individual tags.  You haven't shared any numbers with us, but for 1000 tags you can easily issue 1 bulk PIPoint.FindPIPointsAsync call and save that to a PIPointList object, and then issue another PIPointList.PlotValues call.  That requires only TWO calls to the PI Data Archive.  In my opinion, the boost in performance using bulk justifies the extra bit of coding.  Side note: If you are using AF SDK 2.9 or later, you can easily get PIServer RPC Metrics.

           

          The Async versions of things like FindPIPoints is nice because when you issue that one call it is quite monolithic.  You make the call and you wait for the entire results to come back in one huge result set.    You are not able to partially process or break out of the request until the whole thing is done.  With FindPIPointsAsync, the tags are streamed to you.  Though the return type is listed as IEnumerable<PIPoint> suggests one tag at a time comes back, it actually does so in pages, or as the help documentation says "blocks".  Still, FindPIPointsAsync allows that monolithic call to be broken up so that you may (1) begin processing results as they are ready rather than waiting for the entire list to finish or (2) cancel the call mid-stream.

           

          Why doesn't PIPointList bulk methods have Async versions?  If the intent is to have a call that can be broken up to process earlier results before the entire list is complete then that functionality is already provided with PIPointList.PlotValues thanks to the PIPagingConfiguration as data is streamed to you as determined by your paging config.

           

          I use the phrases "pages" and "streaming".  To properly adopt streaming, it's more than just changing the type of your variables from List to IEnumerable.  The other potential performance benefit is altering your logic to consume the data as it is available, instead of waiting for a complete list.  This means you should avoid calls such as ToList(), ToArray(), Count, Length, or LINQ methods like Count() or Last().  The one exception is of course feeding results of FindPIPointsAsync to the PIPointList constructor - that is absolutely required in order to perform the bulk PlotValues call later. 

           

          An analogy I offer is not based on AF SDK, but simple .NET System.IO.  I had to loop over 300K files from a folder. Using the GetFiles method was very slow as I had to sit and wait for all 300K file names to be returned to me before I could then do something else with the list.  When I swapped this out with the streaming EnumerateFiles method performance made a huge leap because I was able to process about 80% of the files before EnumerateFiles sent me the last one. 

          6 of 6 people found this helpful