Jump to content
Sign in to follow this  
FreeFry

Leveling out cpu usage

Recommended Posts

FreeFry

Hi, I've coded this little Server Monitor app, but there's a problem.

It is very heavy on the cpu with only 3-4 servers..

I'd appreciate if anyone could take the time to look @ it, and give me a suggestion of what I could improve on it. :)

Oh and btw. this is for Half-Life1 servers(CS 1.6, etc. but I think source servers is ok too though, can't remember right now.)

Edit:

Alternatively I maybe could use this instead(to do the server queries):

http://home.arcor.de/levelad/SSQbeta1.zip

Edit2:

Fixed, code updated.

#include <String.au3>
#include <GuiConstants.au3>
#include <Constants.au3>
#NoTrayIcon

UDPStartup()

Opt("WinTitleMatchMode", 4)
Opt("WinWaitDelay", 0)
Opt("GUIDataSeparatorChar", @LF)
Opt("TrayMenuMode",1)
Opt("GUIOnEventMode", 1)
Opt("TrayOnEventMode", 1)

Dim $DebugMode = True


Dim $A2S_INFO = _HexToString("FFFFFFFF") & "TSource Engine Query" & _HexToString("00")  ; Retrives server name and stuff(needs handle)
Dim $A2S_SERVERQUERY_GETCHALLENGE = _HexToString("FFFFFFFF57")                          ; Retrives a handle
Dim $A2S_RULES = _HexToString("FFFFFFFF56")                                             ; Retrives a server's rules(needs handle)

Dim $SettingsDir = @AppDataDir & "\FreeSoft\Server Monitor"
Dim $OnTopAttribute

Dim $ServerList [1] = [0]
Dim $ListViewItems[1][2] = [[0]]

Dim $TimerHandle = TimerInit()

Dim $GuiHandle = GuiCreate("Server Monitor v1.0", 691, 30,-1, -1 , BitOR($WS_OVERLAPPEDWINDOW, $WS_CLIPSIBLINGS))

$List_1 = GUICtrlCreateListView("Name" & @LF & "Players" & @LF & "Map" & @LF & "Ping" & @LF & "Address", 0, 0, 690, 40)

$Tray_Item1 =  TrayCreateItem("Always on top", -1, -1, 0)
$Tray_Item2 =  TrayCreateItem("Add Server", -1, -1)
$Tray_Item4 =  TrayCreateItem("Connect", -1, -1)
$Tray_Item3 =  TrayCreateItem("Exit", -1, -1)


GUISetOnEvent($GUI_EVENT_CLOSE, "_HandleGUI")
TrayItemSetOnEvent($Tray_Item1, "_HandleTray")
TrayItemSetOnEvent($Tray_Item2, "_HandleTray")
TrayItemSetOnEvent($Tray_Item3, "_HandleTray")
TrayItemSetOnEvent($Tray_Item4, "_HandleTray")

GuiSetState()
TraySetState()

_LoadSettings()
_ToggleOnTopState()

While 1
    
    If TimerDiff($TimerHandle) > 2000 Then
        _UpdateServerList()
        $TimerHandle = TimerInit()
    EndIf
    
    Sleep(100)
    
WEnd

Func _HandleGUI()
    
    Local $GuiMsg = @GUI_CTRLID
    
    If $GuiMsg = $GUI_EVENT_CLOSE Then
        _SaveSettings()
        Exit
    EndIf
    
EndFunc

Func _HandleTray()
    
    Local $TrayMsg = @TRAY_ID
    
    If $TrayMsg = $Tray_Item3 Then
        _SaveSettings()
        Exit
    ElseIf $TrayMsg = $Tray_Item4 Then
        _Connect()
    ElseIf $TrayMsg = $Tray_Item1 Then
        _ToggleOnTopState()
    ElseIf $TrayMsg = $Tray_Item2 Then
        _AddServer()
    EndIf
    
EndFunc

Func _Connect()
    
    Local $i_SelectedLVI = GUICtrlRead($List_1)
    
    If $DebugMode Then
        ConsoleWrite("Connecting to listviewitem: " & $i_SelectedLVI & @LF)
    EndIf
    
    If $ListViewItems[0][0] = 1 Then
        MsgBox(0, "Error", "Please add servers first!")
        Return
    ElseIf $i_SelectedLVI = 0 Then
        MsgBox(0, "Error", "Please select a server first!")
        Return
    EndIf
    
    For $i = 1 To $ListViewItems[0][0]
        If $ListViewItems[$i][0] = $i_SelectedLVI Then
            ShellExecute("steam://connect/" & $ListViewItems[$i][1])
        EndIf
    Next
    
EndFunc

Func _AddServer($s_ServerAddress = "")
    
    Local $a_ServerInfo
    Local $i_ListViewItem
    
    If $s_ServerAddress = "" Then
        $s_ServerAddress = InputBox("Server Address", "Input the server address and port, ex: 194.18.96.169:27015")
        If @error Then Return
    EndIf
    
    If $DebugMode Then
        ConsoleWrite("Adding server: " & $s_ServerAddress & @LF)
    EndIf
    
    $a_ServerInfo = _GetServerInfo($s_ServerAddress)
    If @error Then
        MsgBox(0, "Error", "Server: " & $s_ServerAddress & " is not responding, skipping")
        Return
    EndIf
    
    $i_ListViewItem = GUICtrlCreateListViewItem($a_ServerInfo[0] & @LF & $a_ServerInfo[3] & @LF & $a_ServerInfo[2] & @LF & $a_ServerInfo[6] & @LF & $a_ServerInfo[7], $List_1)
    
    $ServerList[0] += 1
    ReDim $ServerList[$ServerList[0]+1]
    $ServerList[$ServerList[0]] = $s_ServerAddress
    
    $ListViewItems[0][0] += 1
    ReDim $ListViewItems[$ListViewItems[0][0]+1][2]
    $ListViewItems[$ListViewItems[0][0]][0] = $i_ListViewItem
    $ListViewItems[$ListViewItems[0][0]][1] = $a_ServerInfo[7]
    
EndFunc

Func _UpdateServerList()
    
    Local $a_ServerInfo
    
    If $DebugMode Then
        ConsoleWrite("Updating serverlist..." & @LF)
    EndIf
    
    For $i = 1 To $ServerList[0]
        $a_ServerInfo = _GetServerInfo($ServerList[$i])
        If @error Then ContinueLoop
        GUICtrlSetData($ListViewItems[$i][0], $a_ServerInfo[0] & @LF & $a_ServerInfo[3] & @LF & $a_ServerInfo[2] & @LF & $a_ServerInfo[6])
    Next
    
EndFunc

Func _LoadSettings()
    
    Global $WindowPosition = IniRead($SettingsDir & "\Settings.ini", "Settings", "Position", -1)
    Global $OnTopAttribute = IniRead($SettingsDir & "\Settings.ini", "Settings", "AoT", True)
    Global $WindowSize = IniRead($SettingsDir & "\Settings.ini", "Settings", "Size", -1)
    
    If $DebugMode Then
        ConsoleWrite("Loading settings..." & @LF)
    EndIf
    
    Local $a_ServerList = IniReadSection($SettingsDir & "\Settings.ini", "Servers")
    
    $a_ServerList = IniReadSection($SettingsDir & "\Settings.ini", "Servers")
    If Not @error Then
        For $i = 1 To $a_ServerList[0][0]
            _AddServer($a_ServerList[$i][1])
        Next
    EndIf
    
    If $WindowPosition <> -1 Then
        $WindowPosition = StringSplit($WindowPosition, ",")
        $WindowSize = StringSplit($WindowSize, ",")
        If Not @error Then
            WinMove($GuiHandle, "", $WindowPosition[1], $WindowPosition[2], $WindowSize[1], $WindowSize[2])
        Else
            WinMove($GuiHandle, "", $WindowPosition[1], $WindowPosition[2])
        EndIf
    EndIf
    
    If $OnTopAttribute = "True" Then
        $OnTopAttribute = True
    ElseIf $OnTopAttribute = "False" Then
        $OnTopAttribute = False
    EndIf
    
EndFunc

Func _SaveSettings()
    
    Local $WindowPosition = WinGetPos($GuiHandle)
    
    If $DebugMode Then
        ConsoleWrite("Saving settings..." & @LF)
    EndIf
    
    If Not FileExists($SettingsDir) Then DirCreate($SettingsDir)
    
    For $i = 1 To $ServerList[0]
        IniWrite($SettingsDir & "\Settings.ini", "Servers", $i, $ServerList[$i])
    Next
    
    IniWrite($SettingsDir & "\Settings.ini", "Settings", "Size", $WindowPosition[2] & "," & $WindowPosition[3])
    IniWrite($SettingsDir & "\Settings.ini", "Settings", "Position", $WindowPosition[0] & "," & $WindowPosition[1])
    IniWrite($SettingsDir & "\Settings.ini", "Settings", "AoT", Not $OnTopAttribute)
    
EndFunc

Func _ToggleOnTopState()
    
    WinSetOnTop($GuiHandle, "", Number($OnTopAttribute))
    
    If $DebugMode Then
        ConsoleWrite("Toggling AllwaysOnTop State" & @LF)
    EndIf
    
    If $OnTopAttribute Then
        TrayItemSetState($Tray_Item1, $TRAY_CHECKED)
    Else
        TrayItemSetState($Tray_Item1, $TRAY_UNCHECKED)
    EndIf
    
    $OnTopAttribute = Not $OnTopAttribute
    
EndFunc

;~  $rServerInfo[0] = $ServerName
;~  $rServerInfo[1] = $ServerType
;~  $rServerInfo[2] = $ServerMap
;~  $rServerInfo[3] = $ServerPlayers
;~  $rServerInfo[4] = $ServerSlots
;~  $rServerInfo[5] = $ServerIsPass
;~  $rServerInfo[6] = $ServerPing

Func _GetServerInfo($sServer); ip:port
    
    Local $sIP = StringLeft($sServer, StringInStr($sServer, ":", 0, -1)-1)
    Local $sPort = StringTrimLeft($sServer, StringInStr($sServer, ":", 0, -1))
    Local $ServerInfo = _QueryServerInfo($sIP, $sPort)
    
;~  If $ServerInfo <> -1 Then
;~      $sPing = Ping($sIP, 5000);      Fast, though less accurate results
;~      $sPing = Int((Ping($sIP, 500)+Ping($sIP, 500)+Ping($sIP, 500)+Ping($sIP, 500))/4);      Hmmm.. takes very long time... but more accurate results
;~  Else
    If Not IsArray($ServerInfo) Then
        SetError(1)
        Return -1
    EndIf
    
;~  If $sPing = 0 Then
;~      SetError(2)
;~  EndIf
    
    Return $ServerInfo
    
EndFunc

Func _QueryServerInfo($t_ServerIp, $t_ServerPort, $t_TimeOut = 5000)
    
    Local $oSocket = UDPOpen($t_ServerIp, $t_ServerPort)
    
    Local $Data
    
    Local $ServerType
    Local $ServerName
    Local $ServerMap
    Local $ServerPlayers
    Local $ServerSlots
    Local $ServerIsPass
    Local $ServerPing
    
    Local $rServerInfo[8]
    
    If $oSocket = -1 Then
        SetError(@error)
        Return -1
    EndIf
    
    _UDPSendData($oSocket, $A2S_INFO)
    
;~  $Data = UDPRecv($oSocket, 9999)
    $Data = BinaryToString(_UDPReceiveData($oSocket, $t_TimeOut*2, 9999))
    
    If @error Then
        SetError(@error)
        Return $Data
    EndIf
    
;~  MsgBox(0, "$Data, Error: " & @error, $Data)
    
    If StringLeft($Data, 4) == _HexToString("FFFFFFFF") Then
        
        $Data = StringTrimLeft($Data, 4)
        
        If StringLeft($Data, 1) == "I" Then
            $ServerType = "Source"
        ElseIf StringLeft($Data, 1) == "m" Then
            $ServerType = "Normal"
        EndIf
        
        $Data = StringTrimLeft($Data, 1)
        
        If $ServerType = "Normal" Then
            
            Do
                $Data = StringTrimLeft($Data, 1);           Trim Ip and Port
            Until StringLeft($Data, 1) = Chr(0)
            
            $Data = StringTrimLeft($Data, 1)
            
            Do
                $ServerName = $ServerName & StringLeft($Data, 1)
                $Data = StringTrimLeft($Data, 1)
            Until StringLeft($Data, 1) = Chr(0)
            
            $Data = StringTrimLeft($Data, 1)
            
            Do
                $ServerMap = $ServerMap & StringLeft($Data, 1)
                $Data = StringTrimLeft($Data, 1)
            Until StringLeft($Data, 1) = Chr(0)
            
            $Data = StringTrimLeft($Data, 1)
            
            Do
                $Data = StringTrimLeft($Data, 1);           Trim GameDir
            Until StringLeft($Data, 1) = Chr(0)
            
            $Data = StringTrimLeft($Data, 1)
            
            Do
                $Data = StringTrimLeft($Data, 1);           Trim Description
            Until StringLeft($Data, 1) = Chr(0)
            
            $Data = StringTrimLeft($Data, 1)
            
            $ServerPlayers = Asc(StringLeft($Data, 1))
            
            $Data = StringTrimLeft($Data, 1)
            
            $ServerSlots = Asc(StringLeft($Data, 1))
            
            $Data = StringTrimLeft($Data, 4)
            
            $ServerIsPass = Asc(StringLeft($Data, 1))
            
            If String($ServerIsPass) = "1" Then
                $ServerIsPass = "Yes"
            Else
                $ServerIsPass = "No"
            EndIf
            
        ElseIf $ServerType = "Source" Then
            
            $Data = StringTrimLeft($Data, 1);               Trim version
            
            Do
                $ServerName = $ServerName & StringLeft($Data, 1)
                $Data = StringTrimLeft($Data, 1)
            Until StringLeft($Data, 1) = Chr(0)
            
            $Data = StringTrimLeft($Data, 1)
            
            Do
                $ServerMap = $ServerMap & StringLeft($Data, 1)
                $Data = StringTrimLeft($Data, 1)
            Until StringLeft($Data, 1) = Chr(0)
            
            $Data = StringTrimLeft($Data, 1)
            
            Do
                $Data = StringTrimLeft($Data, 1);           Trim GameDir
            Until StringLeft($Data, 1) = Chr(0)
            
            $Data = StringTrimLeft($Data, 1)
            
            Do
                $Data = StringTrimLeft($Data, 1);           Trim Description
            Until StringLeft($Data, 1) = Chr(0)
            
            $Data = StringTrimLeft($Data, 3);               Trim nul char & AppID
            
            $ServerPlayers = Asc(StringLeft($Data, 1))
            
            $Data = StringTrimLeft($Data, 1)
            
            $ServerSlots = Asc(StringLeft($Data, 1))
            
            $Data = StringTrimLeft($Data, 4)
            
            $ServerIsPass = Asc(StringLeft($Data, 1))
            
            If String($ServerIsPass) = "1" Then
                $ServerIsPass = "Yes"
            Else
                $ServerIsPass = "No"
            EndIf
            
        EndIf
        
        $ServerPing = Ping($t_ServerIp, $t_TimeOut)
        
        If $ServerPing = 0 Then $ServerPing = -1
        
    Else
        MsgBox(0, "Error", "Wrong data received from server.")
        UDPCloseSocket($oSocket)
        SetError(1)
        Return -3
    EndIf
    
;~  $rServerInfo = "ServerName: " & $ServerName & @CRLF & "ServerType: " & $ServerType & @CRLF & "Map: " & $ServerMap & @CRLF & "Players: " & $ServerPlayers & "/" & $ServerSlots & @CRLF & "Password Required: " & $ServerIsPass
    
;~  Return $rServerInfo
    
    UDPCloseSocket($oSocket)
    
    $rServerInfo[0] = $ServerName
    $rServerInfo[1] = $ServerType
    $rServerInfo[2] = $ServerMap
    $rServerInfo[3] = $ServerPlayers
    $rServerInfo[4] = $ServerSlots
    $rServerInfo[5] = $ServerIsPass
    $rServerInfo[6] = $ServerPing
    $rServerInfo[7] = $t_ServerIp & ":" & $t_ServerPort
    
    Return $rServerInfo
    
EndFunc

Func _UDPReceiveData($o_Socket, $m_TimeOut = 5000, $s_BufferSize = 999)
    
    Local $r_data
    Local $t_Handle = TimerInit()
    
    Do
        
        $r_data = UDPRecv($o_Socket, $s_BufferSize)
        
    Until $r_data <> "" Or TimerDiff($t_Handle) > $m_TimeOut Or @error
    
    If @error Then
        SetError(@error)        ; Other Error
        Return -2               ; Other Error
    ElseIf TimerDiff($t_Handle) > $m_TimeOut Then
        SetError(1)             ; Timed Out
        Return -1               ; Timed Out
    EndIf
    
    Return $r_data              ; No error
    
EndFunc

Func _UDPSendData($o_Socket, $s_Data)
    
    Local $n_Data = UDPSend($o_Socket, $s_Data)
    
    SetError(@error)
    
    If @error = 1 Then
        Return -1       ; Ip-adress error
    ElseIf @error = 2 Then
        Return -2       ; Port error
    ElseIf @error Then
        Return -3       ; Other error
    EndIf
    
    Return $n_Data  ; No error
    
EndFunc
Edited by FreeFry

Share this post


Link to post
Share on other sites
enaiman

What I can see ... there is no Sleep in your While loop.

Update your loop like:

While 1
    Sleep (250)
    If TimerDiff($TimerHandle) > 2000 Then
        _UpdateServerList()
        $TimerHandle = TimerInit()
    EndIf
    
WEnd

and see what's happening - my guess it is that your CPU load will drop significantly.

You can experiment with different values for Sleep to see which suits you.


SNMP_UDF ... for SNMPv1 and v2c so far, GetBulk and a new example script

wannabe "Unbeatable" Tic-Tac-Toe

Paper-Scissor-Rock ... try to beat it anyway :)

Share this post


Link to post
Share on other sites
FreeFry

That helped, thanks. lol :)

I recently updated it to use the OnEventMode instead of the usual gui/tray 'message polling', and I guess I forgot that part. :)

Hmm, though still, it uses quite much cpu usage when it's updating the server list. :/

Share this post


Link to post
Share on other sites
enaiman

Glad it worked :)

One question: do you need to update the server list every 2 seconds?

If TimerDiff($TimerHandle) > 2000 Then

I think this way too fast ... make it like 30 sec or whatever you like and this will also free your CPU.

I didn't check your code for how this update is done (and never will :) because I don't know too much about this).


SNMP_UDF ... for SNMPv1 and v2c so far, GetBulk and a new example script

wannabe "Unbeatable" Tic-Tac-Toe

Paper-Scissor-Rock ... try to beat it anyway :)

Share this post


Link to post
Share on other sites
FreeFry

Hmm, 30 is way to slow in my opinion, but I'm not sure, never made an app like this before. :)

Share this post


Link to post
Share on other sites
enaiman

Hmm, 30 is way to slow in my opinion, but I'm not sure, never made an app like this before.

30 was like an example - you can use any value - I just wanted to say that updating every 2 seconds is a bit too fast.

If you change that for 4 sec instead of 2 it will free your CPU a little - just experiment and see what's best.


SNMP_UDF ... for SNMPv1 and v2c so far, GetBulk and a new example script

wannabe "Unbeatable" Tic-Tac-Toe

Paper-Scissor-Rock ... try to beat it anyway :)

Share this post


Link to post
Share on other sites
FreeFry

I think the problem with it stressing the cpu was because first I tried to use msg polling with the gui instead of the event thing, and that actually made it totally hang after a while, then when I sat down and changed it into using events it worked good, except that it was a little laggy.

It actually works flawless now, I had just forgot the sleep in the main loop. xD

Only thing about the update delay that I'm actually concerned about is so that it doesn't spam the server with requests. :)

Edit:

As the source is available for free(as all my apps) for anyone that wants it with a greater delay can change it. :)

Thanks for you input though! :)

Edited by FreeFry

Share this post


Link to post
Share on other sites
codydbgt

dam onece again I'm sorry wrong post

Edited by codydbgt

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×