janseng

As service slow / as application fast

Discussion created by janseng on Dec 17, 2012
Latest reply on Jan 14, 2013 by hanyong

Program description:
The program requests ca.2000 measurements every 15 minutes from a PI Server (15 minute averages)

Problem:
When the program runs as application the request takes ca. 9s.
When the program runs as serviceit takes up to 5 minutes and more and more RAM is occupied.
After 2 days -> "OutOfMemory"

Programming language: VisualBasic2005 (Microsoft VisualStudio)
PI-SDK: 64bit
OS: WinServer2008 R2 64bit

What was tried but did not help:
- using PI-SDK 32bit instead of 64bit
- On the OSI-Soft homepage (Known Issues No. 25158OSI8) we found the suggestion:
  Declaration of Services via STAThread (static)  instead of MTAThread (multi). This was done, but did not resolve the problem.

I simplified the original code to a 'test-program-code'.
The behaviour 'service is slow' / 'application is fast' is the same, see log file content below.

The simplified code is below.
- If the file "run_as_service.txt" exists, then the service can be started.
- If the file "run_as_service.txt" does not exist, then the executeable can be double clicked.


Logfile as service:
2012-12-12 16:25:36   Service started
2012-12-12 16:25:36   Averages requested of 980 tags
2012-12-12 16:26:32   Duration: 56 s
2012-12-12 16:26:32   RAM used: 25 %
2012-12-12 16:26:32   Wait 20 seconds...
2012-12-12 16:26:52   Averages requested of 980 tags
2012-12-12 16:27:11   Duration: 19 s
2012-12-12 16:27:11   RAM used: 25 %
2012-12-12 16:27:11   Wait 20 seconds...

Logfile as application:
2012-12-12 16:09:39   Averages requested of 980 tags
2012-12-12 16:09:45   Duration: 5 s
2012-12-12 16:09:45   RAM used: 25 %
2012-12-12 16:09:45   Wait 20 seconds...
2012-12-12 16:10:05   Averages requested of 980 tags
2012-12-12 16:10:08   Duration: 3 s
2012-12-12 16:10:08   RAM used: 25 %
2012-12-12 16:10:08   Wait 20 seconds...

 
Module A_Main

    Public LogFile As String

    Sub Main()

        If File.Exists(My.Application.Info.DirectoryPath & "\Run_As_Service.txt") Then

            'Run as Service
            LogFile = My.Application.Info.DirectoryPath & "\LogFile(Service).txt"
            Call Service1.Main_Service1()

        Else
            'Run as Application
            LogFile = My.Application.Info.DirectoryPath & "\LogFile(Application).txt"
            Call Start_DoIt()

        End If

    End Sub

    Sub Start_DoIt()

        WriteLog("")
        WriteLog("Test version 6")

        Dim D1 As Date, D2 As Date
        Dim Tags() As String = File.ReadAllLines(My.Application.Info.DirectoryPath & "\Tags.txt")

        Do While 1 = 1

            Call WriteLog("Averages requested of " & UBound(Tags) + 1 & " tags")

            D1 = Now
            Call DoIt(Tags) 'PI calls
            D2 = Now

            Call WriteLog("Duration: " & DateDiff(DateInterval.Second, D1, D2) & " s")

            MemoryStatus.Refresh()
            Call WriteLog("RAM used: " & MemoryStatus.MemoryLoad.ToString() & " %")

            Call WriteLog("Wait 20 seconds...")
            System.Windows.Forms.Application.DoEvents()
            Call System.Threading.Thread.Sleep(20 * 1000) 'Wait 20 seconds
        Loop

    End Sub

    Sub DoIt(ByVal Tags() As String)

        Dim SDK1 As New PISDK.PISDK


        'Open PI Server
        Dim aServer As PISDK.Server
        aServer = SDK1.Servers("dewesriek")
        aServer.Open("UID=BTBRead;PWD=btbr")

        'StartTime/EndTime for 15 minute mean values
        Dim DStart As Date = DateAdd(DateInterval.Minute, -30, Now)
        Dim DEnd As Date = DateAdd(DateInterval.Minute, -15, Now)
        Dim StartTime As String = Format("dd.MM.yyyy HH:mm:ss", DStart)
        Dim EndTime As String = Format("dd.MM.yyyy HH:mm:ss", DEnd)



        'Loop -------------------------------------------------------------------------------------
        For i As Integer = 0 To UBound(Tags)

            Try

                'Get PIPoint
                Dim pt As PISDK.PIPoint
                pt = aServer.PIPoints(Tags(i))

                If pt.PointType <> PISDK.PointTypeConstants.pttypDigital Then
                    'Get unit and descriptor
                    Dim PU As String = pt.PointAttributes("engunits").Value.ToString
                    Dim Descriptor As String = pt.PointAttributes("descriptor").Value.ToString

                    'Get mean value
                    Dim Pdata As PISDK.PIData
                    Dim IPId2 As PISDK.IPIData2, IPICalc As PISDK.IPICalculation
                    Dim nvsSum As PISDKCommon.NamedValues, valSum As PISDK.PIValues

                    IPICalc = aServer   ' get pointer to IPICalculation Interface
                    Pdata = pt.Data
                    IPId2 = Pdata       ' get pointer to IPIData2 Interface

                    'Time weighteed mean value
                    Dim aDuration As String = ""
                    Dim aAgregateType As PISDK.ArchiveSummaryTypeConstants = PISDK.ArchiveSummaryTypeConstants.astAverage
                    Dim aCalculationBasis As PISDK.CalculationBasisConstants = PISDK.CalculationBasisConstants.cbTimeWeighted

                    nvsSum = IPId2.Summaries2(StartTime, EndTime, aDuration, aAgregateType, aCalculationBasis)

                    valSum = nvsSum("Average").Value

                    Dim SValue As String = CStr(valSum.Item(1).Value) 'only index 1 (only a "one" average)

                    Pdata = Nothing
                    IPId2 = Nothing
                    IPICalc = Nothing
                    nvsSum = Nothing
                    valSum = Nothing
                End If

                pt = Nothing

            Catch ex As Exception
                Call WriteLog("Sub DoIt " & Tags(i) & " ERR#" & CStr(ex.ToString) & " / " & ex.Message)
            End Try

            GC.Collect()

        Next
        '-------------------------------------------------------------------------------------

        aServer.Close()

        'No effect: -----------------------------------------------
        aServer = Nothing
        System.Runtime.InteropServices.Marshal.ReleaseComObject(SDK1)
        SDK1 = Nothing
        GC.Collect()

    End Sub

    Sub WriteLog(ByVal aComment As String)

        Dim aLine As String = ""
        If aComment <> "" Then aLine = Format(Now, "yyyy-MM-dd HH:mm:ss") & "   " & aComment

        Dim Fid As Integer = FreeFile()
        FileOpen(Fid, LogFile, OpenMode.Append)
        PrintLine(Fid, aLine)
        FileClose(Fid)
    End Sub

End Module


Imports System.ServiceProcess

Public Class Service1
    Public Timer1 As New System.Timers.Timer()

    Public Sub New()
        MyBase.new()

        ' Dieser Aufruf ist für den Windows Form-Designer erforderlich.
        InitializeComponent()

        ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu.
    End Sub

     _  _ Shared Sub Main_Service1() Dim ServicesToRun() As System.ServiceProcess.ServiceBase ServicesToRun = New System.ServiceProcess.ServiceBase() {New Service1()} System.ServiceProcess.ServiceBase.Run(ServicesToRun) End Sub Protected Overrides Sub OnStart(ByVal args() As String) AddHandler Timer1.Elapsed, AddressOf Timer_Proc Timer1.Interval = 200 Timer1.Enabled = True End Sub Sub Timer_Proc(ByVal source As Object, ByVal e As System.Timers.ElapsedEventArgs) Timer1.Enabled = False Call Start_DoIt() End Sub Protected Overrides Sub OnStop() Call WriteLog("Service stopped") End Sub End Class 

 

 




Outcomes