Что нового

Отличие показаний TimerInit/TimerDiff при разном количестве проходов

Webarion

Осваивающий
Сообщения
143
Репутация
24
Сравниваю скорости нескольких функций, достигающих одного результата, разными способами. И с удивлением наблюдаю, как первая, работает медленнее других в одном проходе, но быстрее, при множественном. Буду рад, если, кто-то сможет пояснить такое отличие?

fR7uS8FONc.png

Пример:
Код:
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <ButtonConstants.au3>
#include <WinApi.au3>
#include <Array.au3>

__GUI_TestTime()


; переменные для тестируемых функций
Global $igW = 20, $igH = 20, $igTW = 100, $igMH = 100, $igHA = 1, $igVA = 1, $agP1, $agP2

; добавляем функции для тестирования. Вместо 5 следующих строк, можно так: Global $agTestFunctions_TSTM = ['Func1','Func2', 'Func3', 'Func4', 'Func5']
Add_Func_TestTime('Func1')
Add_Func_TestTime('Func2')
Add_Func_TestTime('Func3')
Add_Func_TestTime('Func4')
Add_Func_TestTime('Func5')

Start_TestTime() ; стартуем тест


#Region ТЕСТИРУЕМЫЕ ФУНКЦИИ
; ===============================================================================================================================
Func Func1()
    $agP1 = $igHA = 1 ? ($igTW / 2) - ($igW / 2) : ($igHA = 2 ? $igTW - $igW : 0)
    $agP2 = $igVA = 1 ? ($igMH / 2) - ($igH / 2) : ($igVA = 2 ? $igMH - $igH : 0)
EndFunc   ;==>Func1
; ===============================================================================================================================
Func Func2()
    If $igHA = 1 Then $agP1 = ($igTW / 2) - ($igW / 2)
    If $igHA = 2 Then $agP1 = $igTW - $igW
    If $igVA = 1 Then $agP2 = ($igMH / 2) - ($igH / 2)
    If $igVA = 2 Then $agP2 = $igMH - $igH
EndFunc   ;==>Func2
; ===============================================================================================================================
Func Func3()
    If $igHA = 1 Then
        $agP1 = ($igTW / 2) - ($igW / 2)
    ElseIf $igHA = 2 Then
        $agP1 = $igTW - $igW
    EndIf
    If $igVA = 1 Then
        $agP2 = ($igMH / 2) - ($igH / 2)
    ElseIf $igHA = 2 Then
        $agP2 = $igMH - $igH
    EndIf
EndFunc   ;==>Func3
; ===============================================================================================================================
Func Func4()
    Switch $igHA
        Case 1
            $agP1 = ($igTW / 2) - ($igW / 2)
        Case 2
            $agP1 = $igTW - $igW
    EndSwitch
    Switch $igVA
        Case 1
            $agP2 = ($igMH / 2) - ($igH / 2)
        Case 2
            $agP2 = $igMH - $igH
    EndSwitch
EndFunc   ;==>Func4
; ===============================================================================================================================
Func Func5()
    Select
        Case $igHA = 1
            $agP1 = ($igTW / 2) - ($igW / 2)
        Case $igHA = 2
            $agP1 = $igTW - $igW
    EndSelect
    Select
        Case $igVA = 1
            $agP2 = ($igMH / 2) - ($igH / 2)
        Case $igVA = 2
            $agP2 = $igMH - $igH
    EndSelect
EndFunc   ;==>Func5
; ===============================================================================================================================
#EndRegion ТЕСТИРУЕМЫЕ ФУНКЦИИ

Local $iGUIMsg_TSTM
While 1
    $iGUIMsg_TSTM = GUIGetMsg()
    Switch $iGUIMsg_TSTM
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $igButRepeat_TSTM
            GUICtrlSetState($igButRepeat_TSTM, $GUI_DISABLE)
            Local $hLastChildForm_TSTM = 0
            If $hgChildForm_TSTM Then $hLastChildForm_TSTM = $hgChildForm_TSTM
            $hgChildForm_TSTM = __CreateChildForm_TestTime($hgForm_TSTM, 0x9AAFDC)
            Start_TestTime($agTestFunctions_TSTM)
            GUISetState(@SW_SHOW, $hgChildForm_TSTM)
            If $hLastChildForm_TSTM Then GUIDelete($hLastChildForm_TSTM)
    EndSwitch
WEnd

; #ПОЛЬЗОВАТЕЛЬСКАЯ_ФУНКЦИЯ# ====================================================================================================
; Описание ...: Добавляет функцию в список тестируемых
; Параметры ..: $sFuncName - Ммя функции
; Возвращает .: 1 - функция добавлена, 0 и @error - не добавлена
; ===============================================================================================================================
Func Add_Func_TestTime($sFuncName)
    Call($sFuncName)
    If @error = 0xDEAD And @extended = 0xBEEF Then
        MsgBox(48, 'Тест времени функций', 'Функция «' & $sFuncName & '» не добавлена в список тестирования, так как не найдена' & @CRLF)
        Return SetError(1, 0, 0)
    EndIf
    Local $iUB = UBound($agTestFunctions_TSTM)
    ReDim $agTestFunctions_TSTM[$iUB + 1]
    $agTestFunctions_TSTM[$iUB] = $sFuncName
    Return 1
EndFunc   ;==>Add_Func_TestTime

; #ПОЛЬЗОВАТЕЛЬСКАЯ_ФУНКЦИЯ# ====================================================================================================
; Описание ...: Удаляет функцию из списка тестируемых
; Параметры ..: $sFuncName - Ммя функции
; Возвращает .: 1 - функция удалена, 0 и @error - не удалена,
; ===============================================================================================================================
Func Del_Func_TestTime($sFuncName)
    If Not UBound($agTestFunctions_TSTM) Then Return SetError(1, 0, 0)
    Local $iInd = _ArraySearch($agTestFunctions_TSTM, $sFuncName)
    If @error Then Return SetError(2, 0, 0)
    _ArrayDelete($agTestFunctions_TSTM, $iInd)
    If @error Then Return SetError(3, 0, 0)
    Return 1
EndFunc   ;==>Del_Func_TestTime

; #ПОЛЬЗОВАТЕЛЬСКАЯ_ФУНКЦИЯ# ====================================================================================================
; Описание ...: Стартует тестирование времени выполнения функций
; Параметры ..: $aCicles - массив, с количеством проходов (не обязательный, по умолчанию - [1, 2, 5, 10, 50, 100, 1000, 10000])
; ===============================================================================================================================
Func Start_TestTime($aCicles = 0)

    Global $igMainCols_TSTM = 3 ; количество колонок
    Global $igNumberDecimalPlaces_TSTM = 5 ; количество цифр, после запятой в результатах таймингов

    If Not $aCicles Then Dim $aCicles = [1, 2, 5, 10, 50, 100, 1000, 10000] ; проверка на разном количестве проходов

    GUICtrlSetData($igLabEvent_TSTM, 'Идёт тестирование...')
    Global $igCiclElem
    Local $iUBC = UBound($aCicles)
    Local $iUB = UBound($agTestFunctions_TSTM)
    Local $aTimeRes[$iUBC][$iUB], $aFnTimes[$iUB], $aMaxMin[$iUBC][2]
    For $n = 0 To $iUBC - 1
        $igCiclElem = $aCicles[$n] - 1
        If $igCiclElem < 0 Then $igCiclElem = 0
        Local $iTimeT
        For $c = 0 To $iUB - 1
            $iTimeT = __Caller_TestTime($agTestFunctions_TSTM[$c])
            $aTimeRes[$n][$c] = $iTimeT
            $aFnTimes[$c] = $iTimeT
        Next
        $aMaxMin[$n][0] = _ArrayMax($aFnTimes, 1)
        $aMaxMin[$n][1] = _ArrayMin($aFnTimes, 1)
    Next
    __Redraw_TestTime($aTimeRes, $aMaxMin, $aCicles)
EndFunc   ;==>Start_TestTime

; #СИСТЕМНАЯ_ФУНКЦИЯ# ===========================================================================================================
; Описание ...: Рисует графики протестированных функций
; ===============================================================================================================================
Func __Redraw_TestTime($aTimeRes, $aMaxMin, $aCicles)

    Local $iPaddingX = 8, $iPaddingY = 8
    Local $iSpaceLineW = 8, $iSpaceLineH = 8, $iTitleH = 14, $iFuncNameH = 14

    Local $nY = 0, $iLineY, $iTitleX, $iTitleY, $iTitleW = 0, $iGraphDiap, $iTimeDiap, $iGraphW, $iGrpX = $iPaddingX, $iGrpH
    Local $iGraphColor, $iRW, $iRowW = 0, $iRowH = 0
    Local $iFuncTime, $iCicles, $iTitle, $iLbTime, $iFuncName
    Local $hLastForm = GUISwitch($hgChildForm_TSTM)
    Local $iGraph = GUICtrlCreateGraphic(0, 0, $igFormW_TSTM, $igFormH_TSTM - 25)
    GUICtrlSetResizing(-1, $GUI_DOCKALL)
    Local $iUBC = UBound($aCicles)
    Local $iUB = UBound($agTestFunctions_TSTM)
    For $n = 0 To $iUBC - 1
        $iLineY = $iUB = 1 ? $iPaddingY + $nY * ($iFuncNameH + $iSpaceLineH + $iTitleH + $iTitleH) - $igGraphH_TSTM + $iTitleH : $iPaddingY + $nY * ($igGraphH_TSTM + $iFuncNameH + $iSpaceLineH + $iTitleH)
        $iTitleX = $iGrpX
        $iTitleW = 0
        $iGraphDiap = ($igGraphH_TSTM - $iTitleH) ; $igGraphH_TSTM-$iTitleH ; dMax - dMin
        $iTimeDiap = $aMaxMin[$n][0] - $aMaxMin[$n][1]
        $iCicles = $aCicles[$n]
        $sClTitle = $iCicles & ' проход' & __DeclRusNumber_TestTime($iCicles, '', 'а', 'ов')
        For $c = 0 To $iUB - 1
            $sFuncTime = String($aTimeRes[$n][$c])
            $iGraphW = __GetStringDimensions_TestTime($hgChildForm_TSTM, $sFuncTime)
            If $iUB = 1 Then
                $iClTitle = __GetStringDimensions_TestTime($hgChildForm_TSTM, $sClTitle)
                If $iClTitle > $iGraphW Then $iGraphW = $iClTitle
            EndIf
            $iGrpH = $iUB = 1 ? $iTitleH : $iTitleH + ($iGraphDiap * ($aTimeRes[$n][$c] - $aMaxMin[$n][1])) / $iTimeDiap
            $iGraphColor = $iUB = 1 ? 0x55FF4F : Ceiling(0x55FF4F + ((0xFF4D4D - 0x55FF4F) * ($aTimeRes[$n][$c] - $aMaxMin[$n][1])) / $iTimeDiap)
            GUICtrlSetGraphic($iGraph, $GUI_GR_COLOR, 0x000000, $iGraphColor)
            GUICtrlSetGraphic($iGraph, $GUI_GR_RECT, $iGrpX, $iLineY + $igGraphH_TSTM, $iGraphW, -$iGrpH)
            $iLbTime = GUICtrlCreateLabel($sFuncTime, $iGrpX, $iLineY + $igGraphH_TSTM - $iGrpH, $iGraphW, $iTitleH, $SS_CENTER)
            GUICtrlSetResizing(-1, $GUI_DOCKALL)
            GUICtrlSetBkColor(-1, -2)
            GUICtrlSetFont(-1, 8)
            $iFuncName = __CreateBorderLabel_TestTime($agTestFunctions_TSTM[$c], $iGrpX, $iLineY + $igGraphH_TSTM - 1, $iGraphW, $iFuncNameH, 0x0, 1, BitOR($SS_CENTER, $SS_CENTERIMAGE))
            GUICtrlSetResizing(-1, $GUI_DOCKALL)
            GUICtrlSetBkColor(-1, 0xFF8080)
            GUICtrlSetFont(-1, 8)
            $iGrpX += $iGraphW - 1
            $iTitleW += $iGraphW - 1
        Next
        $iTitleY = $iLineY + $igGraphH_TSTM + $iFuncNameH - 2
        $iTitle = __CreateBorderLabel_TestTime($sClTitle, $iTitleX, $iTitleY, $iTitleW + 1, $iTitleH, 0x0, 1, BitOR($SS_CENTER, $SS_CENTERIMAGE))
        GUICtrlSetResizing(-1, $GUI_DOCKALL)
        GUICtrlSetBkColor(-1, 0x80FF80)
        GUICtrlSetFont(-1, 8)
        $iGrpX += $iSpaceLineW
        $iRW = $iTitleX + $iTitleW + 1
        If $iRowW <= $iRW Then $iRowW = $iRW
        If Mod($n, $igMainCols_TSTM) = $igMainCols_TSTM - 1 Then
            $nY += 1
            $iGrpX = $iPaddingX
            $iTitleW = $iPaddingX
        EndIf
    Next
    $iRowW += 6 + $iPaddingX
    $iRowH = 66 + $iTitleY + $iTitleH
    WinMove($hgForm_TSTM, '', (@DesktopWidth / 2) - ($iRowW / 2), (@DesktopHeight / 2) - ($iRowH / 2), $iRowW, $iRowH)
    WinMove($hgChildForm_TSTM, '', 0, 30, $iRowW, $iRowH)
    GUICtrlSetData($igLabEvent_TSTM, '')
    GUICtrlSetState($igButRepeat_TSTM, $GUI_ENABLE)
    GUISetState(@SW_SHOW, $hgChildForm_TSTM)
    GUISetState(@SW_SHOW, $hgForm_TSTM)
EndFunc   ;==>__Redraw_TestTime

; #СИСТЕМНАЯ_ФУНКЦИЯ# ===========================================================================================================
; Описание ...: Создаёт дочернюю форму
; ===============================================================================================================================
Func __CreateChildForm_TestTime($hParentForm, $iColor = -1)
    Local $hFormChild = GUICreate('', $igFormW_TSTM, $igFormH_TSTM - 30, 0, 30, $WS_CHILD, $WS_EX_TOPMOST, $hParentForm)
    GUICtrlSetResizing($hFormChild, $GUI_DOCKALL)
    If $iColor >= 0 Then GUISetBkColor($iColor, $hFormChild)
    Return $hFormChild
EndFunc   ;==>__CreateChildForm_TestTime

; #СИСТЕМНАЯ_ФУНКЦИЯ# ===========================================================================================================
; Описание ...: Непосредственное тестирование
; ===============================================================================================================================
Func __Caller_TestTime($sFunc)
    Local $iTimer, $iTime
    $iTimer = TimerInit()
    For $i = 0 To $igCiclElem
        Call($sFunc)
    Next
    $iTime = TimerDiff($iTimer)
    Return StringFormat('%.' & String($igNumberDecimalPlaces_TSTM) & 'f', $iTime)
EndFunc   ;==>__Caller_TestTime

; #СИСТЕМНАЯ_ФУНКЦИЯ# ===========================================================================================================
; Описание ...: Создание интерфейса
; ===============================================================================================================================
Func __GUI_TestTime()
    Global $agTestFunctions_TSTM[0]
    Global $igGraphH_TSTM = 50
    Global $hgForm_TSTM, $hgChildForm_TSTM
    Global $igFormW_TSTM = 333, $igFormH_TSTM = 200
    Global $hgForm_TSTM = GUICreate('Тест времени функций', $igFormW_TSTM, $igFormH_TSTM, -1, -1, BitOR($WS_MINIMIZEBOX, $WS_CAPTION, $WS_POPUP, $WS_SYSMENU))
    Global $igButRepeat_TSTM = GUICtrlCreateButton('Обновить', 4, 2, 80, 24, BitOR($BS_CENTER, $BS_VCENTER))
    GUICtrlSetResizing(-1, $GUI_DOCKALL)
    GUICtrlSetImage(-1, "C:\Windows\System32\shell32.dll", -138, 0)
    GUICtrlSetTip(-1, 'Старт теста')
    GUICtrlSetState(-1, $GUI_DISABLE)
    Global $igLabEvent_TSTM = GUICtrlCreateLabel('', 88, 2, 150, 24, BitOR($BS_CENTER, $BS_VCENTER))
    GUICtrlSetResizing(-1, $GUI_DOCKALL)
    GUICtrlSetFont(-1, 8, 800)
    GUISetBkColor(0x88AABB)
    Global $hgChildForm_TSTM = __CreateChildForm_TestTime($hgForm_TSTM, 0x9AAFDC)
;~     GUISetState(@SW_SHOW, $hgForm_TSTM)
EndFunc   ;==>__GUI_TestTime

; #СИСТЕМНАЯ_ФУНКЦИЯ# ===========================================================================================================
; Описание ...: Склоняет русские слова, относительно чисел
; ===============================================================================================================================
Func __DeclRusNumber_TestTime($iN, $sT1, $sT2, $sT3)
    Return (Mod($iN, 10) = 1 And Mod($iN, 100) <> 11) ? $sT1 : (Mod($iN, 10) >= 2 And Mod($iN, 10) <= 4 And (Mod($iN, 100) < 10 Or Mod($iN, 100) >= 20)) ? $sT2 : $sT3
EndFunc   ;==>__DeclRusNumber_TestTime

; #СИСТЕМНАЯ_ФУНКЦИЯ# ===========================================================================================================
; Описание ...: Определяет длину строки в пикселях
; ===============================================================================================================================
Func __GetStringDimensions_TestTime($hWnd, $sText)
    Local $hDC = _WinAPI_GetDC($hWnd)
    Local $hFont = _SendMessage($hWnd, 0x0031)
    Local $hSelectObject = _WinAPI_SelectObject($hDC, $hFont)
    Local $tSIZE = _WinAPI_GetTextExtentPoint32($hDC, $sText)
    _WinAPI_SelectObject($hDC, $hSelectObject)
    _WinAPI_ReleaseDC($hWnd, $hDC)
    Return DllStructGetData($tSIZE, 1)
EndFunc   ;==>__GetStringDimensions_TestTime

; #СИСТЕМНАЯ_ФУНКЦИЯ# ===========================================================================================================
; Описание ...: Рисует Label с рамкой нужного цвета
; ===============================================================================================================================
Func __CreateBorderLabel_TestTime($sText, $iX, $iY, $iW, $iH, $iColor, $iPenSize = 1, $iStyle = -1, $iStyleEx = 0)
    GUICtrlCreateLabel('', $iX, $iY, $iW, $iH, 0)
    GUICtrlSetResizing(-1, $GUI_DOCKALL)
    GUICtrlSetBkColor(-1, $iColor)
    Return GUICtrlCreateLabel($sText, $iX + $iPenSize, $iY + $iPenSize, $iW - 2 * $iPenSize, $iH - 2 * $iPenSize, $iStyle, $iStyleEx)
EndFunc   ;==>__CreateBorderLabel_TestTime
 
Последнее редактирование:
Верх