Progress Bar Control Performance Testing

Moderator: Rathinagiri

User avatar
ljubacirovic
Posts: 12
Joined: Thu Mar 27, 2014 6:38 am
DBs Used: DBF, MySQL, MS Access, MS SQL
Been thanked: 1 time

Progress Bar Control Performance Testing

Post by ljubacirovic » Tue Feb 05, 2019 12:19 pm

Hi guys,
During lengthy processing I like to display progress of the processing to the user.
To achieve this goal, I made a simple method of displaying horizontal progress bar in a form of string made of small square characters (in my case chr(254) in ASCII table for code pages 437 and 852). I was very glad when I found progress bar control in HMG. When I tried it, I was disappointed with its performance and erratic behavior. Reading through the other users experiences on HMG forum and other places on the Internet, I realized that the root of the problem lies not in HMG but in Windows OS.
Therefore, I used workaround as described in https://derekwill.com/2014/06/24/combat ... ogressbar/ to make control to display properly. This method is not very pretty but it's effective. OK, main thing is that the control is giving accurate information about the process flow.
My next question was the speed of execution within the process, i.e. how big is overhead. Therefore I wrote this rather simple test to compare loop execution times for the following cases: without displaying progress bar (only counter), displaying progress bar control and displaying label with the string of characters.

Code: Select all

	
    #include 'hmg.ch'
	
	PROCEDURE ProgTest
	/*
    
    */
        PRIVATE cProgCh
        
        SET CODEPAGE TO ENGLISH
        cProgCh := chr(254)
        
        DEFINE WINDOW wProgTest ;
            AT 10, 10 ;
            WIDTH 420 HEIGHT 250 ;
            TITLE "Progress Indicator Testing" ;
            ICON NIL CHILD CURSOR NIL ;
            ON INTERACTIVECLOSE NIL ;
            ON GOTFOCUS NIL ;
            ON LOSTFOCUS NIL

            DEFINE LABEL lbSteps
                PARENT wProgTest
                ROW 20 
                COL 10
                VALUE "Enter number of steps for the test loop"
                WIDTH 220
                HEIGHT 20
            END LABEL

            DEFINE TEXTBOX tbSteps
                PARENT wProgTest
                ROW 18
                COL 250
                HEIGHT 20
                VALUE 0
                WIDTH 100
                INPUTMASK '999,999,999'
                FORMAT 'E'
                MAXLENGTH 9
                DATATYPE NUMERIC
                MAXLENGTH 9
                ONGOTFOCUS wProgTest.tbSteps.CaretPos := 8
                ONENTER wProgTest.btExecute.SetFocus
                RIGHTALIGN .T.
                VISIBLE .T.
                TABSTOP .T.
            END TEXTBOX
 
            DEFINE CHECKBOX cbProgBar
                PARENT wProgTest
                ROW 80
                COL 10
                CAPTION 'Progress bar'
                VALUE .F.
                WIDTH 100
                HEIGHT 20
                TOOLTIP 'Check if you want to test progress bar as progress indicator.'
                VISIBLE .T.
                TABSTOP .T.
            END CHECKBOX
             
            DEFINE PROGRESSBAR pbFlow
                ROW    80
                COL    110
                WIDTH  270
                HEIGHT 20
                RANGEMIN 1
                RANGEMAX 100
                VALUE 1
                TOOLTIP ""
                HELPID Nil
                VISIBLE .f.
                VERTICAL .F. 
            END PROGRESSBAR  

            DEFINE CHECKBOX cbLablBar
                PARENT wProgTest
                ROW 100
                COL 10
                CAPTION 'Label bar'
                VALUE .F.
                WIDTH 100
                HEIGHT 20
                TOOLTIP 'Check if you want to test label as progress indicator.'
                VISIBLE .T.
                TABSTOP .T.
            END CHECKBOX

            DEFINE LABEL lbFlow
                PARENT wProgTest
                ROW 100 
                COL 110
                VALUE ""
                WIDTH 10
                HEIGHT 50
                FONTCOLOR {0,76,153}
            END LABEL

            DEFINE BUTTON btExecute
                ROW    180
                COL    110
                WIDTH  200
                HEIGHT 25
                ACTION {TestInd(), wProgTest.tbSteps.SetFocus}
                CAPTION "Execute"
                TOOLTIP "Accept entered parameters and execute test."
                TABSTOP .T.
                VISIBLE .T.
            END BUTTON 
 
        END WINDOW	
        
        wProgTest.tbSteps.SetFocus
        wProgTest.Center
        wProgTest.Activate
    
    RETURN NIL	

//*---->

	FUNCTION TestInd
	/*
    
    */   
        nKfLb := 0
        nSteps := wProgTest.tbSteps.Value
        nStart:= SECONDS()
        IF wProgTest.cbProgBar.Value
            cTest := wProgTest.cbProgBar.Caption+' as progress indicator'
            wProgTest.pbFlow.RangeMax := nSteps
            wProgTest.pbFlow.Visible := wProgTest.cbProgBar.Value
        ELSEIF wProgTest.cbLablBar.Value
            cTest := wProgTest.cbLablBar.Caption+' as progress indicator'
            wProgTest.lbFlow.Visible := wProgTest.cbLablBar.Value
            wProgTest.lbFlow.Width := wProgTest.Width-wProgTest.lbFlow.Col
            nKfLb := (wProgTest.lbFlow.Width/wProgtest.lbFlow.FontSize)/105 
        ELSE
            cTest := 'Without progress indicator'
        END       
        
        FOR nI := 1 TO nSteps           
            IF wProgTest.cbProgBar.Value               
                IF nI==wProgTest.pbFlow.RangeMax    
                    wProgTest.pbFlow.RangeMax := wProgTest.pbFlow.RangeMax + 1      
                    wProgTest.pbFlow.Value := nI + 1
                    wProgTest.pbFlow.RangeMax := wProgTest.pbFlow.RangeMax - 1                 
                ELSE
                    wProgTest.pbFlow.Value := nI + 1   
                ENDIF
                wProgTest.pbFlow.Value := nI
            ELSEIF wProgTest.cbLablBar.Value
                nRatio := INT((nI/nSteps)*100)
                wProgTest.lbFlow.Value := REPLICATE(cProgCh,INT(nRatio*nKfLb))+' '+LTRIM(STR(nRatio))+'%'                
            END
            wProgTest.btExecute.Caption := 'Step '+LTRIM(STR(nI))+' of '+LTRIM(STR(nSteps))
            DO EVENTS
        NEXT             
        MsgInfo(cTest+' -> '+LTRIM(STR(SECONDS() - nStart))+ " seconds",'TEST DURATION')
        
        wProgTest.pbFlow.Visible := wProgTest.cbProgBar.Value := .F.
        wProgTest.lbFlow.Visible := wProgTest.cbLablBar.Value := .F.
        wProgTest.btExecute.Caption := "Execute"
        
    RETURN NIL

//*---->

Test was compiled by HMG 3.4.4 Stable (32-bits) and executed on HP ProBook 4530S laptop (Intel Core i5 @ 2,40GHz, 8GB RAM, Windows 10 OS 64bit). Testing range was from 5 to 100,000 steps. Results show that for the number of steps under 200 progress bar control is slightly faster, but for the larger number of steps it lags significantly (approx. 0,2 seconds per 1,000 steps) after the label.
Also, I noticed that maximum value for the progress bar control property RangeMax is 65,535 (2^16). If you set greater value, you get the value of the complement in the RangeMax (e.g. for 70,000 steps RangeMax will be set to 70,000-65,535=4,465) and the progress bar will be filled long before the process ends.
In my opinion, for the time being, progress bar control is useable for displaying of processing of less than 5,000 steps. After that amount, I would rather use only counter or label with string of characters. One can only hope that in the future this problem will be resolved and progress bar control will be really usable in HMG.

Finally, test execution results (in seconds) are in the attachment, for those who are interested.
Attachments
Process indicator testing.zip
Excel file
(10.39 KiB) Downloaded 64 times

User avatar
mustafa
Posts: 829
Joined: Fri Mar 20, 2009 11:38 am
DBs Used: DBF
Location: Alicante - Spain
Been thanked: 117 times
Contact:

Post by mustafa » Tue Feb 05, 2019 1:46 pm

Hola amigo ljubacirovic:
Esta muy bien esta aportación de Progress Bar
Experimentaré com mi sample "HB_ZipFile"
http://www.hmgforum.com/viewtopic.php?f ... afa#p57347

Gracias por compartir
Saludos
Mustafa
*--------------------------------- Google --------------------------------------------------*
Hello friend ljubacirovic:
This contribution from Progress Bar is very good
I will experiment with my sample "HB_ZipFile"
http://www.hmgforum.com/viewtopic.php?f ... afa#p57347

Thanks for sharing
regards
Mustafa

User avatar
serge_girard
Posts: 2312
Joined: Sun Nov 25, 2012 2:44 pm
DBs Used: 1 MySQL - MariaDB
2 DBF
Location: Belgium
Has thanked: 555 times
Been thanked: 116 times
Contact:

Post by serge_girard » Tue Feb 05, 2019 6:21 pm

Thanks ljubacirovic for sharing !

Serge

User avatar
ljubacirovic
Posts: 12
Joined: Thu Mar 27, 2014 6:38 am
DBs Used: DBF, MySQL, MS Access, MS SQL
Been thanked: 1 time

Post by ljubacirovic » Tue Feb 05, 2019 6:33 pm

Hello Mustafa and Serge,

I am glad to see that you are also interested in this, lets say glitch. I would be happy to know if you tried this test or possibly made some other kind of testing of HMG elements.

Best regards!

User avatar
serge_girard
Posts: 2312
Joined: Sun Nov 25, 2012 2:44 pm
DBs Used: 1 MySQL - MariaDB
2 DBF
Location: Belgium
Has thanked: 555 times
Been thanked: 116 times
Contact:

Post by serge_girard » Wed Feb 06, 2019 8:32 am

Hello ljubacirovic ,

I use the progress bar when there are few records. Otherwise I call a batch program to do the heavy stuff.
I also tried to play with the STEP but all this is consuming CPU time and the process will take longer.

Serge

User avatar
ljubacirovic
Posts: 12
Joined: Thu Mar 27, 2014 6:38 am
DBs Used: DBF, MySQL, MS Access, MS SQL
Been thanked: 1 time

Post by ljubacirovic » Wed Feb 06, 2019 11:24 am

Hello Serge,

I agree with you that all these graphics gadgets consume CPU time unnecessarily, but beauty comes with the price tag. Although, I must admit that MS improved performance in Windows 10.
If you are referring to the STEP option of the FOR...NEXT loop, as far as I know this is the slowest loop in many languages and it should be avoided if the speed of execution is important.

Ljuba

User avatar
serge_girard
Posts: 2312
Joined: Sun Nov 25, 2012 2:44 pm
DBs Used: 1 MySQL - MariaDB
2 DBF
Location: Belgium
Has thanked: 555 times
Been thanked: 116 times
Contact:

Post by serge_girard » Wed Feb 06, 2019 1:29 pm

Hello Ljuba,

I wrongly said STEP instead of Form.Progress.Value and RangeMax. When Rangemax exceeds 65535 I wanted to recalculate Rangemax with my total amount of records divided by 65535 etc...To complicated,

Serge

User avatar
ljubacirovic
Posts: 12
Joined: Thu Mar 27, 2014 6:38 am
DBs Used: DBF, MySQL, MS Access, MS SQL
Been thanked: 1 time

Post by ljubacirovic » Wed Feb 06, 2019 5:48 pm

Hello Serge,

Maybe it would be simpler to try to set Form.ProgfressBar.RangeMax to 100 and then in each step recalculate percentage of progress like int(nStepCounter/nTotalSteps*100). You can calculate quotient nQt := 100/nTotalSteps before entering the loop and then perform the ProgressBar.Value calculation like int(nStepCounter*nQt). By using this method I avoid the RangeMax limitation of 65535.
Here is what I mean in a code example.

Code: Select all

...
Form.ProgressBar.RangeMax := 100
...
nTotalSteps := ALIAS->(lastrec())	//	Define the number of total steps
nQt := 100/nTotalSteps
nStepCounter := 0
while ALIAS->(.not. eof())
	Form.ProgressBar.Value := int(++nStepCounter*nQt)	
	do events
	...processing steps...
	ALIAS->(dbskip())
end
Ljuba

User avatar
serge_girard
Posts: 2312
Joined: Sun Nov 25, 2012 2:44 pm
DBs Used: 1 MySQL - MariaDB
2 DBF
Location: Belgium
Has thanked: 555 times
Been thanked: 116 times
Contact:

Post by serge_girard » Wed Feb 06, 2019 8:38 pm

Thanks Ljuba,

This will help a lot to overcome the limitations of progressbar!

Thanks, Serge

User avatar
mol
Posts: 3195
Joined: Thu Sep 11, 2008 5:31 am
Location: Myszków, Poland
Has thanked: 214 times
Been thanked: 120 times
Contact:

Post by mol » Thu Feb 07, 2019 3:28 pm

Maybe change divide operation with addition former computed increment?
NStep := reccount()/100
Index .... Eval NtxProgress() every nStep records

Function NtxProgress
Form.progressbar.value +=1
Return

Post Reply