BBC BASIC
« Parallel Assembly »

Welcome Guest. Please Login or Register.
Sep 24th, 2017, 01:27am


Cross-platform BBC BASIC (Win32, Linux x86, Android, Mac OS-X, Raspberry Pi)

« Previous Topic | Next Topic »
Pages: 1 2  Notify Send Topic Print
 hotthread  Author  Topic: Parallel Assembly  (Read 425 times)
Ric
New Member
Image


member is offline

Avatar




PM


Posts: 18
xx Parallel Assembly
« Thread started on: Apr 16th, 2017, 7:05pm »

Probably one for Richard, but does anyone know if it is possible to get 2 assembly routines to run truly in parallel? IE on two cores, with maybe a shared memory location to trigger the routines. Say:


Routine 1
Do something
On result set !data=1
Repeat routine 1


Routine 2
Check !data
If 0 repeat routine 2
If 1 do something
Set !data=0
Repeat routine 2

If this is possible could someone be kind enough to supply some sample code.

Regards Ric
User IP Logged

You can't succeed without failing a few times first, CHIN UP.
Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 587
xx Re: Parallel Assembly
« Reply #1 on: Apr 16th, 2017, 9:19pm »

on Apr 16th, 2017, 7:05pm, Ric wrote:
If this is possible could someone be kind enough to supply some sample code.

It's entirely possible, indeed it's common (several of the BB4W libraries do it) and it's the standard way of making the most of a multi-core machine.

Achieving it is simply a case of choosing the right method to run the assembled code. If you run it using CALL or USR then it will share the same thread as the interpreter, but if you run it using SYS "CreateThread" (in BB4W) or SYS "SDL_CreateThread" (in BBCSDL) it will run in an independent thread.

As for sample code, you can find that in any of the libraries which use the technique, such as WINLIB2.BBC or WINLIB4.BBC.

Note that, ordinarily, you don't have control over whether the multiple threads run on separate cores or time-sliced on the same core, but assuming the machine isn't too busy the Windows kernel should allocate resources 'sensibly'. Forcing certain threads onto particular cores is possible but a complication that will rarely be justified.

Richard.
« Last Edit: Apr 16th, 2017, 9:31pm by Richard Russell » User IP Logged

Ric
New Member
Image


member is offline

Avatar




PM


Posts: 18
xx Re: Parallel Assembly
« Reply #2 on: Apr 16th, 2017, 10:05pm »

Thanks, I will look the libraries up for the source code.

Ric
User IP Logged

You can't succeed without failing a few times first, CHIN UP.
Ric
New Member
Image


member is offline

Avatar




PM


Posts: 18
xx Re: Parallel Assembly
« Reply #3 on: Apr 17th, 2017, 10:55am »

Please excuse my ignorance. I do not understand the code in either library. I don't know how to load a library and consequently can not run either, do I need all the code or just some of it?

Regards Ric
User IP Logged

You can't succeed without failing a few times first, CHIN UP.
Ric
New Member
Image


member is offline

Avatar




PM


Posts: 18
xx Re: Parallel Assembly
« Reply #4 on: Apr 17th, 2017, 3:33pm »

Afternoon Richard,

I may have mis-lead with the initial question. I would like two or more sections of code to run independently (each section of code is about 2000 instructions, (which is not what I understand a thread to be.) If this is still classed as a thread then I will continue.

Each thread will permanently run in the background until the BASIC program is terminated. Is this possible?

The not being able to understand winlib2 or winlib4 still stands, can you make it simpler or do I need the whole section of code to create a thread?

What I would like to do is

SYS "CreateThread" assembly label1
SYS "CreateThread" assembly label2
SYS "CreateThread" assembly label3

etc...

From my BB4W program, leave the assembly running in the background with a few memory location changes to operate the assembly routines and then for them to terminate only when the BASIC program is terminated.

Regards Ric

User IP Logged

You can't succeed without failing a few times first, CHIN UP.
Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 587
xx Re: Parallel Assembly
« Reply #5 on: Apr 17th, 2017, 7:45pm »

on Apr 17th, 2017, 3:33pm, Ric wrote:
I would like two or more sections of code to run independently (each section of code is about 2000 instructions, (which is not what I understand a thread to be.)

You didn't use the word "threads" in your question, but it's exactly what you seemed to be describing. If not, I don't understand what it is you are trying to achieve. You surely don't want to run your routines as separate processes, because they occupy independent address spaces and your 'shared variables' technique for communication couldn't work.

Why are you so convinced that threads won't do what you want? What do you understand them to be?

Quote:
The not being able to understand winlib2 or winlib4 still stands, can you make it simpler or do I need the whole section of code to create a thread?

I explained that you need to use SYS "CreateThread" in BB4W or SYS "SDL_CreateThread" in BBCSDL, please see my original reply; it could hardly be any simpler! The only reason that I pointed you to the libraries is because you asked for "sample code".

Quote:
What I would like to do is
SYS "CreateThread" assembly label1
SYS "CreateThread" assembly label2
SYS "CreateThread" assembly label3

You've just said that threads will not achieve what you want, but now you say you would like to use threads. That is surely contradictory?

Richard.
« Last Edit: Apr 17th, 2017, 9:08pm by Richard Russell » User IP Logged

Ric
New Member
Image


member is offline

Avatar




PM


Posts: 18
xx Re: Parallel Assembly
« Reply #6 on: Apr 18th, 2017, 07:49am »

Unlike you I am not a programming guru, I know what I want to achieve but don't necessarily know how to go about it. I will ask in a different way.

I would like to have two routines doing calculations running in the background and another that is capable of asking them for answers by passing and receiving parameters. All three programs/routines would run at the same time. Is this possible?

I do not know whether threads are needed, you suggested them. Simple would be a call with 1 or no parameters, create thread appears to have 8 of which I know not any of them are for or how to calculate.

Can what I am asking be done?

Ric
User IP Logged

You can't succeed without failing a few times first, CHIN UP.
Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 587
xx Re: Parallel Assembly
« Reply #7 on: Apr 18th, 2017, 08:40am »

on Apr 18th, 2017, 07:49am, Ric wrote:
I would like to have two routines doing calculations running in the background and another that is capable of asking them for answers by passing and receiving parameters. All three programs/routines would run at the same time. Is this possible?

This sounds very similar to your original question, except that you don't mention assembly language. It makes a big difference whether you want to do the "background" calculations in BASIC or in assembly language!

In the case of BASIC code the only practical way of performing your background tasks would be by running multiple copies of BBC BASIC. This will work, but because they run in different processes arranging the necessary communication and synchronisation between the tasks, so that they cooperate to achieve the wanted end result, may not be trivial.

If you are happy to perform the "background" calculations in assembler (i.e. machine) code then, as I said, threads will achieve that. However, as I tried to explain before, there is a subtle difference between running "at the same time" (which is your phrase) and running 'concurrently'.

Because of the (typically) many things that are happening on a PC that you are not directly aware of - just look in Task Manager to get an idea - you can never guarantee that there will be sufficient spare CPU cores to run your multiple tasks literally simultaneously, so you should not make that a requirement.

Rather, by running the tasks as different threads it is then up to the Windows kernel to schedule them on different cores if it can but to use time-sharing on fewer cores if it can't. Is it this factor that is causing you to doubt whether threads are suitable? I can assure you that it is perfectly normal to allow the OS this flexibility, rather than to attempt to force certain pieces of code to run on certain cores.

So if I assume that using assembler code is acceptable, and that you can relax your requirement that the tasks run literally "at the same time", then my opinion is not changed that threads are what you want. If you are already familiar with running assembler code using CALL or USR then, as I said, it is a simple change to using SYS "CreateThread" instead.

For the precise syntax of the CreateThread API you can either refer to its formal description at MSDN or simply copy-and-paste the relevant statement from either WINLIB2 or WINLIB4 (or look at both to see, and hopefully understand, how they relate). For example the statement in WINLIB2 is:

Code:
      SYS "CreateThread", 0, 1024, start%, 0, 0, ^I% TO H% 

I cannot literally list here the code you will need (even if that was desirable) because only you know things like how, and under what circumstances, the thread(s) will be terminated, how information will be passed into and out of the threads, how the threads will be synchronised and coordinated etc.

I suggest that you try it; you have all the information you need. Write the multiple tasks as assembler code, and test them independently using CALL (if that is practical). Once you are confident the code is working as you intend, change the CALL statements to SYS "CreateThread" statements (copied from one of the libraries if you must) and then see if everything it working as it should.

I have been careful to write this reply using straightforward English, using short sentences and short paragraphs, and using no technical jargon other than what is unavoidable given the subject matter.

Richard.
« Last Edit: Apr 18th, 2017, 08:59am by Richard Russell » User IP Logged

Ric
New Member
Image


member is offline

Avatar




PM


Posts: 18
xx Re: Parallel Assembly
« Reply #8 on: Apr 18th, 2017, 09:42am »

Thanks Richard,

It is questions like "what are ^I% and H%" and what do they need to be set to.
I assume start% is the start address of the assembly to be created as a thread?
Can I simply exchange start% for the address label?

They may be simple questions, but without answers I am flummoxed.

Regards Ric
User IP Logged

You can't succeed without failing a few times first, CHIN UP.
Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 587
xx Re: Parallel Assembly
« Reply #9 on: Apr 18th, 2017, 1:21pm »

on Apr 18th, 2017, 09:42am, Ric wrote:
It is questions like "what are ^I% and H%" and what do they need to be set to.

It's all explained in great detail at the MSDN page to which I linked (or in the case of BBCSDL at the SDL Wiki). You cannot expect to call Windows API functions without referring to their descriptions at MSDN. It would be wasteful duplication (and probably a violation of Copyright) for me to reproduce here what is written there, and valuable links to other MSDN references might be lost.

Quote:
They may be simple questions, but without answers I am flummoxed.

Every programming language that provides support for calling Windows API functions (and functions in other DLLs), whether it be by BBC BASIC's SYS statement, or Liberty BASIC's CALLDLL statement, or Visual BASIC's __stdcall declaration, requires the programmer to consult MSDN (etc.) to discover how the function is called, what its parameters are and what value (if any) it returns.

Richard.
User IP Logged

Ric
New Member
Image


member is offline

Avatar




PM


Posts: 18
xx Re: Parallel Assembly
« Reply #10 on: Apr 19th, 2017, 4:18pm »

I have now managed to create threads successfully, using help from MSDN(etc...) and a post by Michael Hutton. So many thanks, now I can see clearly, you were right, it is simple😊 There is just one thing I can not figure, why is the last parameter X TO y and not just an address/variable?

Regards Ric
User IP Logged

You can't succeed without failing a few times first, CHIN UP.
Ric
New Member
Image


member is offline

Avatar




PM


Posts: 18
xx Re: Parallel Assembly
« Reply #11 on: Apr 28th, 2017, 8:00pm »

Richard

It has taken a while but I now understand that it is not x to y after the last comma, but the first six parameters to thread handle. I have created both BASIC and ASM versions of "CreateThread" and in BASIC my laptop will allow 5 threads, but appears to only run two at a time (is this normal?), but in ASM when I try to create more than one thread the program crashes, is this because I can only create two threads at the same time and the current ASM code counts as one of them? Or am I missing something?

The code to create the codes in ASM is
Code:
        push              0
        push              0
        push              0
        push              start
        push              1024
        push              0
        CALL              "CreateThread"
        mov               [thread1],             eax

 


Regards Ric
User IP Logged

You can't succeed without failing a few times first, CHIN UP.
Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 587
xx Re: Parallel Assembly
« Reply #12 on: Apr 28th, 2017, 9:21pm »

on Apr 28th, 2017, 8:00pm, Ric wrote:
when I try to create more than one thread the program crashes, is this because I can only create two threads at the same time and the current ASM code counts as one of them?

You ought to be able to run hundreds of threads (at least!). To get a feel for the number of threads typically running on your PC, start Task Manager, select the 'Details' tab and then right-click on any of the column headings. One of the options you will see is 'Select Columns' - click on that and then tick the 'Threads' checkbox. Now you will see how many threads each process is running - the total is likely to be several hundred!

So if you are finding that you cannot start more than two threads there must be another reason. You may be able to discover what that is by using the code listed in the BB4W Help manual under 'Accessing the Windows API... Discovering an unknown error' (or you can read it online here). Copy that code into your program and use it to discover the Windows error when your thread creation fails.

Quote:
The code to create the codes in ASM is

Creating a thread using assembler code is unusual and probably makes it rather more difficult to debug. Do you need to? Couldn't you create all the threads you need initially, using BASIC code? There's a considerable overhead in creating a thread so it's more efficient to create it just once, at the start, rather than to repetitively terminate the thread and then create another one.

Richard.
User IP Logged

svein
New Member
Image


member is offline

Avatar




PM


Posts: 10
xx Re: Parallel Assembly
« Reply #13 on: Jun 22nd, 2017, 6:12pm »

Ric:

This might get you started, don't know who wrote it.
Disregard the middle bit (system info).

Code:
      REM!WC
      MAXIMUM_PROCESSORS = 32
      CREATE_SUSPENDED = &4
      INFINITE = &FFFFFFFF
      _TRUE = 1


      A% = 1
      B% = 1

      :\
      \\ assemble two different (pointless) routines to increment A% and B%
      \
      DIM code 50, L%-1
      FOR pass=8 TO 10 STEP 2
        P% = code
        [
        OPT pass
  
        .ThreadProc1
        inc dword [^A%]
        cmp dword [^A%],0
        jne ThreadProc1
        ret
  
        .ThreadProc2
        inc dword [^B%]
        cmp dword [^B%],0
        jne ThreadProc2
        ret
  
        ]
      NEXT

      :\
      \\ Declare SYSTEM_INFO structure
      \
      DIM _SYSTEM_INFO{ wProcessorArchitecture%,      \ Only lower word if valid: high word is wReserved - was dwOemID
      \                 dwPageSize%,                  \
      \                 lpMinimumApplicationAddress%, \
      \                 lpMaximumApplicationAddress%, \
      \                 dwActiveProcessorMask%,       \
      \                 dwNumberOfProcessors%,        \
      \                 dwProcessorType%,             \
      \                 dwAllocationGranulatiry%,     \
      \                 wProcessorLevel{l&,h&},       \
      \                 wProcessorRevision{l&,h&}    }

      SYS "GetSystemInfo", _SYSTEM_INFO{}

      PRINT "Number of processors available: ";_SYSTEM_INFO.dwNumberOfProcessors%

      :\
      \\ Create the threads and store their handles in an array
      \
      DIM hThread%(1)

      :\
      \\ ON ERROR and ON CLOSE to cleanup thread handles
      \
      ON ERROR PROCCleanup:REPORT:END
      ON CLOSE PROCCleanup:QUIT

      :\
      \\ Create the threads in a suspended state
      \
      SYS "CreateThread", 0, 1024, ThreadProc1, 0, CREATE_SUSPENDED, 0 TO hThread%(0)
      IF hThread%(0) = 0 THEN ERROR,"Failed to create Thread 1."
      SYS "CreateThread", 0, 1024, ThreadProc2, 0, CREATE_SUSPENDED, 0 TO hThread%(1)
      IF hThread%(1) = 0 THEN ERROR,"Failed to create Thread 2."

      :\
      \\ Get the current ideal processor for each thread
      \
      SYS "SetThreadIdealProcessor", hThread%(0), MAXIMUM_PROCESSORS TO current0%
      PRINT "Thread 1 is currently on : ";current0%
      SYS "SetThreadIdealProcessor", hThread%(1), MAXIMUM_PROCESSORS TO current1%
      PRINT "Thread 2 is currently on : ";current1%

      IF current0% = current1% AND _SYSTEM_INFO.dwNumberOfProcessors%>1 THEN
        SYS "SetThreadIdealProcessor", hThread%(1), 1 TO R%
        IF R%=-1 THEN PRINT"Couldn't change the processor for the 2nd thread."
      ENDIF


      :\
      \\ Wait a bit, check out Task Manager maybe...
      \
      PRINT "Waiting....."
      WAIT 500
      PRINT "Starting threads."
      PRINT A%,B%

      :\
      \\ |||Fry||| those processors
      \
      SYS "ResumeThread", hThread%(0)
      SYS "ResumeThread", hThread%(1)

      :\
      \\ Wait until both threads have stopped and then exit
      \
      SYS "WaitForMultipleObjects", 2, ^hThread%(0), _TRUE, INFINITE TO R%

      PRINT A%,B%
      PROCCleanup
      END

      :\
      \\ Close the thread objects
      \
      DEFPROCCleanup
      FOR I%=0 TO 1
        IF hThread%(I%) THEN SYS "CloseHandle", hThread%(I%) : hThread%(I%) = 0
      NEXT
      ENDPROC

 


Svein
User IP Logged

Richard Russell
Administrator
ImageImageImageImageImage


member is offline

Avatar




Homepage PM


Posts: 587
xx Re: Parallel Assembly
« Reply #14 on: Jun 22nd, 2017, 7:51pm »

on Jun 22nd, 2017, 6:12pm, svein wrote:
This might get you started, don't know who wrote it.

It's important to note this comment:

Code:
      \\ |||Fry||| those processors 

... and it certainly does! I would be very cautious about running this program unless you are confident about the efficiency of your CPU's cooling system!

Another thing to note is that, as it stands, the program cannot be terminated other than by using Task Manager (which will kill the BB4W IDE at the same time); the threads would exit eventually but only after 2^32 loops!

I wonder if the original author thought that closing a thread's handle terminates the thread (there's an ON CLOSE handler that closes both thread handles) but it doesn't. In fact it's perfectly OK to close a thread's handle immediately after it has been started; it won't affect anything unless the handle is needed later.

I would prefer to adapt the program so that the threads are forced to terminate on clicking Close, which can be achieved by changing the last few lines as follows:

Code:
      REM Wait until both threads have stopped and then exit
      REPEAT
        SYS "WaitForMultipleObjects", 2, ^hThread%(0), _TRUE, 100 TO R%
      UNTIL R% <> 258

      PRINT A%,B%
      PROCCleanup
      END

      REM Close the thread objects
      DEFPROCCleanup
      A% = TRUE : B% = TRUE
      FOR I%=0 TO 1
        IF hThread%(I%) THEN SYS "CloseHandle", hThread%(I%) : hThread%(I%) = 0
      NEXT
      ENDPROC 

My final suggestion would be to give careful thought to whether 'SetThreadIdealProcessor' or 'SetThreadAffinityMask' is most appropriate for your program.

Richard.
User IP Logged

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

Donate $6.99 for 50,000 Ad-Free Pageviews!


This forum powered for FREE by Conforums ©
Sign up for your own Free Message Board today!
Terms of Service | Privacy Policy | Conforums Support | Parental Controls