BBC BASIC for Windows
« Turning BB into ASM code »

Welcome Guest. Please Login or Register.
Apr 5th, 2018, 9:57pm



ATTENTION MEMBERS: Conforums will be closing it doors and discontinuing its service on April 15, 2018.
Ad-Free has been deactivated. Outstanding Ad-Free credits will be reimbursed to respective payment methods.

If you require a dump of the post on your message board, please come to the support board and request it.


Thank you Conforums members.

BBC BASIC for Windows Resources
Online BBC BASIC for Windows documentation
BBC BASIC for Windows Beginners' Tutorial
BBC BASIC Home Page
BBC BASIC on Rosetta Code
BBC BASIC discussion group
BBC BASIC for Windows Programmers' Reference

« Previous Topic | Next Topic »
Pages: 1 2  Notify Send Topic Print
 veryhotthread  Author  Topic: Turning BB into ASM code  (Read 1158 times)
Matt
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 210
xx Turning BB into ASM code
« Thread started on: May 31st, 2013, 07:32am »

Ok. Really struggling here.

I'm not after direct answers, but I could use a few pointers.

This is the portion of code (slightly edited) that I want to change into MC.

Code:
      FOR col%=0 TO Headers% - 1
        lvitem%!0=13
        lvitem%!4=line%
        lvitem%!8=col%
        lvitem%!20=!^detail$(col%)
        lvitem%!24=LEN(detail$(col%))
        lvitem%!32=line%
        IF col% THEN
          SYS "SendMessage", hlist%, &102E, line%, lvitem%
        ELSE
          SYS "SendMessage", hlist%, &1007, line%, lvitem%
        ENDIF
      NEXT 


Now, I think I've managed to work out how to deal with basic variables: [^variable], and I can send the SYS commands using push. However, arrays are a complete mystery. I know that they are not stored in memory the same as variables, but I'm not sure how to access them or use a 'count' to work my way through the array.

Any pointers?

Matt
User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Turning BB into ASM code
« Reply #1 on: May 31st, 2013, 4:05pm »

on May 31st, 2013, 07:32am, Matt wrote:
This is the portion of code (slightly edited) that I want to change into MC.

Why? Given that it is presumably populating a list control it doesn't seem very likely that it would run much faster. Before contemplating conversion to assembler code I'd want to see the relevant extract from the Profiler report file to see exactly where the time is being spent. Perhaps you could list that so we can see the evidence on which you are basing your decision.

Richard.
User IP Logged

Matt
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 210
xx Re: Turning BB into ASM code
« Reply #2 on: May 31st, 2013, 5:05pm »

I'm trying to load 10,000 dummy lines into the listview. I have three ways to do this.

1. A single pass through a large 2D array.
2. Line-by-line by 1D array.
3. Several passes through a smaller 2D array.

Ignore the third option as it turns out to be the worst of both.

Option 1 takes around 10 seconds to load the array and load the listview. However, it requires that I increas the available memory to at least 32MB. (+listview memory)

Option 2 takes around 90 seconds to load the listview, but it requires only a few bytes of memory. (+ listview memory)

The amount of memory is important as the number of lines in the listview is variable and could potentially be many times this. However, the time taken to list them is also important as listing just 10,000 should not take more than a few short seconds.

I've never seriously used the Profiler before as I never really had need for it or understood it. This is the listing for the selected code: (lvitem%!0 = 13 is set prior to loop)

Code:
        17:     0.03      FOR col%=0 TO Headers% - 1
       350:     0.68      lvitem%!4=line%
       203:     0.39      lvitem%!8=col%
       148:     0.29      lvitem%!20=!^detail$(col%)
       126:     0.24      lvitem%!24=LEN(detail$(col%))
        79:     0.15      lvitem%!32=line%
        49:     0.09      IF col% THEN
      9781:    18.94      SYS "SendMessage", hlist%, &102E, line%, lvitem% : REM LVM_SETITEMTEXT
        23:     0.04      ELSE
      9486:    18.37      SYS "SendMessage", hlist%, &1007, line%, lvitem% : REM LVM_INSERTITEM
         4:     0.01      ENDIF
        90:     0.17      NEXT 


Hope you can glean some helpful info from this. It seems to me, having examined it now, that the majority of time is spent sending the items to the listview. Do you think there is a way of increasing this? (I ask with the intension of testing this myself, but your opinion would be useful.)

Matt

Edit:
Tried this, but got 'Address out of range' for lvitem% when loading assembler:

Code:
      REM ASSEMBLER
      LOCAL P%, L%, code%, opt%, lvset, lvinsert
      DIM code% LOCAL 100, L% -1
      FOR opt% = 9 TO 11 STEP 2
        P% = code%
        [OPT opt%
        .lvset
        push lvitem%
        push line%
        push &102E
        push hlist%
        call "SendMessage"
        ret
        .lvinsert
        push lvitem%
        push line%
        push &1007
        push hlist%
        call "SendMessage"
        ret
        ]
      NEXT
      REM end ASSEMBER 
« Last Edit: May 31st, 2013, 5:31pm by Matt » User IP Logged

Michael Hutton
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 248
xx 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
User IP Logged

Matt
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 210
xx 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
User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx 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.
User IP Logged

Matt
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 210
xx 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
User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx 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.
User IP Logged

Michael Hutton
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 248
xx 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
User IP Logged

Matt
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 210
xx 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
User IP Logged

Matt
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 210
xx 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
User IP Logged

Michael Hutton
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 248
xx 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
User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx 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.
User IP Logged

Matt
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 210
xx 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
User IP Logged

Michael Hutton
Developer

member is offline

Avatar




PM

Gender: Male
Posts: 248
xx 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
 

« Last Edit: Jun 2nd, 2013, 1:57pm by Michael Hutton » User IP Logged

Pages: 1 2  Notify Send Topic Print
« Previous Topic | Next Topic »

| |

This forum powered for FREE by Conforums ©
Terms of Service | Privacy Policy | Conforums Support | Parental Controls