Author |
Topic: Turning BB into ASM code (Read 1163 times) |
|
Michael Hutton
Developer
member is offline


Gender: 
Posts: 248
|
 |
Re: Turning BB into ASM code
« Reply #3 on: May 31st, 2013, 7:42pm » |
|
Matt,
There is probably no real benefit in asm coding the SendMessage - as you may find out the delay is in Windows processing the messages not how fast you send them. There is no real way to speed this up. I know this because I have done exactly the same experimentation. Coding SYS calls will hardly ever result in a speed up unless you are using the SYS call to enter some user written routine and then only when in a very tight loop.
Write it all out in BASIC then profile it and find out what is causing the delay. Only then spend the time and effort to write the ASM code for the bits you might save time on.
Michael
|
|
Logged
|
|
|
|
Matt
Developer
member is offline


Gender: 
Posts: 210
|
 |
Re: Turning BB into ASM code
« Reply #4 on: May 31st, 2013, 8:05pm » |
|
Thanks Michael.
on May 31st, 2013, 7:42pm, Michael Hutton wrote:| Write it all out in BASIC then profile it and find out what is causing the delay. Only then spend the time and effort to write the ASM code for the bits you might save time on. |
|
As before, the main delay seems to be SYS commands. If even MC will not help this, then I'll have to figure out some other way to do it. Perhaps going back to increasing the size of the available memory.
Matt
|
|
Logged
|
|
|
|
admin
Administrator
member is offline


Posts: 1145
|
 |
Re: Turning BB into ASM code
« Reply #5 on: May 31st, 2013, 8:54pm » |
|
on May 31st, 2013, 5:05pm, Matt wrote:| Hope you can glean some helpful info from this. |
|
It confirms what I thought: converting to assembler code is unlikely to make much difference to the speed. You can usefully replace the SYS "SendMessage" with the numeric equivalent e.g. SYS SendMessage% (where the value is established using GetProcAddress during initialisation). That will avoid the 'lookup' overhead, but otherwise you might as well leave the code in BASIC I would have thought.
Richard.
|
|
Logged
|
|
|
|
Matt
Developer
member is offline


Gender: 
Posts: 210
|
 |
Re: Turning BB into ASM code
« Reply #6 on: Jun 1st, 2013, 07:13am » |
|
on May 31st, 2013, 8:54pm, Richard Russell wrote:You can usefully replace the SYS "SendMessage" with the numeric equivalent e.g. SYS SendMessage% (where the value is established using GetProcAddress during initialisation). |
|
I've put this at the front end of the program: Code:
SYS "LoadLibrary", "User32.dll" TO u32%
SYS "GetProcAddress", u32%, "SendMessage" TO SendMessage% (This appears to be the correct dll file according to the MS website.)
However, SendMessage% contains zero, which results in an 'Address out of range' error when it's called.
Matt
|
|
Logged
|
|
|
|
admin
Administrator
member is offline


Posts: 1145
|
 |
Re: Turning BB into ASM code
« Reply #7 on: Jun 1st, 2013, 08:43am » |
|
on Jun 1st, 2013, 07:13am, Matt wrote:| However, SendMessage% contains zero, which results in an 'Address out of range' error when it's called. |
|
Use this code:
Code: SYS "GetModuleHandle", "USER32" TO H%
SYS "GetProcAddress", H%, "SendMessageA" TO SendMessage%
Richard.
|
|
Logged
|
|
|
|
Michael Hutton
Developer
member is offline


Gender: 
Posts: 248
|
 |
Re: Turning BB into ASM code
« Reply #8 on: Jun 1st, 2013, 3:21pm » |
|
Although, using ASM code does have one advantage, especially in BB4W as there is no native multithreaded support, if you want to populate a large list view but want to go on and do something else in the meantime you could create a worker thread quite easily to send all the information and then wait for it to complete.
Michael
|
|
Logged
|
|
|
|
Matt
Developer
member is offline


Gender: 
Posts: 210
|
 |
Re: Turning BB into ASM code
« Reply #9 on: Jun 1st, 2013, 5:12pm » |
|
Thanks Richard. on Jun 1st, 2013, 08:43am, Richard Russell wrote:Use this code:
Code: SYS "GetModuleHandle", "USER32" TO H%
SYS "GetProcAddress", H%, "SendMessageA" TO SendMessage%
Richard. |
|
This does work now. However, it unfortunately only increases the speed by around 5%. It was worth a try.
Matt
|
|
Logged
|
|
|
|
Matt
Developer
member is offline


Gender: 
Posts: 210
|
 |
Re: Turning BB into ASM code
« Reply #10 on: Jun 1st, 2013, 5:16pm » |
|
Thanks Michael.
on Jun 1st, 2013, 3:21pm, Michael Hutton wrote:| Although, using ASM code does have one advantage, especially in BB4W as there is no native multithreaded support, if you want to populate a large list view but want to go on and do something else in the meantime you could create a worker thread quite easily to send all the information and then wait for it to complete. |
|
At present, I'm struggling to cope with basic ASM without trying to do multithread, but thanks.
Matt
|
|
Logged
|
|
|
|
Michael Hutton
Developer
member is offline


Gender: 
Posts: 248
|
 |
Re: Turning BB into ASM code
« Reply #11 on: Jun 1st, 2013, 6:39pm » |
|
Here is some code to play with for filling out a ListView. Tomorrow I'll try to make it multithreaded for you . I have to go out now.
Code:
REM Demo of filling a ListView Control with Dummy Data
REM Install Libraries
INSTALL @lib$ + "WINLIB5"
REM!WC Windows Constants
LVIS_SELECTED = &2
LVM_SETCOLUMNWIDTH = &101E
LVSCW_AUTOSIZE = -1
LVS_REPORT = &1
REM Define lvitem and lvcolumn structures
DIM lvitem{mask%, \
\ iItem%, \
\ iSubItem%, \
\ state%, \
\ stateMask%, \
\ pszText%, \
\ cchTextMax%, \
\ iImage%, \
\ lParam%, \
\ iIndent% }
DIM column{mask%, \
\ fmt%, \
\ cx%, \
\ pszText%, \
\ cchTextMax%, \
\ iSubItem% }
column.mask% = 15 : REM LVCF_WIDTH | LVCF_SUBITEM | LVCF_FMT | LVCF_TEXT
REM Define the number of row and columns (includes 0)
MAXCOL% = 99
MAXROW% = 99
REM Create Dummy Data
DIM Data$(MAXCOL%, MAXROW%)
FOR col% = 0 TO MAXCOL%
FOR row% = 0 TO MAXROW%
Data$(row%,col%) = STR$(row%) + STR$(col%) + CHR$0
NEXT
NEXT
REM Create a list View
SYS "InitCommonControls"
hList% = FN_createwindow("SysListView32","",100,100,@vdu%!28,@vdu%!36,0,LVS_REPORT,0) : REM LVS_REPORT
REM Assemble our machine code routine
PROC_AssembleMachineCode
REM Insert the Headers of the list View
FOR C% = 0 TO MAXCOL%
head$ = STR$(C%) + CHR$0
column.cx% = 50
column.pszText% = !^head$
column.iSubItem% = C%
SYS "SendMessage", hList%, &101B, C%, column{} : REM LVM_INSERTCOLUMN
NEXT
REM Fill the list view with Dummy data in BB4W
T = TIME
REM FOR col% = 0 TO MAXCOL%
REM FOR row% = 0 TO MAXROW%
REM PROCaddtolist(row%, col%, Data$(row%,col%))
REM NEXT
REM NEXT
TT = TIME-T
PRINT TT
T = TIME
CALL FillListView
TT = TIME-T
PRINT TT
REM PROCReSizeColumns(LVSCW_AUTOSIZE)
END
REM **** PROCEDURES ****
DEF PROCaddtolist(R%, C%, text$)
text$ += CHR$0
lvitem.mask% = 13 : REM LVIF_TEXT | LVIF_STATE | LVIF_PARAM
lvitem.stateMask% = LVIS_SELECTED
lvitem.iItem% = R%
lvitem.iSubItem% = C%
lvitem.pszText% = !^text$
lvitem.cchTextMax% = LENtext$
REM lvitem.lParam% = I% : REM Must Write this parameter for sort to work
IF C% THEN
SYS "SendMessage", hList%, &102E, R%, lvitem{} : REM LVM_SETITEMTEXT
ELSE
SYS "SendMessage", hList%, &1007, R%, lvitem{} : REM LVM_INSERTITEM
ENDIF
ENDPROC
DEF PROCReSizeColumns(O%)
LOCAL I%
FOR I%=0 TO MAXCOL%
SYS "SendMessage", hList%, LVM_SETCOLUMNWIDTH, I%, O%
NEXT
SYS "RedrawWindow", hList% , 0, 0, &101
ENDPROC
DEF PROC_AssembleMachineCode
LOCAL P%, L%, code%, opt%
DIM code% 500, L% -1
FOR opt% = 8 TO 10 STEP 2
P% = code%
[OPT opt%
.FillListView
mov esi, 0
.outerloop
mov edi, 0
.innerloop
mov edx, ^Data$(0,0)
mov ecx, esi
imul ecx, MAXCOL% + 1
add ecx, edi
imul ecx, 6
mov eax, [edx + ecx]
mov dword [^lvitem.mask%], 13 ;REM LVIF_TEXT | LVIF_STATE | LVIF_PARAM
mov dword [^lvitem.stateMask%], LVIS_SELECTED
mov dword [^lvitem.iItem%], edi
mov dword [^lvitem.iSubItem%], esi
mov dword [^lvitem.pszText%], eax
mov dword [^lvitem.cchTextMax%], 20 ;REM max text size
mov dword [^lvitem.lParam%], I% ;REM Must Write this parameter for sort to work
cmp esi,0
je insert
push lvitem{}
push edi
push &102E
push hList%
call "SendMessage"
jmp next
.insert
push lvitem{}
push edi
push &1007
push hList%
call "SendMessage"
.next
inc edi
cmp edi, [^MAXROW%]
jbe near innerloop
inc esi
cmp esi, [^MAXCOL%]
jbe near outerloop
ret
]
NEXT
ENDPROC
Michael
|
|
Logged
|
|
|
|
admin
Administrator
member is offline


Posts: 1145
|
 |
Re: Turning BB into ASM code
« Reply #12 on: Jun 1st, 2013, 9:58pm » |
|
on Jun 1st, 2013, 5:12pm, Matt wrote:| However, it unfortunately only increases the speed by around 5%. |
|
5% is worth having, isn't it? There's no way you are ever going to be able to boost the performance by a large amount, without abandoning the List View altogether and writing your own faster replacement.
Richard.
|
|
Logged
|
|
|
|
Matt
Developer
member is offline


Gender: 
Posts: 210
|
 |
Re: Turning BB into ASM code
« Reply #13 on: Jun 2nd, 2013, 04:45am » |
|
on Jun 1st, 2013, 9:58pm, Richard Russell wrote:| 5% is worth having, isn't it? |
|
Any increase is worth having, but I was hoping for a far higher one.
Quote:| There's no way you are ever going to be able to boost the performance by a large amount, without abandoning the List View altogether and writing your own faster replacement. |
|
In the long run, that seems it might be the only way.
Thanks, though.
Matt
|
|
Logged
|
|
|
|
Michael Hutton
Developer
member is offline


Gender: 
Posts: 248
|
 |
Re: Turning BB into ASM code
« Reply #14 on: Jun 2nd, 2013, 1:49pm » |
|
Two things Matt, and I think this will just confirm what Richard has said. If your looking for performance a ListView is not the way to go, but what are you trying to do? Manipulate or view the data? If you you want to manipulate the data do it outside of the list view, if you are just viewing it there is no issue, however long the computer takes to fill it there is no way a human can read it faster.
If you are worried that the program stalls while it is loading the list view then look below as the solution is to create another thread to fill it while you can carry on with the main program. Just for fun I have got the main program to calculate and print out the digits of pi while the worker thread populates the ListView with the data, but I hope you see the important lines are the CreateThread and the WaitForSingleObject.
Does this provide a solution for you?
Code:
REM Demo of filling a ListView Control with Dummy Data
HIMEM = LOMEM + &1000000
MODE 8
REM Install Libraries
INSTALL @lib$ + "WINLIB5"
REM!WC Windows Constants
LVIS_SELECTED = &2
LVM_SETCOLUMNWIDTH = &101E
LVSCW_AUTOSIZE = -1
LVS_REPORT = &1
REM Define lvitem and lvcolumn structures
DIM lvitem{mask%, \
\ iItem%, \
\ iSubItem%, \
\ state%, \
\ stateMask%, \
\ pszText%, \
\ cchTextMax%, \
\ iImage%, \
\ lParam%, \
\ iIndent% }
DIM column{mask%, \
\ fmt%, \
\ cx%, \
\ pszText%, \
\ cchTextMax%, \
\ iSubItem% }
column.mask% = 15 : REM LVCF_WIDTH | LVCF_SUBITEM | LVCF_FMT | LVCF_TEXT
REM Define the number of row and columns (includes 0)
MAXCOL% = 599
MAXROW% = 599
REM Create Dummy Data
DIM Data$(MAXCOL%, MAXROW%)
FOR col% = 0 TO MAXCOL%
FOR row% = 0 TO MAXROW%
Data$(row%,col%) = STR$(row%) + STR$(col%) + CHR$0
NEXT
NEXT
REM Create a list View
SYS "InitCommonControls"
hList% = FN_createwindow("SysListView32","",100,100,400,400,0,LVS_REPORT,0) : REM LVS_REPORT
REM Assemble our machine code routine
PROC_AssembleMachineCode
REM Insert the Headers of the list View
FOR C% = 0 TO MAXCOL%
head$ = STR$(C%) + CHR$0
column.cx% = 50
column.pszText% = !^head$
column.iSubItem% = C%
SYS "SendMessage", hList%, &101B, C%, column{} : REM LVM_INSERTCOLUMN
NEXT
SYS "CreateThread", 0, 1024, FillListView, 0, 0, 0 TO hThread%
IF hThread% = 0 THEN ERROR,"Failed to create Thread 1."
REM Or you could do something like this Matt
REM I% = 0
REM REPEAT
REM I% += 1
REM PRINT TAB(0,0) "In the meantime I'm going to count to ";I%
REM SYS "WaitForSingleObject", hThread%, 1 TO R%
REM UNTIL R% = 0
f% = 12000
f% = (f% DIV 4) * 14
DIM f%(f%)
f%() = 2000
a% = 10000
e% = 0
FOR c% = f% TO 14 STEP -14
d% = 0
FOR b% = c% TO 1 STEP -1
d% *= b%
g% = b%*2-1
d% += f%(b%)*a%
f%(b%) = d% MOD g%
d% DIV= g%
NEXT
PRINT RIGHT$("000"+STR$(e% + d% DIV a%),4);
e% = d% MOD a%
SYS "WaitForSingleObject", hThread%, 1 TO R%
IF R% = 0 THEN EXIT FOR
NEXT
END
REM **** PROCEDURES ****
DEF PROCaddtolist(R%, C%, text$)
text$ += CHR$0
lvitem.mask% = 13 : REM LVIF_TEXT | LVIF_STATE | LVIF_PARAM
lvitem.stateMask% = LVIS_SELECTED
lvitem.iItem% = R%
lvitem.iSubItem% = C%
lvitem.pszText% = !^text$
lvitem.cchTextMax% = LENtext$
REM lvitem.lParam% = I% : REM Must Write this parameter for sort to work
IF C% THEN
SYS "SendMessage", hList%, &102E, R%, lvitem{} : REM LVM_SETITEMTEXT
ELSE
SYS "SendMessage", hList%, &1007, R%, lvitem{} : REM LVM_INSERTITEM
ENDIF
ENDPROC
DEF PROCReSizeColumns(O%)
LOCAL I%
FOR I%=0 TO MAXCOL%
SYS "SendMessage", hList%, LVM_SETCOLUMNWIDTH, I%, O%
NEXT
SYS "RedrawWindow", hList% , 0, 0, &101
ENDPROC
DEF PROC_AssembleMachineCode
LOCAL P%, L%, code%, opt%
DIM code% 500, L% -1
FOR opt% = 8 TO 10 STEP 2
P% = code%
[OPT opt%
.FillListView
mov esi, 0
.outerloop
mov edi, 0
.innerloop
mov edx, ^Data$(0,0)
mov ecx, esi
imul ecx, MAXCOL% + 1
add ecx, edi
imul ecx, 6
mov eax, [edx + ecx]
mov dword [^lvitem.mask%], 13 ;REM LVIF_TEXT | LVIF_STATE | LVIF_PARAM
mov dword [^lvitem.stateMask%], LVIS_SELECTED
mov dword [^lvitem.iItem%], edi
mov dword [^lvitem.iSubItem%], esi
mov dword [^lvitem.pszText%], eax
mov dword [^lvitem.cchTextMax%], 20 ;REM max text size
mov dword [^lvitem.lParam%], I% ;REM Must Write this parameter for sort to work
cmp esi,0
je insert
push lvitem{}
push edi
push &102E
push hList%
call "SendMessage"
jmp next
.insert
push lvitem{}
push edi
push &1007
push hList%
call "SendMessage"
.next
inc edi
cmp edi, [^MAXROW%]
jbe near innerloop
inc esi
cmp esi, [^MAXCOL%]
jbe near outerloop
ret
]
NEXT
ENDPROC
|
|
|
|
Matt
Developer
member is offline


Gender: 
Posts: 210
|
 |
Re: Turning BB into ASM code
« Reply #15 on: Jun 2nd, 2013, 6:51pm » |
|
on Jun 2nd, 2013, 1:49pm, Michael Hutton wrote:| what are you trying to do? Manipulate or view the data? If you you want to manipulate the data do it outside of the list view, if you are just viewing it there is no issue, however long the computer takes to fill it there is no way a human can read it faster. |
|
In reality, it's probably viewing. Any manipulation of the data is already done outside the LV. However, each time manipulation is done, the list needs to be re-listed due to various parameter changes. I will have to consider the idea of threading, as the list needs to be complete for the user to act on any of the items.
With a little change (mainly listing row for row, rather than column for column), your ASM code passes 10,000 lines through in 10 seconds, which is far faster than before.
Quote:| If you are worried that the program stalls while it is loading the list view then look below as the solution is to create another thread to fill it while you can carry on with the main program... I hope you see the important lines are the CreateThread and the WaitForSingleObject. |
|
Thanks. Much appreciated. I'll examine it and see whether I can implement it.
Matt
|
|
Logged
|
|
|
|
admin
Administrator
member is offline


Posts: 1145
|
 |
Re: Turning BB into ASM code
« Reply #16 on: Jun 2nd, 2013, 9:33pm » |
|
on Jun 2nd, 2013, 6:51pm, Matt wrote:| In reality, it's probably viewing. |
|
I must support what Michael has said. If you need to display 10,000 items in a List View the design of your user interface is probably not optimal. I would suggest you forget about the speed issue completely, step back, and look at things from the point of view of your final user. A different design of user interface will probably solve the problem without any need for assembler code, multi-threading and so on.
Richard.
|
|
Logged
|
|
|
|
Matt
Developer
member is offline


Gender: 
Posts: 210
|
 |
Re: Turning BB into ASM code
« Reply #17 on: Jun 3rd, 2013, 04:37am » |
|
on Jun 2nd, 2013, 9:33pm, Richard Russell wrote:| I must support what Michael has said. If you need to display 10,000 items in a List View the design of your user interface is probably not optimal. I would suggest you forget about the speed issue completely, step back, and look at things from the point of view of your final user. A different design of user interface will probably solve the problem without any need for assembler code, multi-threading and so on. |
|
I'm unsure what you mean by 'A different design...'. There are three ways that I'm aware of that I can list the items: a Listview (tried), a list box (guessing, the same results) and directly in the main or a child window. Would you be suggesting that I try using the third, or is there another way I haven't thought of? Or are you simply suggesting using what I have but in a different way? (Or am I just missing the point of you comment altogether?)
Matt
Edit: A thought has just occured to me that I could display the first, say, 1000 items and wait for the user to move down the list to the bottom and than send the next 1000 items. Displaying 1000 items in the normal way (array and send to LV through basic) takes a mere 3 seconds. However, I need to know how to test whether the scroll bar of the Listview is at the bottom. Will investigate.
Edit: This appears to be: Code:
SYS "GetScrollPos", hlist%, SB_VERT TO hBarPos%
However, for 1000 items this only goes up to 966. The shortfall appears to be the number of lines on display.
If I can get this working, it will overcome the main time problem.
Thanks to both of you for your input. It has been much appreciated and very enlightening. Please comment further if you can as I feel I'm learning a lot about this (both ASM and LVs)
Matt
|
| « Last Edit: Jun 3rd, 2013, 05:46am by Matt » |
Logged
|
|
|
|
|