› Foros › PlayStation 3 › Scene
int main(int argc, char **argv)
{
int num_spes, i;
if ( argc < 2) {
fprintf(stderr, "Usage: %s NUM_SPEs\n", argv[0]); exit(1);
}
/* set number of SPEs */
num_spes = atoi(argv[1]);
/* figure out the number of availabe SPEs */
if ((spe_cpu_info_get(SPE_COUNT_USABLE_SPES, -1)) < num_spes) {
fprintf(stderr, "System doesn't have enough working SPEs.\n"); return -1;
}
/* marshall thread_info structures */
for(i=0; i < num_spes; i++)
{
/* create the SPE context */
if ((tinfo[i].ctx = spe_context_create(SPE_MAP_PS, NULL)) == NULL) {
perror("spe_context_create"); exit (1);
}
/* load the SPE program into the SPE context */
if (spe_program_load(tinfo[i].ctx, &cellbe_hola_spu) != 0) {
perror("spe_program_load\n"); exit (1);
}
/* set SPE thread ID */
tinfo[i].id = i;
}
/* run the SPE threads */
for(i=0; i < num_spes; i++)
{
/* spawn Linux threads to run SPE contexts */
if (pthread_create (&(tinfo[i].thread), NULL,
&thread_function, &tinfo[i])){
perror("pthread_create");
exit (1);
}
printf("PPE: thread for SPE %d created\n", i);
}
/* Computation is distributed among SPEs */
for(i=0;i<num_spes;i++)
{
/* wait for Linux threads */
if (pthread_join (tinfo[i].thread, NULL)) {
perror("Failed pthread_join");
exit (1);
}
/* destroy the SPE context */
if (spe_context_destroy(tinfo[i].ctx) != 0) {
perror("spe_context_destroy");
exit (1);
}
...
}
for(i=0;i<num_spes;i++)
{
...
/* check the SPE exit status */
if (tinfo[i].stop_info.stop_reason == SPE_EXIT) {
if (tinfo[i].stop_info.result.spe_exit_code != 0) {
fprintf(stderr, "SPE %d returned a non-zero exit status.\n", i); exit(1);
}
} else {
fprintf(stderr, "SPE %d abnormally terminated.\n", i); exit(1);
}
}
printf("*** Test completed successfully ***\n");
return 0;
}
/* function executed by each Linux thread */
void *thread_function(void *arg)
{
unsigned int entry = SPE_DEFAULT_ENTRY;
thread_info *tinfo = (thread_info *) arg;
if ((spe_context_run(tinfo->ctx, &entry, 0, (void *) tinfo->id, 0, &tinfo->stop_info))<0)
{
perror("spe_context_run");
exit (1);
}
pthread_exit(NULL);
}
int main(uint64_t speid, uint64_t id)
{
/* ¡Hola mundo! */
fprintf(stderr, "SPE %lld (%llx): ¡Hola mundo!\n", id, speid);
return 0;
}
• Acceder a directorio de ejemplo:
• [AcidXX@...] $ cd Acid/cellbe_mbox
• Compilar:
• [AcidXX@...] $ source ../ps3.env
• [AcidXX@...] $ make
• Ejecutar:
• [AcidXX@...] $ ppu/cellbe_mbox 1
• Editar código:
• [AcidXX@...] $ vim ppu/cellbe_mbox_ppu.c
• [AcidXX@...] $ vim spu/cellbe_mbox_spu.c
int main(int argc, char **argv)
{
...
/* marshall the control block and the thread_info structures */
for(i=0; i < num_spes; i++)
{
...
/* get memory-mapped address of SPEs' control area (to use mailboxes) */
tinfo[i].control_addr = (void *) spe_ps_area_get(tinfo[i].ctx, SPE_CONTROL_AREA);
cb.control_addr[i] = (EA) tinfo[i].control_addr;
...
}
...
}
int main(int argc, char **argv)
{
...
in_mbox_data = MBOX_HELLO;
/* PPE -----MBOX-----> SPE (check if we can write in the inbound mailbox) */
while(spe_in_mbox_status(tinfo[0].ctx) == 0);
res = spe_in_mbox_write(tinfo[0].ctx, &in_mbox_data, 1,SPE_MBOX_ALL_BLOCKING);
assert(res == 1);
/* PPE <-----MBOX----- SPE (check if there is any message in the outbound mailbox) */
while(spe_out_mbox_status(tinfo[num_spes-1].ctx) == 0);
res = spe_out_mbox_read(tinfo[num_spes-1].ctx, &out_mbox_data, 1);
assert(res == 1); assert(out_mbox_data == MBOX_HELLO_ACK);
fprintf(stderr, "PPE: MBOX test sent %d and received %d\n", in_mbox_data, out_mbox_data);
...
}
int main(uint64_t speid, uint64_t id, EA cb_ptr)
{
...
/* DMA call to get the control block from main memory. */
mfc_get(&cb, cb_ptr, sizeof(control_block), CB_TAG, 0, 0);
/* Now, we set the "tag bit" which is always 1 left-shifted by the tag
specified with the DMA for whose completion you wish to wait. */
mfc_write_tag_mask(1<<CB_TAG);
/* Finally, issue the read and wait for DMA completion. */
mfc_read_tag_status_all();
fprintf(stderr, "SPE %lld (%llx): got cb (%p) from main memory (0x%llx)\n",
id, speid, &cb, cb_ptr);
...
}
int main(uint64_t speid, uint64_t id, EA cb_ptr)
{
...
in_mbox_data = spu_read_in_mbox(); assert(in_mbox_data == (MBOX_HELLO+id));
if (id < (cb.num_spes-1)) {
control_area.SPU_In_Mbox = in_mbox_data + 1;
CHECK_DMA_ALIGN(&control_area.SPU_In_Mbox, cb.control_addr[id+1] +
SHIFT_SPU_IN_MAILBOX, sizeof(unsigned int));
mfc_put(&control_area.SPU_In_Mbox, cb.control_addr[id+1] + SHIFT_SPU_IN_MAILBOX,
sizeof(unsigned int), MBOX_TAG, 0, 0);
mfc_write_tag_mask(1<<MBOX_TAG); mfc_read_tag_status_all();
fprintf(stderr, "SPE %lld (%llx): MBOX test: received %d sent %d\n",
id, speid, in_mbox_data, in_mbox_data + 1);
}
...
else if (id == (cb.num_spes-1)) {
spu_write_out_mbox(MBOX_HELLO_ACK);
fprintf(stderr, "SPE %lld (%llx): MBOX test: received %d sent %d\n",
id, speid, in_mbox_data, MBOX_HELLO_ACK);
}
...
}
int main(int argc, char **argv)
{
...
/* marshall the control block and the thread_info structures */
for(i=0; i < num_spes; i++)
{
...
/* get memory-mapped address of SPEs' signal area */
tinfo[i].sig1_addr = (void *) spe_ps_area_get(tinfo[i].ctx, SPE_SIG_NOTIFY_1_AREA);
cb.sig1_addr[i] = (EA) tinfo[i].sig1_addr;
...
}
...
}
int main(int argc, char **argv)
{
...
/* PPE -----SIGNAL-----> SPE */
in_signal = SIGNAL_HELLO;
res = spe_signal_write(tinfo[0].ctx, SPE_SIG_NOTIFY_REG_1, in_signal); assert(res == 0);
/* PPE <------MBOX------ SPE (check if there is any message in the outbound mailbox) */
while(spe_out_mbox_status(tinfo[num_spes-1].ctx) == 0);
res = spe_out_mbox_read(tinfo[num_spes-1].ctx, &out_mbox_data, 1); assert(res == 1);
assert(out_mbox_data == MBOX_HELLO_ACK);
fprintf(stderr, "PPE: SIGNAL test sent %x and received %d\n",
SIGNAL_HELLO, out_mbox_data);
...
}
int main(uint64_t speid, uint64_t id, EA cb_ptr)
{
...
/* DMA call to get the control block from main memory. */
mfc_get(&cb, cb_ptr, sizeof(control_block), 31, 0, 0);
/* Now, we set the "tag bit" which is always 1 left-shifted by the tag
specified with the DMA for whose completion you wish to wait. */
mfc_write_tag_mask(1<<31);
/* Finally, issue the read and wait for DMA completion. */
mfc_read_tag_status_all();
fprintf(stderr, "SPE %lld (%llx): got cb (%p) from main memory (0x%llx)\n",
id, speid, &cb, cb_ptr);
...
int main(uint64_t speid, uint64_t id, EA cb_ptr)
{
...
in_signal = spu_read_signal1();
if (id < (cb.num_spes-1)) {
spe_sig_notify_1_area.SPU_Sig_Notify_1 = in_signal + 1;
mfc_sndsig(&spe_sig_notify_1_area.SPU_Sig_Notify_1,
cb.sig1_addr[id+1] + SHIFT_SIG_NOTIFY_1,
SIGNAL_TAG, 0, 0);
mfc_write_tag_mask(1<<SIGNAL_TAG);
mfc_read_tag_status_all();
}
...
}
int main(uint64_t speid, uint64_t id, EA cb_ptr)
{
...
else if (id == (cb.num_spes-1)) {
spu_write_out_mbox(MBOX_HELLO_ACK);
}
fprintf(stderr, "SPE %lld (%llx): SIGNAL test: received %x and sent %x\n",
id, speid, in_signal, in_signal + 1);
...
}
int main(int argc, char **argv)
{
...
/* ATOMIC Ops test */
fprintf(stderr, "PPE: shared variable is %d\n", shared_var);
...
/* wait until all SPEs are done */
while( shared_var != (SHARED_VALUE+(num_spes * INC_VALUE)) );
fprintf(stderr, "PPE: shared variable is %d\n", shared_var);
...
}
int main(uint64_t speid, uint64_t id, EA cb_ptr)
{
...
/* atomically increment shared variable in main memory */
res = _atomic_add_return(INC_VALUE, cb.shared_var_ptr); /* fetch&add */
fprintf(stderr, "SPE %lld (%llx): ATOMIC OPS test: obtained %d\n", id, speid, res);
...
}
if ( __builtin_expect((a>b),0) ) c+=a else c+=b
int main(int argc, char **argv)
{
...
/* float source and destination vectors */
float vec1[MAX_VECTOR] __attribute__(aligned(128));
float vec2[MAX_VECTOR] __attribute__(aligned(128));
float vec_res[MAX_VECTOR] __attribute__(aligned(128));
...
/* init the control block */
cb.num_spes = num_spes = atoi(argv[1]);
cb.vec1_ptr = (EA) vec1;
cb.vec2_ptr = (EA) vec2;
cb.vec_res_ptr = (EA) vec_res;
...
}
int main(int argc, char **argv)
{
...
/* initialize vectors */
memset(vec1, sizeof(float) * MAX_VECTOR, 0.0);
for(i=0;i<MAX_VECTOR;i++) vec1[i] = DMA_VALUE1;
memset(vec2, sizeof(float) * MAX_VECTOR, 0.0);
for(i=0;i<MAX_VECTOR;i++) vec2[i] = DMA_VALUE2;
memset(vec_res, sizeof(float) * MAX_VECTOR, 0.0);
...
}
int main(int argc, char **argv)
{
...
/* tell SPEs they can proceed */
in_mbox_data = DMA_HELLO;
for(i=0;i<num_spes;i++) {
/* PPE -----MBOX-----> SPE (check if we can write in the inbound mailbox) */
while(spe_in_mbox_status(tinfo[i].ctx) == 0);
res = spe_in_mbox_write(tinfo[i].ctx,&in_mbox_data,1,SPE_MBOX_ALL_BLOCKING);
assert(res == 1);
}
...
}
int main(int argc, char **argv)
{
...
/* wait until all SPEs are done */
for(i=0;i<num_spes;i++) {
/* PPE <------MBOX------ SPE (check if there is any message in the outbound mailbox) */
while(spe_out_mbox_status(tinfo[i].ctx) == 0);
res = spe_out_mbox_read(tinfo[i].ctx, &out_mbox_data, 1);
assert(res == 1);
assert(out_mbox_data == DMA_HELLO_ACK);
}
...
}
int main(uint64_t speid, uint64_t id, EA cb_ptr)
{
...
in_mbox_data = spu_read_in_mbox();
assert(in_mbox_data == DMA_HELLO);
elems = MAX_VECTOR/cb.num_spes;
myid = (unsigned int) id;
mysize = elems * sizeof(float);
vec1_ptr = (int) cb.vec1_ptr + (int) myid * mysize;
vec2_ptr = (int) cb.vec2_ptr + (int) myid * mysize;
vec_res_ptr = (int) cb.vec_res_ptr + (int) myid * mysize;
...
}
int main(uint64_t speid, uint64_t id, EA cb_ptr)
{
...
/* copy vec1 and vec2 fragments from main memory */
mfc_get(vec1, vec1_ptr, mysize, DMA_TAG, 0, 0);
mfc_get(vec2, vec2_ptr, mysize, DMA_TAG, 0, 0);
mfc_write_tag_mask(1<<DMA_TAG);
mfc_read_tag_status_all();
...
}
int main(uint64_t speid, uint64_t id, EA cb_ptr)
{
...
/* add vec1 and vec2 fragments */
for(i=0;i<elems/4;i++) {
vec_res[i] = spu_add(vec1[i], vec2[i]);
}
...
}
nt main(uint64_t speid, uint64_t id, EA cb_ptr)
{
...
/* copy vec_res fragment back in main memory */
mfc_put(vec_res, vec_res_ptr, mysize, DMA_TAG, 0, 0);
mfc_write_tag_mask(1<<DMA_TAG);
mfc_read_tag_status_all();
...
}
santo079 escribió:Ya lo sabia
PRiSMiWi escribió:Uff... pero un tutorial para esto es pasarse de extensión ¿no? Un curro exagerado de bueno, ¿tocarás la parte de la programación concurrente?
yevon escribió:yo solo entiendo una cosa, cell es una pesadilla xD
CORAGON2 escribió:[offtopic]Acid-Burn que sepas que no eres bienvenido por un sitio... [/offtopic]
Psmaniaco escribió:Yo me remito a la pregunta que le hice a Acid-burn sobre las herramientas de compilacion del Cell si se pueden usar para compilar en los procesadores x86,por que en la PS3 con la poca RAM de la que dispone se hace eterno compilar algo en Linux.
Un saludo.
Lanik79 escribió:Desde luego es un curro de la hostia... gracias!!
Psmaniaco escribió:Oye pues no me importaria,pero me tendriais que dar un cursillo ya que en programacion de Linux he perdido un poco de practica(hace años que compile mi ultimo kernel jejeje).
Por cierto ahora que lo mencionas f5inet,ya que las ultimas distros de linux usan una de las SPU como aceleradora 3D tengo una pequeña duda¿se podria programar otra SPU para la misma tarea?,es decir usar 2 para aceleracion grafica por hardware,creo que podrian funcionar en paralelo,aunque tengo mis dudas.
Un saludo.
Psmaniaco escribió:Era lo del hilo bloqueado en el PPU,gracias por la aclaracion,una cosa mas¿como harias para mejorar el rendimiento grafico si el hilo que conecta la SPU con el PPU se bloquea?aparte de eso cuando el SPU que calcula los graficos si tiene que tirar de memoria RAM para video¿que la coje de la RAM principal(que son 256 MB) o recurre a la swap que usa la RAM del RSX?
Un saludo.
Psmaniaco escribió:Yo mientras IBM y Toshiba sigan dando informacion y el SDK para el Cell seguire adelante,desde luego Sony la esta cagando a base bien con este tema,veremos si esta decision no les pasa factura tarde o temprano.
Un saludo.
Psmaniaco escribió:Gracias por las clases f5inet ,ahora que se puede cargar ejecutables sin firmar en la Xbox 360 esperare a ver si adaptan el kernel del Linux al los 3 cores de la 360 y la GPU para usar el Linux en la 360,pero mientras tanto a centrarse en el Cell.
Un saludo.
Acid-burn escribió:todavía no esta terminado! tengo poco tiempo, lo terminaré en breve.