Sign in to follow this  
Followers 0
Zedna

_GUICtrlListView_AddItem() MUCH slower than GUICtrlCreateListViewItem()

14 posts in this topic

#1 ·  Posted (edited)

1) GUICtrlCreateListViewItem() - very quick

2) _GUICtrlListView_AddItem(ControlId) - MUCH slower

3) _GUICtrlListView_AddItem(ControlHwnd) - even MUCH more slower

I think 1) and 2) should have similar time consume amount and not such big differences.

I saw it's sources.

Times in parenthesis are from another computer.

All times are avg from several runs (all on 3.2.10 version)

#include <GUIConstants.au3>
#include <GUIListView.au3>

$gui = GUICreate("listview items", 320, 250, 100, 200)
$listview = GUICtrlCreateListView("col1 |col2|col3 ", 10, 10, 200, 150);,$LVS_SORTDESCENDING)
$hListView = ControlGetHandle($gui, '', $listview)
$button1 = GUICtrlCreateButton("Create std", 15, 170, 70, 20)
$button2 = GUICtrlCreateButton("Create UDF", 125, 170, 70, 20)
$button3 = GUICtrlCreateButton("Delete UDF", 200, 170, 70, 20)
$input1 = GUICtrlCreateInput("", 20, 200, 150)
GUISetState()

Do
    $msg = GUIGetMsg()

    Select
        Case $msg = $button1
            $start = TimerInit()
            For $i = 1 To 4000
                GUICtrlCreateListViewItem("item1|col2|col3", $listview)
            Next
            GUICtrlSetData($input1, 'Time: ' & TimerDiff($start))
            ; 440 ms (650)

        Case $msg = $button2
            $start = TimerInit()
            For $i = 1 To 4000
                _GUICtrlListView_AddItem($ListView, "item1|col2|col3")
;~              _GUICtrlListView_AddItem($hListView, "item1|col2|col3")
            Next
            GUICtrlSetData($input1, 'Time: ' & TimerDiff($start))
            ; 1250 ms with $ListView (2650)
            ; 1980 ms with $hListView (12000)
                    Case $msg = $button3
            _GUICtrlListView_DeleteAllItems($hListView)
                EndSelect
Until $msg = $GUI_EVENT_CLOSE

Is this only _GUICtrlListView_AddItem() speed limitation or some bug/not optimized code in UDF?

Edited by Zedna

Share this post


Link to post
Share on other sites



Look at _GUICtrlListView_InsertItem, if you can see a way to optimize i'm all for it.


SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

Share this post


Link to post
Share on other sites

1) GUICtrlCreateListViewItem() - very quick

2) _GUICtrlListView_AddItem(ControlId) - MUCH slower

3) _GUICtrlListView_AddItem(ControlHwnd) - even MUCH more slower

I think 1) and 2) should have similar time consume amount and not such big differences.

I saw it's sources.

Times in parenthesis are from another computer.

All times are avg from several runs (all on 3.2.10 version)

#include <GUIConstants.au3>
#include <GUIListView.au3>

$gui = GUICreate("listview items", 320, 250, 100, 200)
$listview = GUICtrlCreateListView("col1 |col2|col3 ", 10, 10, 200, 150);,$LVS_SORTDESCENDING)
$hListView = ControlGetHandle($gui, '', $listview)
$button1 = GUICtrlCreateButton("Create std", 15, 170, 70, 20)
$button2 = GUICtrlCreateButton("Create UDF", 125, 170, 70, 20)
$button3 = GUICtrlCreateButton("Delete UDF", 200, 170, 70, 20)
$input1 = GUICtrlCreateInput("", 20, 200, 150)
GUISetState()

Do
    $msg = GUIGetMsg()

    Select
        Case $msg = $button1
            $start = TimerInit()
            For $i = 1 To 4000
                GUICtrlCreateListViewItem("item1|col2|col3", $listview)
            Next
            GUICtrlSetData($input1, 'Time: ' & TimerDiff($start))
            ; 440 ms (650)

        Case $msg = $button2
            $start = TimerInit()
            For $i = 1 To 4000
                _GUICtrlListView_AddItem($ListView, "item1|col2|col3")
;~              _GUICtrlListView_AddItem($hListView, "item1|col2|col3")
            Next
            GUICtrlSetData($input1, 'Time: ' & TimerDiff($start))
            ; 1250 ms with $ListView (2650)
            ; 1980 ms with $hListView (12000)
                    Case $msg = $button3
            _GUICtrlListView_DeleteAllItems($hListView)
                EndSelect
Until $msg = $GUI_EVENT_CLOSE

Is this only _GUICtrlListView_AddItem() speed limitation or some bug/not optimized code in UDF?

This is largely a Windows problem IMO. I have had exactly this problem in Delphi with sorting listviews.

I think the reason is that windows tries to redraw the listview every time an item is added. If you stop it being redrawn, for example by hiding it, then it is much faster.

#include <GUIConstants.au3>
#include <GUIListView.au3>

$gui = GUICreate("listview items", 320, 250, 100, 200)
$listview = GUICtrlCreateListView("col1 |col2|col3 ", 10, 10, 200, 150);,$LVS_SORTDESCENDING)
$hListView = ControlGetHandle($gui, '', $listview)
$button1 = GUICtrlCreateButton("Create std", 15, 170, 70, 20)
$button2 = GUICtrlCreateButton("Create UDF", 125, 170, 70, 20)
$button3 = GUICtrlCreateButton("Delete UDF", 200, 170, 70, 20)
$input1 = GUICtrlCreateInput("", 20, 200, 150)
GUISetState()

Do
    $msg = GUIGetMsg()

    Select
        Case $msg = $button1
        ;GUICtrlSetState($listview,$GUI_HIDE)
            _SendMessage(ControlGetHandle($gui,"",$listview),$WM_SETREDRAW,0,0)
            $start = TimerInit()
            For $i = 1 To 4000
                GUICtrlCreateListViewItem("item1|col2|col3", $listview)
            Next
            GUICtrlSetData($input1, 'Time: ' & TimerDiff($start))
        ;GUICtrlSetState($listview,$GUI_SHOW)
            _SendMessage(ControlGetHandle($gui,"",$listview),$WM_SETREDRAW,1,0)
           ; 440 ms (650)

        Case $msg = $button2
            $start = TimerInit()
            For $i = 1 To 4000
                _GUICtrlListView_AddItem($ListView, "item1|col2|col3")
;~   _GUICtrlListView_AddItem($hListView, "item1|col2|col3")
            Next
            GUICtrlSetData($input1, 'Time: ' & TimerDiff($start))
           ; 1250 ms with $ListView (2650)
           ; 1980 ms with $hListView (12000)
                    Case $msg = $button3
            _GUICtrlListView_DeleteAllItems($hListView)
                EndSelect
Until $msg = $GUI_EVENT_CLOSE

(Your PC is about 2 times faster than mine :) )


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

Look at _GUICtrlListView_InsertItem, if you can see a way to optimize i'm all for it.

Maybe look into AutoIt sources and compare native AutoIt with UDF because native one is speed winner.

I have no access to AutoIt GUI sources.

Share this post


Link to post
Share on other sites

_GUICtrlListView_BeginUpdate

_GUICtrlListView_EndUpdate

Oh yes, thanks.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

Compiled code is much faster than interpreted code, that's a given.

I'm surprised that you are surprised. :)

You can optimize it to perform better in such benchmark, for example, _GUICtrlListView_AddItem() in fact does nothing but call the _GUICtrlListView_InsertItem(), so simply by calling the latter yourself you'd make that 4000 iteration loop a tiny bit faster. Also, if you "saw it's sources", there's quite a few things that need to be done before actual sendmessage takes place, and that's repeated for each iteration - waste of precious time if you intend to add that many items in a row (as basically you only need to repeat 2 actions - setting new text in buffer and sending LVM_INSERTITEM message). You could write custom function moving the For loop inside of it, and that would reduce total time dramatically. But it will be slower still, as it should.


"be smart, drink your wine"

Share this post


Link to post
Share on other sites

This is largely a Windows problem IMO. I have had exactly this problem in Delphi with sorting listviews.

I think the reason is that windows tries to redraw the listview every time an item is added. If you stop it being redrawn, for example by hiding it, then it is much faster.

You are absolutely right about _SendMessage($hlistview,$WM_SETREDRAW,0,0) stuff, thanks.

With this optimization it's faster but relative differences among 1) 2) 3) cases are the same.

So question still remains: Why is native GUICtrlCreateListViewItem() so much faster?

Share this post


Link to post
Share on other sites

Compiled code is much faster than interpreted code, that's a given.

I'm surprised that you are surprised. :)

You can optimize it to perform better in such benchmark, for example, _GUICtrlListView_AddItem() in fact does nothing but call the _GUICtrlListView_InsertItem(), so simply by calling the latter yourself you'd make that 4000 iteration loop a tiny bit faster. Also, if you "saw it's sources", there's quite a few things that need to be done before actual sendmessage takes place, and that's repeated for each iteration - waste of precious time if you intend to add that many items in a row (as basically you only need to repeat 2 actions - setting new text in buffer and sending LVM_INSERTITEM message). You could write custom function moving the For loop inside of it, and that would reduce total time dramatically. But it will be slower still, as it should.

Yes Siao you are right.

I know used UDFs are general so they have some overhead.

But I didn't expect 3times or 4times worse time than native one.

So I asked question if there is some "magic" code used inside native GUICtrlCreateListViewItem().

I will definitely try new tests based on your and martin's ideas and I will post results...

Thanks for all ideas.

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

Here is optimized version which is even quicker than native one!

But I noticed that UDF and also my optimized UDF only adds first column and not all subitems like native one.

So I will create also test for all subitems.

Note: Times are:  without WM_SETREDRAW / with $WM_SETREDRAW = 0

native: 440/310 ms

UDF: 1250/1120 ms

UDF optimized: 365/240 ms

#include <GUIConstants.au3>
#include <GUIListView.au3>

$gui = GUICreate("listview items", 320, 250, 100, 200)
$listview = GUICtrlCreateListView("col1 |col2|col3 ", 10, 10, 200, 150);,$LVS_SORTDESCENDING)
$hListView = ControlGetHandle($gui, '', $listview)
$button1 = GUICtrlCreateButton("Create std", 15, 170, 70, 20)
$button2 = GUICtrlCreateButton("Create UDF", 125, 170, 70, 20)
$button3 = GUICtrlCreateButton("Delete UDF", 200, 170, 70, 20)
$input1 = GUICtrlCreateInput("", 20, 200, 150)
GUISetState()

Global $pBuffer, $tBuffer, $pItem, $tItem

$tItem = DllStructCreate($tagLVITEM)
$pItem = DllStructGetPtr($tItem)
$tBuffer = DllStructCreate("char Text[2048]")
$pBuffer = DllStructGetPtr($tBuffer)
DllStructSetData($tItem, "Text", $pBuffer)
DllStructSetData($tItem, "TextMax", 2048)
DllStructSetData($tItem, "Mask", BitOR($LVIF_TEXT, $LVIF_PARAM))
DllStructSetData($tItem, "Item", 999999999)
DllStructSetData($tItem, "Image", -1)

Do
    $msg = GUIGetMsg()

    Select
        Case $msg = $button1
            _SendMessage($hlistview,$WM_SETREDRAW,0,0)
;~          _GUICtrlListView_BeginUpdate($ListView)
            $start = TimerInit()
            For $i = 1 To 4000
                GUICtrlCreateListViewItem("item1|col2|col3", $listview)
            Next
            GUICtrlSetData($input1, 'Time: ' & TimerDiff($start))
            _SendMessage($hlistview,$WM_SETREDRAW,1,0)
;~          _GUICtrlListView_EndUpdate($ListView)
            ; 440/310 ms (650/280)

        Case $msg = $button2
            _SendMessage($hlistview,$WM_SETREDRAW,0,0)
            $start = TimerInit()
            For $i = 1 To 4000
;~              _GUICtrlListView_AddItem($ListView, "item1|col2|col3")
;~              _GUICtrlListView_AddItem($hListView, "item1|col2|col3")
                _GUICtrlListView_InsertItem_Optim($ListView, "item1|col2|col3")
            Next
            GUICtrlSetData($input1, 'Time: ' & TimerDiff($start))
            _SendMessage($hlistview,$WM_SETREDRAW,1,0)
            ; 1250/1120 ms with $ListView (2650/2000)
            ; 1980/1850ms with $hListView (12000/9280)
            ; 365/240 optim with $ListView
                    Case $msg = $button3
            _GUICtrlListView_DeleteAllItems($hListView)
                EndSelect
Until $msg = $GUI_EVENT_CLOSE

Func _GUICtrlListView_InsertItem_Optim($hWnd, $sText)
    DllStructSetData($tItem, "Param", GUICtrlSendMsg($hWnd, $LVM_GETITEMCOUNT, 0, 0))
    DllStructSetData($tBuffer, "Text", $sText)
    Return GUICtrlSendMsg($hWnd, $LVM_INSERTITEMA, 0, $pItem)
EndFunc
Edited by Zedna

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

Here is optimized version which is even quicker than native one!

But I noticed that UDF and also my optimized UDF only adds first column and not all subitems like native one.

So I will create also test for all subitems.

Note: Times are:  without WM_SETREDRAW / with $WM_SETREDRAW = 0

native: 440/310 ms

UDF: 1250/1120 ms

UDF optimized: 365/240 ms

I changed previous test only for adding 1 (first) column so it could be comparable between native and UDF version

Here are results:

Note: Times are: with $WM_SETREDRAW = 0

native: 110 ms

UDF: 1125 ms

UDF optimized: 235 ms

Edited by Zedna

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

I changed previous test only for adding 1 (first) column so it could be comparable between native and UDF version

Here are results:

Note: Times are: with $WM_SETREDRAW = 0

native: 110 ms

UDF: 1125 ms

UDF optimized: 235 ms

I removed $LVIF_PARAM and DllStructSetData($tItem, "Param", GUICtrlSendMsg($hWnd, $LVM_GETITEMCOUNT, 0, 0))

in my optimized UDF version and results is

UDF optimized: 160 ms (without LVIF_PARAM)

#include <GUIConstants.au3>
#include <GUIListView.au3>

$gui = GUICreate("listview items", 320, 250, 100, 200)
$listview = GUICtrlCreateListView("col1 ", 10, 10, 200, 150);,$LVS_SORTDESCENDING)
$hListView = ControlGetHandle($gui, '', $listview)
$button1 = GUICtrlCreateButton("Create std", 15, 170, 70, 20)
$button2 = GUICtrlCreateButton("Create UDF", 125, 170, 70, 20)
$button3 = GUICtrlCreateButton("Delete UDF", 200, 170, 70, 20)
$input1 = GUICtrlCreateInput("", 20, 200, 150)
GUISetState()

Global $pBuffer, $tBuffer, $pItem, $tItem

$tItem = DllStructCreate($tagLVITEM)
$pItem = DllStructGetPtr($tItem)
$tBuffer = DllStructCreate("char Text[2048]")
$pBuffer = DllStructGetPtr($tBuffer)
DllStructSetData($tItem, "Text", $pBuffer)
DllStructSetData($tItem, "TextMax", 2048)
DllStructSetData($tItem, "Mask", $LVIF_TEXT)
DllStructSetData($tItem, "Item", 999999999)
DllStructSetData($tItem, "Image", -1)

Do
    $msg = GUIGetMsg()

    Select
        Case $msg = $button1
            _SendMessage($hlistview,$WM_SETREDRAW,0,0)
;~          _GUICtrlListView_BeginUpdate($ListView)
            $start = TimerInit()
            For $i = 1 To 4000
                GUICtrlCreateListViewItem("item1", $listview)
            Next
            GUICtrlSetData($input1, 'Time: ' & TimerDiff($start))
            _SendMessage($hlistview,$WM_SETREDRAW,1,0)
;~          _GUICtrlListView_EndUpdate($ListView)
            ; 440/310 ms (650/280)

        Case $msg = $button2
            _SendMessage($hlistview,$WM_SETREDRAW,0,0)
            $start = TimerInit()
            For $i = 1 To 4000
;~              _GUICtrlListView_AddItem($ListView, "item1")
;~              _GUICtrlListView_AddItem($hListView, "item1")
                _GUICtrlListView_InsertItem_Optim($ListView, "item1")
            Next
            GUICtrlSetData($input1, 'Time: ' & TimerDiff($start))
            _SendMessage($hlistview,$WM_SETREDRAW,1,0)
            ; 1250/1120 ms with $ListView (2650/2000)
            ; 1980/1850ms with $hListView (12000/9280)
            ; 365/240 optim with $ListView
                    Case $msg = $button3
            _GUICtrlListView_DeleteAllItems($hListView)
                EndSelect
Until $msg = $GUI_EVENT_CLOSE

Func _GUICtrlListView_InsertItem_Optim($hWnd, $sText)
    DllStructSetData($tBuffer, "Text", $sText)
    Return GUICtrlSendMsg($hWnd, $LVM_INSERTITEMA, 0, $pItem)
EndFunc
Edited by Zedna

Share this post


Link to post
Share on other sites

Now I randomly noticed there is _GUICtrlListView_AddArray() function which is based on the same optimization idea!!

So I found America once again today :)

It happens. :)

Can't remember everything I've done.


SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

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  
Followers 0