Multi Core example

Non-technical related questions should go here.
Post Reply
User avatar
Obtuse
Member++
Posts: 29
Joined: Mon Jul 09, 2012 11:54 pm

Multi Core example

Post by Obtuse »

I am trying to understand running something on a separate core of a tile,,, and getting no place.
For the code below, is it even possible to do this? This is only a learning exercise and really don't know what to do.

[combinable], while{ select{, I have no clue as to what goes where.

Code: Select all

/*
 * 3core.xc
 *
 *  Created on: Jun 9, 2017
 *      Author: len
 *
 *      XS1-L16A-128-QF124-C10 Device
 */

#include <xs1.h>
#include <platform.h>
#define DELAY 20000
#define TRUE 1

on tile [1] : port out port1E = XS1_PORT_1E;

// on tile 0 core0.
void worker (chanend ch)
{
  timer tmr;
  unsigned t;
  unsigned workdata = 0;

  while (TRUE)
      {
    tmr :> t;
    tmr when timerafter (t+ DELAY*3) :> void;
    ch <: workdata;
      }
}

//on tile[0}.core[2]
void mimic (chanend dh)
{
  timer tm;
  unsigned t1;
  unsigned count = 1;

  while (TRUE)
      {
    tm :> t1;
    tm when timerafter (t1+ DELAY+1000) :> void;
    dh <: count;
      }
}

// on tile 1 core0
void boss (chanend ch, chanend dh )
{
    unsigned bossdata;
    timer time;
    unsigned d;

    while (TRUE)
    {
       ch :> bossdata;
       port1E <: bossdata;
       time :> d;
       time when timerafter (d+ (DELAY)) :> void;

       dh :> bossdata;
       port1E <: bossdata;
       time :> d;
       time when timerafter (d+ (DELAY*2)) :> void;

    }
}


int main (void)
{
        chan ch; chan dh;
  par {
            on tile [0] : worker ( ch );
            on tile [0] : mimic ( dh );
            //on tile [0].core[2] : mimic ( dh );
            on tile [1] : boss ( ch, dh );
      }
  return 0;
}


Gothmag
XCore Addict
Posts: 129
Joined: Wed May 11, 2016 3:50 pm

Post by Gothmag »

https://www.xmos.com/support/tools/prog ... nent=17653
Check this PDF. It is the programming manual. It's a short but informative read like K&R C, should help you to understand what you want to do. You can also use it as a quick reference when you need.
User avatar
Obtuse
Member++
Posts: 29
Joined: Mon Jul 09, 2012 11:54 pm

Post by Obtuse »

I have been all through the manuals, many times.
The supplied code has been modified 100s of times. Like most people it is not easy to admit stupidity. However I'm just not putting two and two together. I am stupid, and Qbtuse.
User avatar
zhengyang0512
Member++
Posts: 27
Joined: Tue Aug 23, 2016 6:14 am

Post by zhengyang0512 »

Hi, it's not wise to use the channel across the tiles. Your main process should be

Code: Select all

int main (void)
{
        chan ch; chan dh;
  par {
            on tile [0] : worker ( ch );
            on tile [0] : mimic ( dh );
            //on tile [0].core[2] : mimic ( dh );
            on tile [0] : boss ( ch, dh );
      }
  return 0;
}
I think this should be work.
User avatar
Obtuse
Member++
Posts: 29
Joined: Mon Jul 09, 2012 11:54 pm

Post by Obtuse »

@zhengyang0512

Confusion can be implemented by official statements as in the Programming Guide in the Communication/Channels section.

--------------------------------------------------------------------------------
Channels (both streaming and normal) are the lowest level
of abstraction to the communication hardware available in xC and can be used to
implement quite efficient inter-core communication but have no type-checking and
cannot be used between tasks on the same core.
--------------------------------------------------------------------------------

So unless the compiler assigns tasks to different cores automatically when using channels then the above guidance is confusing.

As for channels across tiles.
This is a simulator exercise and I ask what other inter-tile communication would do the job.?

I really would like to keep this as simple as possible.

Thank You,

P.S. In the real world external signals could be used. In the virtual world...?
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

User avatar
Obtuse
Member++
Posts: 29
Joined: Mon Jul 09, 2012 11:54 pm

Post by Obtuse »

@mon2

Thanks for the link. I will give it a go. :)
plex
Member++
Posts: 22
Joined: Fri Aug 12, 2016 6:13 pm

Post by plex »

Hi,
I can only guess what you are trying to achieve but here are some comments on your code:
The channels inputs and outputs are blocking. You will find in the documentation that they might have some buffering but initially you need to assume they do not, to build your code correctly.
This means that when you send something through a channel the code will block until it is received on the other end. The same goes for receive, it will wait until data arrives.
What this does is force the tasks to synchronize. So the "mimic" task that looks like it should send data every 21000 ticks will actually send data every ~ 60000 ticks because this is the rate at which the receiving task can accept the data.
If you want asynchronous communications then usually you have to used an intermediate task that will act as a repository and the other tasks will send and get data from it.
There is a way to make the receive on channel not blocking by using a "select" statement with a default case.
The programming guide and the examples you can access through the xtimecomposer are very helpful in understanding the xcore devices and language. I had a lot of difficulty as well when I started.
I think that the statement that channels should not be used between tasks on the same core in an error.
The documentation can be confusing at times and I find that details are sometimes missing but a big part of it is very useful.
Regarding your question about other communications interfaces there are streaming channels and at a higher level interfaces. Interfaces are channel communications disguised by the compiler as "functions". The compiler underneath does all the difficult work. When used between tasks on the same core the compiler might not even use actual channels.
User avatar
Obtuse
Member++
Posts: 29
Joined: Mon Jul 09, 2012 11:54 pm

Post by Obtuse »

@plex

Hello,
This was an exercise for me to use the [[combinable]] function in a simple program. It was simply a question that is now answered.

The code itself was stripped from a much larger program that depends on channel blocking for event timing. I simply copied the 'worker' section, renamed it 'mimic', and set about to answer that question. It is sloppy code, that really has no useful purpose other than to demonstrate running code on a separate core of a tile. I have found other programs that do this but not really suitable for running on a simulator for my own education.

I will spend some time cleaning up the mess I created with the code, comment it and post it for others with the same question.

It was just a question, 'How to use a separate core of a tile?' If I had not been reading the programming guide I would not have had the question in the first place. Ignorance is bliss. :-)

Thanks to all for your interest and advice.
User avatar
Obtuse
Member++
Posts: 29
Joined: Mon Jul 09, 2012 11:54 pm

Post by Obtuse »

The code below is derived from the first post in this thread.
It may be of use to some folks looking to play around with the [[combinable]] function on the xTIMEcomposer simulator.

It will run on various Xmos chips and probably some kits, Read the comments in the source file. Channel Blocking and using more than one core per tile where the simple goal of this exercise.

Code: Select all

/*
 * 3core.xc
 *
 *  Created on: Jun 12, 2017
 *      Author: len
 *
 *      Just an example for using [[combinable]], while{ select{case : }}
 *      XS1-L16A-128-QF124-C10 Device and probably others.
 *
 */

#include <xs1.h>
#include <platform.h>
#include <timer.h>
#define DELAY 2000 // Set to 20 million for flashing LEDs on hardware.
#define TRUE 1

on tile [1] : port out port1E = XS1_PORT_1E;

// on tile 0 core0.
void worker (chanend bosswork ) // Send LOWs to the boss.
{
  timer tmr;
  unsigned t;
  unsigned workdata = 0;

  while (TRUE)
      {
    workdata = 0;
    //bosswork <: workdata; // Send a 0 to boss and wait for it to go.
    tmr :> t; //Reset t.
    tmr when timerafter (t+ (DELAY*8)) :> void; // Increase HI time by increasing DELAY multiplier.
    bosswork <: workdata; // Send a 0 to boss and wait for it to go.
    workdata = 1; // Just a test.
      }
}

//on tile[0}.core[1] Send HIs to the boss.
[[combinable]]
void mimic ( chanend bossmimic )
{
  timer tmr2;
  unsigned t1;
  unsigned mimicdata = 1;

  while (1)
  {

      select{
          case tmr2 when timerafter (t1 + DELAY) :> void: // Short DELAY due to lazy programmer.
                 bossmimic <: mimicdata; // Send a 1 to boss.
                 mimicdata = 0; // Just a test.
                 tmr2 :> t1; //reset t1.
                 mimicdata = 1; // Test is over.
               break;
            }
  }
}


// on tile 1 core0
void boss (chanend bosswork, chanend bossmimic )
{
    unsigned bossdata;
    timer time;
    unsigned d;

    while (TRUE)
    {
       bosswork :> bossdata; // Channel blocked until LOW sent by worker.
       port1E <: bossdata; //  Wait for worker to send. Toggle port LOW. Hold LOW till after DELAY.
       time :> d; // Set variable d to present timer ticks
       time when timerafter (d+ (DELAY*2)) :> void; // Up LOW time by increasing multiplier.
       bossmimic :> bossdata; // Get the 1 sent by mimic.
       port1E <: bossdata; // Toggle port1E HI. Hold port1E HI until worker sends LOW.
    }
}


int main (void)
{
        chan bosswork; chan bossmimic;
  par {
            on tile [0] : worker ( bosswork );
            on tile [0].core[1] : mimic (bossmimic);
            on tile [1] : boss ( bosswork, bossmimic );
      }
  return 0;
}
Post Reply