Pot fi mai multe tipuri de programe: programe PPE, programe SPE si programe pentru Cell Broadband Engine (programe PPE care au programme SPE embedded).
Programele pentru PPE si SPE folosesc compilatoare diferite. Compilatorul, flagurile compilatorului si librariile trebuie folosite in functie de tipul de procesor si program. De obicei, un PPE seteaza, porneste si opreste SPEuri. Un aspect important ce trebuie luat in consideratie este comunicarea dintre PPEuri si SPEuri.
Exista doua modalitati de baza pentru a testa un program pentru Cell Broadband Engine: prima se refera la folosirea de fisiere Makefile iar cea de a doua la folosirea unui mediu IDE (aceasta modalitate va fi prezentata in laboratorul urmator, folosind Eclipse). Mai departe vom exemplifica lucrul cu fisiere Makefile. Pentru mai multe detalii se poate consulta fisierul “README_build_env.txt” ce poate fi gasit in ”/opt/cell/sdk/buildutils”.
In fisierele Makefile se pot declara tipul programelor, compilatorul ce va fi folosit, optiunile de compilare si librariile ce vor fi folosite. Cele mai importante tipuri de tinte (target types) sunt: PROGRAM_ppu and PROGRAM_spu, pentru compilarea programelor PPE si respective SPE. Pentru a folosi definitiile pentru makefile din kitul SDK, trebuie inclusa urmatoarea linie la sfarsitul fisierului makefile:
include ../../../buildutils/make.footer
Trebuie folosit un numar sufiecient de ”../” pentru a ajunge la directorul buildutils. Alternativa este indicarea sursei pentru make.footer (mai ales cand se lucreaza din Eclipse IDE framework) definind in prealabil si folosind variabila de mediu CELL_TOP dupa cum urmeaza:
include $(CELL_TOP)/buildutils/make.footer
Se pot folosi ambele metode de a importa make.footer, asa cum se va vedea in exemplul de mai jos. In Figura 12 este prezentata structura de directoare si fisiere makefile pentru un sistem cu un program PPE si un program SPE. Acest proiect sampleproj are un director de proiect si doua subdirectoare. Directorul ppu contine codul sursa si fisierul makefile pentru programul PPE. Directorul spu contine codul sursa si fisierul makefile pentru programul SPE. Fisierul makefile din directorul de proiect lanseaza in executie fisierele makefile din cele doua subdirectoare. Aceasta structura de organizare pe directoare nu este unica.
<imgcaption image1|Exemplu de structura de directoare a unui proiect si fisiere makefile></imgcaption>
#include <libspe2.h> spe_context_ptr_t spe_context_create(unsigned int flags, spe_gang_context_ptr_t gang)
#include <libspe2.h> int spe_program_load (spe_context_ptr_t spe, spe_program_handle_t *program)
#include <libspe2.h> int spe_context_run(spe_context_ptr_t spe, unsigned int *entry, unsigned int runflags, void *argp, void *envp, spe_stop_info_t *stopinfo)
#include <libspe2.h> int spe_context_destroy (spe_context_ptr_t spe)
Nu ma uit la parametrii de return: context_create / program_load / context_run / context_destroy
.
#include <stdio.h> #include <libspe2.h> extern spe_program_handle_t hello_spu; int main(void) { spe_context_ptr_t speid; unsigned int entry = SPE_DEFAULT_ENTRY; spe_stop_info_t stop_info; speid = spe_context_create(0, NULL); spe_program_load(speid, &hello_spu); spe_context_run(speid, &entry, 0, NULL, NULL, &stop_info); spe_context_destroy(speid); return 0; }
Acum, eu trebuie sa pregatesc programul compilat pe spu sa fie linkat ca librarie [spu/Makefile]:
PROGRAM_spu := hello_spu LIBRARY_embed := hello_spu.a include $(CELL_TOP)/buildutils/make.footer
In makefile-ul PPE-ului trebuie atunci sa-i amintesc ca am in spate de fapt o librarie (vezi extern
).
DIRS = ../spu PROGRAM_ppu = hello_be1 IMPORTS = ../spu/hello_spu.a -lspe2 -lpthread include $(CELL_TOP)/buildutils/make.footer
Uramtorul program va fi de acum incolo programul de la care se vor dezvolta restul programelor. Acesta porneste de pe PPE SPU_THREADS
programe (contexte). Arhiva se poate descarca de aici: labXcell.zip.
SPE Slave
#include <stdio.h> int main(unsigned long long id) { printf("Hello Cell (0x%llx)\n", id); return 0; }
Makefile-ul pentru SPU
PROGRAM_spu=spu LIBRARY_embed=lib_spu.a SPU_TIMING=1 include $(CELL_TOP)/buildutils/make.footer
PPE Master
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <libspe2.h> #include <pthread.h> #define SPU_THREADS 8 extern spe_program_handle_t spu; void *ppu_pthread_function(void *arg) { spe_context_ptr_t ctx; unsigned int entry = SPE_DEFAULT_ENTRY; ctx = *((spe_context_ptr_t *)arg); if (spe_context_run(ctx, &entry, 0, NULL, NULL, NULL) < 0) { perror ("Failed running context"); exit (1); } pthread_exit(NULL); } int main(void) { int i; spe_context_ptr_t ctxs[SPU_THREADS]; pthread_t threads[SPU_THREADS]; /* Create several SPE-threads to execute 'SPU'. */ for(i=0; i<SPU_THREADS; i++) { /* Create context */ if ((ctxs[i] = spe_context_create (0, NULL)) == NULL) { perror ("Failed creating context"); exit (1); } /* Load program into context */ if (spe_program_load (ctxs[i], &spu)) { perror ("Failed loading program"); exit (1); } /* Create thread for each SPE context */ if (pthread_create (&threads[i], NULL, &ppu_pthread_function, &ctxs[i])) { perror ("Failed creating thread"); exit (1); } } /* Wait for SPU-thread to complete execution. */ for (i=0; i<SPU_THREADS; i++) { if (pthread_join (threads[i], NULL)) { perror("Failed pthread_join"); exit (1); } /* Destroy context */ if (spe_context_destroy (ctxs[i]) != 0) { perror("Failed destroying context"); exit (1); } } printf("\nThe program has successfully executed.\n"); return (0); }
Makefile-ul pentru PPE
DIRS=../spu PROGRAM_ppu=ppu IMPORTS=../spu/lib_spu.a -lspe2 -lpthread include $(CELL_TOP)/buildutils/make.footer