SPE to SPE signaling

From Cellbe

(Difference between revisions)
(KgFL8vduSxcM)
 
(4 intermediate revisions not shown)
Line 1: Line 1:
-
This tutorial shows  how to send signals from one spe to another.
+
Denny,There IS a bug in the incrementing of the major vsoeirn.  I've fixed it in SVN, but haven't made a new public release with the fix (one more entry on my list of things to do "sometime"). Since the major vsoeirn only updates between migrations, the bug can only manifest itself if there is an issue with the first step of a given migration, but you're right, there is an issue there.  The minor vsoeirns (steps within a migration) are double protected: the increment happens second, and the whole thing is wrapped in a CFTRANSACTION. The reason the major vsoeirn increments first is for internal bookkeeping reasons. It's safe for it to increment even if the first migration step fails, because it'll be minor vsoeirn zero (which means the first step is still next in line).  The bug was in when the minor vsoeirn was reset to zero; it happened at the wrong time before.For the two-developer conflict scenario, there's nothing the tool can do about it. You have to resolve the conflicts when the second developer commits his/her changesMigration code does have some ordering ramifications, so resolving a conflict might not be as simple as otherwise (quite possibly requiring manual tweaks to the `schema_version` table), but it's really no different from any other conflict between multiple developers.
-
 
+
-
There are three entities in this tutorial:
+
-
*'''starter''': the PPE process who starts the spe threads
+
-
*'''sender''': the SPE thread who sends the signal
+
-
*'''receiver''' the SPE thread who receives the signal
+
-
 
+
-
==Version 3.0 Issues==
+
-
Unfortunately this tutorial does not work under standard settings (Cell SDK v3.0). The following Sourcecode will give you some hints how to signal from one SPE to another.
+
-
On PPE side:
+
-
<pre>
+
-
spe_sig_notify_1_area_t *sig_area1 = (spe_sig_notify_1_area_t*)spe_ps_area_get(context_,SPE_SIG_NOTIFY_1_AREA);
+
-
spe_sig_notify_2_area_t *sig_area2 = (spe_sig_notify_2_area_t*)spe_ps_area_get(context_,SPE_SIG_NOTIFY_2_AREA);
+
-
 
+
-
  addressSignalArea1_ = (uint64_t) (&(sig_area1->SPU_Sig_Notify_1));
+
-
  addressSignalArea2_ = (uint64_t) (&(sig_area2->SPU_Sig_Notify_2));
+
-
</pre>
+
-
On SPE sender side:
+
-
<pre>
+
-
void sendSignal(uint64_t address,uint32_t value)
+
-
{
+
-
uint32_t signal[4] __attribute__ ((aligned (128)));
+
-
+
-
if ( address == 0 ) {
+
-
return;
+
-
}
+
-
+
-
signal[3] = value;
+
-
+
-
mfc_sndsig(((char *) &signal[0]) + 12,address, TAG_SIGNAL, 0, 0);
+
-
mfc_write_tag_mask(TAG_SIGNAL);
+
-
mfc_read_tag_status_all();
+
-
}
+
-
</pre>
+
-
On SPE receiver side:
+
-
<pre>
+
-
spu_read_signal1()
+
-
</pre>
+
-
You're welcome to post your questions and suggestions on the discussion page.
+
-
--[[User:78.54.169.70|78.54.169.70]] 14:21, 11 January 2008 (EST)
+
-
 
+
-
==PPE side: starter==
+
-
The process '''starter''' does basically this:
+
-
#creates the spe threads
+
-
#sends '''sender''' the address of the signal notify area of '''receiver'''
+
-
#joins the threads.
+
-
It's important to note that the contexts are created using the <tt>'''SPE_MAP_PS'''</tt> flag, because we want the problem state area of the SPEs to be mapped in the effective address space (the signals are sent with dma commands).
+
-
<pre>
+
-
 
+
-
/*
+
-
  * =============================================================================
+
-
*      Filename:  ppusig.c
+
-
*    Description:  starter
+
-
*        Author:  Alessandro Piras (laynor@gmail.com)
+
-
* =============================================================================
+
-
*/
+
-
 
+
-
#define ZZ_CTX_CREATE -2
+
-
#define ZZ_PRG_LOAD -3
+
-
#define ZZ_CTX_RUN -4
+
-
#define ZZ_PTH_CREATE -5
+
-
#define ZZ_PTH_JOIN -6
+
-
 
+
-
#include <stdio.h>
+
-
#include <libspe2.h>
+
-
#include <pthread.h>
+
-
#include <unistd.h>
+
-
#include <stdlib.h>
+
-
//#include <commonlib.h>
+
-
 
+
-
extern spe_program_handle_t spurecv;
+
-
extern spe_program_handle_t spusend;
+
-
 
+
-
void *pth_rtn(void *arg)
+
-
{
+
-
unsigned int entry=SPE_DEFAULT_ENTRY;
+
-
int rc;
+
-
void *argp=NULL;
+
-
void *envp=NULL;
+
-
spe_context_ptr_t ctx;
+
-
 
+
-
ctx = *((spe_context_ptr_t *) arg);
+
-
 
+
-
rc = spe_context_run(ctx, &entry, 0, argp, envp, NULL);
+
-
if(rc < 0) {
+
-
perror("spe_context_run()");
+
-
exit(ZZ_CTX_RUN);
+
-
}
+
-
pthread_exit(NULL);
+
-
}
+
-
 
+
-
int main()
+
-
{
+
-
spe_context_ptr_t ctx[2];
+
-
pthread_t pth[2];
+
-
unsigned int flags = SPE_MAP_PS;
+
-
int i;
+
-
spe_sig_notify_1_area_t *sig_area;
+
-
unsigned int sig_area1;
+
-
 
+
-
//-----CTX creation
+
-
for(i=0; i<2; i++){
+
-
ctx[i] = spe_context_create(flags, 0);
+
-
if(ctx[i] == NULL){
+
-
perror("spe_context_create()");
+
-
exit(ZZ_CTX_CREATE);
+
-
}
+
-
}
+
-
 
+
-
//-----PRG load
+
-
if(spe_program_load(ctx[0],&spurecv)){
+
-
perror("spe_program_load()");
+
-
exit(ZZ_PRG_LOAD);
+
-
}
+
-
if(spe_program_load(ctx[1],&spusend)){
+
-
perror("spe_program_load()");
+
-
exit(ZZ_PRG_LOAD);
+
-
}
+
-
 
+
-
//-----PTH creation
+
-
for(i=0; i<2; i++)
+
-
if(pthread_create(&pth[i], NULL, pth_rtn, &ctx[i])){
+
-
perror("pthread_create()");
+
-
exit(ZZ_PTH_CREATE);
+
-
}
+
-
 
+
-
sig_area = spe_ps_area_get(ctx[0], SPE_SIG_NOTIFY_1_AREA);
+
-
sig_area1 = (unsigned int) (&(sig_area->SPU_Sig_Notify_1));
+
-
spe_in_mbox_write(ctx[1], &sig_area1, 1, 1);
+
-
+
-
//-----PTH join
+
-
for(i=0; i<2; i++)
+
-
if(pthread_join(pth[i], NULL)){
+
-
perror("pthread_join()");
+
-
exit(ZZ_PTH_JOIN);
+
-
}
+
-
 
+
-
//-----CTX destruction
+
-
for(i=0; i<2; i++)
+
-
spe_context_destroy(ctx[i]);
+
-
return 0;
+
-
}
+
-
</pre>
+
-
==SPE side: sender==
+
-
The important thing here is that the memory area which contain the signal must be aligned, but that's not all: '''the message should be placed 12 bytes after the base address of the aligned memory area'''. The address passed to mfc_sndsig is the address at which the message resides (base_address + 12bytes).
+
-
<pre>
+
-
/*
+
-
* =============================================================================
+
-
*      Filename:  spusend.c
+
-
  *    Description:  sends a signal to "spe1"
+
-
*        Author:  Alessandro Piras (laynor@gmail.com)
+
-
* =============================================================================
+
-
*/
+
-
 
+
-
#include <spu_intrinsics.h>
+
-
#include <spu_mfcio.h>
+
-
#include <stdio.h>
+
-
 
+
-
int main(unsigned long long spe_id __attribute__ ((unused)),
+
-
unsigned long long argp __attribute__ ((unused)),
+
-
unsigned long long envp __attribute__ ((unused)))
+
-
{
+
-
unsigned int ps_area_ptr;
+
-
 
+
-
//the memory area must be aligned
+
-
volatile unsigned int signal[4] __attribute__ ((aligned (128)));
+
-
 
+
-
//the message should be placed 3 bytes after
+
-
signal[3] = 201;
+
-
ps_area_ptr = spu_read_in_mbox();
+
-
printf("(spe) ps_area_ptr: %x\
+
-
", ps_area_ptr);
+
-
 
+
-
//NB: the address passed is base address + 12 bytes
+
-
mfc_sndsig(((char *) &signal[0]) + 12,
+
-
ps_area_ptr, 31, 0, 0);
+
-
+
-
mfc_write_tag_mask(1<<31);
+
-
mfc_read_tag_status_all();
+
-
return 0;
+
-
}
+
-
</pre>
+
-
 
+
-
==SPE side: receiver==
+
-
Not much to say here, it's pretty simple.
+
-
<pre>
+
-
 
+
-
/*
+
-
* =============================================================================
+
-
*      Filename:  spurecv.c
+
-
*    Description:  Waits for a signal and prints it
+
-
*        Author:  Alessandro Piras (laynor@gmail.com)
+
-
* =============================================================================
+
-
*/
+
-
 
+
-
#include <spu_intrinsics.h>
+
-
#include <spu_mfcio.h>
+
-
#include <stdio.h>
+
-
 
+
-
int main(unsigned long long spe_id __attribute__ ((unused)),
+
-
unsigned long long argp __attribute__ ((unused)),
+
-
unsigned long long envp __attribute__ ((unused)))
+
-
{
+
-
 
+
-
unsigned int value;
+
-
value = spu_read_signal1();
+
-
printf("(recvr) value: %u\
+
-
", value);
+
-
return 0;
+
-
}
+
-
</pre>
+
-
[[Category:Tutorial]]
+

Current revision as of 19:44, 20 November 2015

Denny,There IS a bug in the incrementing of the major vsoeirn. I've fixed it in SVN, but haven't made a new public release with the fix (one more entry on my list of things to do "sometime"). Since the major vsoeirn only updates between migrations, the bug can only manifest itself if there is an issue with the first step of a given migration, but you're right, there is an issue there. The minor vsoeirns (steps within a migration) are double protected: the increment happens second, and the whole thing is wrapped in a CFTRANSACTION. The reason the major vsoeirn increments first is for internal bookkeeping reasons. It's safe for it to increment even if the first migration step fails, because it'll be minor vsoeirn zero (which means the first step is still next in line). The bug was in when the minor vsoeirn was reset to zero; it happened at the wrong time before.For the two-developer conflict scenario, there's nothing the tool can do about it. You have to resolve the conflicts when the second developer commits his/her changes. Migration code does have some ordering ramifications, so resolving a conflict might not be as simple as otherwise (quite possibly requiring manual tweaks to the `schema_version` table), but it's really no different from any other conflict between multiple developers.

Personal tools