Information exchange between different cogs trough variables (different threads
chbrandl
Posts: 13
Hi,
I wanted·to calculate different threads of a whole problem, but how does a variable exchange works. I test it with a small programm but the cogs doesn´t exchange the information.
The programm should simply read a variable from a the terminalprogram, calculate three different results on three cogs and display the whole result on the terminal. How does it work correct. I alter an example program from parallax.
CON
··
· _clkmode = xtal1 + pll16x
· _xinfreq = 5_000_000
·
VAR long x
··· long in
··· long in1
··· long in2
··· long stack1[noparse][[/noparse]10]
··· long stack2[noparse][[/noparse]10]
··· long stack3[noparse][[/noparse]10]
OBJ
··
· Debug: "FullDuplexSerialPlus"
··
··
PUB TwoWayCom | value
· ''Test HyperTerminal number entry and display.
· Debug.start(31, 30, 0, 57600)
· repeat
···· Debug.Str(String("Enter a decimal value: "))
···· value := Debug.getDec
···· Debug.Str(String(10, 10, 13, "You Entered", 10, 13, "
"))
···· debug.dec(value)
···· Debug.Str(String(10, 13, "Decimal: ",10,13))
···· cognew (multi(value+1,IN),@stack1)
···· cognew (multi(value+2,IN1),@stack1)
···· cognew (multi(value+3,IN2),@stack2)
···· debug.dec(IN)
···· debug.dec(in1)
···· debug.dec(in2)
···· value:=IN+IN1+IN2
···· Debug.Dec(value)
···· debug.str(string(10,13," ",10,13))
···· repeat 2
······· Debug.Str(String(10, 13))
············
PUB MULTI(A,B)
···· B:=A*5
Thanks
Christopher···
·
I wanted·to calculate different threads of a whole problem, but how does a variable exchange works. I test it with a small programm but the cogs doesn´t exchange the information.
The programm should simply read a variable from a the terminalprogram, calculate three different results on three cogs and display the whole result on the terminal. How does it work correct. I alter an example program from parallax.
CON
··
· _clkmode = xtal1 + pll16x
· _xinfreq = 5_000_000
·
VAR long x
··· long in
··· long in1
··· long in2
··· long stack1[noparse][[/noparse]10]
··· long stack2[noparse][[/noparse]10]
··· long stack3[noparse][[/noparse]10]
OBJ
··
· Debug: "FullDuplexSerialPlus"
··
··
PUB TwoWayCom | value
· ''Test HyperTerminal number entry and display.
· Debug.start(31, 30, 0, 57600)
· repeat
···· Debug.Str(String("Enter a decimal value: "))
···· value := Debug.getDec
···· Debug.Str(String(10, 10, 13, "You Entered", 10, 13, "
"))
···· debug.dec(value)
···· Debug.Str(String(10, 13, "Decimal: ",10,13))
···· cognew (multi(value+1,IN),@stack1)
···· cognew (multi(value+2,IN1),@stack1)
···· cognew (multi(value+3,IN2),@stack2)
···· debug.dec(IN)
···· debug.dec(in1)
···· debug.dec(in2)
···· value:=IN+IN1+IN2
···· Debug.Dec(value)
···· debug.str(string(10,13," ",10,13))
···· repeat 2
······· Debug.Str(String(10, 13))
············
PUB MULTI(A,B)
···· B:=A*5
Thanks
Christopher···
·
Comments
I think your problem is that you're passing the values of the b variables into the function, when you should be passing the address to the variable itself.
Post Edited (Bergamot) : 8/16/2007 1:51:51 PM GMT
Problem 2 is a typo (stack1 is use twice)
Problem 3 is that is makes no sense to START a COG for an operationen taking less that 10 SPIN operations; you should learn how to use a COG as a "server", waiting for requests.
Do do not run into problem 4 as long as you perform "debug" operations after loading the COGS, you will however when you remove them and try to add the three results that have presumably not yet been computed...
Post Edited (deSilva) : 8/16/2007 3:19:06 PM GMT
The use of the stack1 twice is·an error,·it should be stack1, stack2, stack3, like declared above.
I test all variantes, but the variables are always 0, and the result is 0.
One is right a new cog is only·used if there are more than 10 operations.
Please an example in spin.
Best regards
Christopher
Post Edited (chbrandl) : 8/16/2007 6:38:11 PM GMT
Post Edited (Bergamot) : 8/16/2007 6:56:35 PM GMT
But in general your program should work when doing the "call by references" correctly as explained by Bergamot.
Example... Bergamot also explained that: You can access any "global" variable you like! There are no such restrictions in SPIN as you keep reading from the Assembly gurus all the time
Edit: This forum software swallowed his "[noparse][[/noparse] ", it should read:
Post Edited (deSilva) : 8/16/2007 6:54:12 PM GMT
This can not do what you want. B is a local variable that is allocated in the stack that this cog is using. Spin passes parameters "by value". It copies the value supplied. You want to pass that parameter "by reference" which is done by passing an address "by value". In other words, you have:
When you start this cog, you have to pass the address of the variable as the 2nd parameter like this:
Best whishes
Christopher
CON
· _clkmode = xtal1 + pll16x
· _xinfreq = 5_000_000
·
VAR long x
··· long in
··· long in1
··· long in2
··· long stack1[noparse][[/noparse]20]
··· long stack2[noparse][[/noparse]20]
··· long stack3[noparse][[/noparse]10]
··· byte cog
··· byte cog1
··· long out
OBJ
··
· Debug: "FullDuplexSerialPlus"
··
··
PUB TwoWayCom | value
· ''Test HyperTerminal number entry and display.
· Debug.start(31, 30, 0, 57600)
· repeat
···· Debug.Str(String("Enter a decimal value: "))
···· value := Debug.getDec
···· Debug.Str(String(10, 10, 13, "You Entered", 10, 13, "
"))
···· debug.dec(value)
···· Debug.Str(String(10, 13, "Decimal: ",10,13))
···· cog:=cognew(MULTI(Value,@IN),@stack1)
···· 'cog1:=cognew(MULTI(Value+1,@IN1),@stack2)
···· out:=IN+IN1+IN2
···· debug.str(String(10,13,"IN",10,13))
···· debug.dec(IN)
···· debug.str(String(10,13,"IN1",10,13))
···· debug.dec(IN1)
···· debug.str(String(10,13,"OUT",10,13))
···· debug.dec(out)
···· debug.str(string(10,13,"fertig",10,13))
···· repeat 2
······ Debug.Str(String(10, 13))
···· IN:=0
···· IN1:=0
···· IN2:=0
···· OUT:=0·
···· cogstop(cog)
···· 'cogstop(cog1)·
············
PUB MULTI (A,B)
···· long [noparse][[/noparse]B]:=0
···· long [noparse][[/noparse]X]:=1
···· repeat A
····· long [noparse][[/noparse]B]:=long [noparse][[/noparse]B]+long [noparse][[/noparse]X]
····· long [noparse][[/noparse]X]:=long [noparse][[/noparse]X]+1
···· return B
2. "Problem 4" that daSilva is obliquely referring to is the fact that it takes some time to start a cog. After you do
cog:=cognew(MULTI(Value,@IN),@stack1)
you'll need to add a little delay before looking at IN. The call to debug.str might add enough delay that IN is valid, but
out:=IN+IN1+IN2
immediately after the cognew will read IN before the cog has had a chance to update it. Either add a waitcnt before computing out or move the computation down, maybe to just in front of
debug.str(String(10,13,"OUT",10,13))
3. Where can I find FullDuplexSerialPlus?
Michael
There are still some misunderstandings, Chbrandl, wrt to basic SPIN features:
(5) There is no return value from a routine started through COGNEW.
(6) long[noparse][[/noparse] address ] "dereferences" address, i.e. address has to be a pointer (as with @B); you most likely wanted to use X directly (and NOT long [noparse][[/noparse] X ] )
(7) it is extremely tricky to modify the same variable from different processes (consult information about locks in this forum)
(8) It is not only good practice to use "something OP= other" rather than "something := something OP other", but also considerably faster.
Post Edited (deSilva) : 8/17/2007 1:48:14 PM GMT
Now that you've added X which is a global variable shared by all the cogs, you have a standard multiprocessor programming problem ... All of the cogs can attempt to change X at the same time. When you do "X := X + 1", you're really getting a copy of X, adding 1 to it, then copying the result back to X. Since several cogs can be running at the same time, another one can be attempting the same thing at the same time. Which X value are you working with? The one before the other cog increments it or the one after the other cog increments it? When you store what you think should be the value of X back into X, are you destroying the value that some other cog just stored there?
Have a look at the discussion in the Propeller Manual on the LOCKxxx statements. These are the standard way to share resources among multiple processors. You are fiddling with the subject of several lectures in a course on multiprocessing.
No X should be·a local·counter variable. B is the result which should be transfered to the first (I think controlling calling cog 0) cog.
I hope I see it right, that the variables X, B and A will be used only by the cog and they are on the local·RAM and not on the main RAM. I s it right that the first cog starts with the command cognew a new process on an other cog and uses local variables in it 512 byte local ram ?
And this is only an example to test my ideas not a really project.
I wanted to start 2 or more cogs with a similar mathematical problem, which should be solved parallel and all part solves should be·processed finally on the calling cog.
start Calling (0)cog
·start mathproblem on first cog
·start mathproblem on second cog
·start mathproblem on thrid cog
process result from first cog with result from second cog and result from third cog.
Print it on the display.
Best regards
Christopher
PS: The module FullDuplexSerialPlus is found on the object exchange or on the education board on the examples.
·
No, No, No! your concepts are still twisted. There is no such thing as "local RAM" when using SPIN!
No!
A COGNEW or COGINIT does one of two things:
1) It loads an assembly (machine instruction) program into a cog's local memory either from a user provided 2K byte area (512 long word) in main memory or the Spin interpreter from ROM.
2) The assembly program is started at location zero after loading is complete, roughly 100us later (after copying 512 long words from main memory to cog memory). If the program is the Spin interpreter, it will begin interpreting the method call that was set up in the COGNEW / COGINIT statement using the stack and the parameters to the method call that were set up on the stack by the COGNEW / COGINIT statement.
3) If the program started in the cog is a Spin method, it has access to all of the variables (VAR) declared in its object and all of the data (DAT) declared in its object. These are global to the object and this access has nothing to do with the fact that the program is using more than one cog. It also has access to its local variables which are private to the method and unique to the cog executing the method (since there should be a unique stack for each cog running Spin).
The start method will be given the parameters that are different from one instance to the next and it will store them locally for further reference. The main program can call methods in the object to: 1) check on the progress of the computation; 2) retrieve the results when the computation is done; 3) supply information to the computation that may change during the computation; 4) retrieve intermediate results.
Each instance of the object will have its own set of variables (VAR), but there will be only one copy of the code (PUB/PRI) and only one copy of the data areas (DAT). If your computation requires shared variables, these can be put in the DAT areas and you can use LOCKxxx (see the description in the manual) to regulate access to them.
Have a look at any I/O driver that uses a separate cog for the I/O. It will have this sort of structure. There will be a start and stop method and several interface methods that are called from whatever program is using this object. These take care of interfacing between the main program and the program running in the dedicated cog. You'll find I/O drivers like this in the Propeller Tool's library and in the Propeller Object Exchange website.
I adapted the program, now it runs. Is there a methode or a command to see if a cog is ready with its calculations ? At the moment I use a waitcnt command.
I had the same idea to write the methode as an object, but i don´t like objects and object oriented programming languages. In my opinion they are very hard to read.
Thanks a lot
Best regards from Austria
Christopher
·
(2) Don't be afraid: SPIN "objects" are just a trade name
(3) Your (sub-)program can simply set a "global" variable, just before it quits!
Post Edited (deSilva) : 8/17/2007 6:12:54 PM GMT