Curso Avanzado Cell Broad Engine by Acid-burn

Moderadores: Kravenbcn, largeroliker, fidelcastro, cerealkiller, pspCaracas, dark_sasuke, m0skit0, LnD, ka69, zacky06, driKton

Responder
Avatar de Usuario
Acid-burn
Novato
Novato
Mensajes: 8
Registrado: 03 Sep 2009, 19:56

Curso Avanzado Cell Broad Engine by Acid-burn

Mensaje por Acid-burn »

Programación de procesadores multinúcleo.
Introducción a la programación del Cell Broadband Engine (Cell BE)
Programación del Cell BE:
-Introducción
-Arquitectura del Cell BE
-Programación del Cell BE
-Conclusiones

1-Introducción

Motivación
• Procesadores monolíticos --------------------------------------------------• Procesadores modulares
• Procesadores mononúcleo -------------------------------------------------• Procesadores multinúcleo
• Complejidad: diseño hardware ----------------------------------------------• Complejidad: desarrollo y optimización del software

Imagen


Desafíos
• Restricciones tecnológicas
• Los núcleos de procesamiento son más simples
– Menos transistores dedicados a lógica de control y a almacenamiento
– Falta de predicción de saltos y otras técnicas de especulación agresivas
– Cantidad limitada de memoria dentro del chip para cada núcleo (el tamaño de la memoria escala a un ritmo menor que el tamaño de los núcleos)
• Cantidad limitada de ancho de banda de acceso a memoria
• Restricciones software
• Complejidad que supone el desarrollo y optimización de nuevas aplicaciones paralelas
• Dificultad para construir nuevos compiladores capaces de extraer automáticamente el paralelismo sin intervención del programador
• Fracción del rendimiento pico que se puede conseguir con aplicaciones reales
• Migración de software existente construido sobre MPI, OpenMP, Cray Shmem, etc.

Objetivos
• Existe una arquitectura multinúcleo que está recibiendo una enorme atención debido a su tremendo potencial: Cell BE
• El Cell BE posee un modelo de programación no tradicional
• En esta sesión vamos a explicar los conceptos básicos en los que se basa este modelo de programación
• Para ello, resulta imprescindible conocer su arquitectura
• A continuación, pasaremos a analizar y ejecutar algunos ejemplos reales sobre una PS3
• Por último, esbozaremos las técnicas de optimización más relevantes


Cell BE
• Desarrollado conjuntamente por Sony (PS3), Toshiba e IBM (STI)
• Procesadormultinúcleo heterogéneo diseñado específicamente para explotar tanto el paralelismo de datos (SIMD) como el paralelismo a nivel de thread (Thread-Level Parallelism, TLP)
• 1 x Power Processor Element (PPE)
– Procesador de propósito general para ejecutar el SO y coordinar las tareas de los demás núcleos (el jefe)
• 8 x Synergistic Processing Element (SPE)
– Procesadores de propósito específico diseñados para tratar grandes cantidades de datos (los subordinados)
• Rendimiento pico de 204.8 Gflops (simple precisión) y 14.64 Gflops (doble precisión)


Arquitectura del Cell BE

Imagen



PPE

• Procesadormultinúcleo hetérogéneo
• 1 x Power Processor Element (PPE)
– 64-bit Power-architecture-compliant processor
– Dual-issue, in-order execution, 2-way SMT processor
– PowerPC Processor Unit (PPU)
– 32 KB L1 IC, 32 KB L1 DC, VMX unit
– PowerPC Processor Storage Subsystem(PPSS)
– 512 KB L2 Cache
– Procesador de propósito general para ejecutar el SO y el código de control
– Coordina las tareas realizadas por los demás núcleos

Imagen


SPEs
• Procesadormultinúcleo hetérogéneo
• 8 x Synergistic Processing Element (SPE)
– Dual-issue, in-order execution, 128-bit SIMD processors
– Synergistic Processor Unit (SPU)
– ISA SIMD (cuatro granularidades diferentes) con banco de registros SIMD (128 registros de 128 bits )
– 256 KB Local Storage (LS) para código/datos
– Memory Flow Controller (MFC)
– Memory-mapped I/O registers (MMIO Registers)
– DMA Controller: comandos para transferir datos desde/hacia memoria principal/LSs
– Procesadores de propósito específico diseñados para tratar datos
– Proporcionan la capacidad de cómputo principal

Imagen


Esquema general
• Element Interconnect Bus (EIB)
– Interconecta PPE, SPEs, y los controladores de memoria y E/S
– 4 anillos de 16 Bytes de ancho (2 en sentido horario y 2 en sentido antihorario)
– Hasta tres transferencias de datos simultáneas por anillo
– Algoritmo de ruta más corta
• Memory Interface Controller (MIC)
– 2 canales de memoria Rambus XDR (accesos en cada canal de 1-8, 16, 32, 64 o 128 Bytes)
• Cell BE Interface (BEI)
– 2 canales Rambus FlexIO I/O (1 de ellos puede unir 2 Cell BEs – 16 SPEs)

Imagen

El encanto del Cell BE
• Capacidad de procesamiento (3.2 GHz)
• Rendimiento pico de 204.8 Gflops (simple precisión) y 14.64 Gflops (doble precisión)
• Ancho de banda interno
• Rendimiento pico de 204.8 GB/s
• Ancho de banda de acceso a memoria (25.6 GB/s) y a los dispositivos de E/S (25 GB/s entrantes y 35 GB/s salientes)
• Permite que se realicen muchas peticiones de acceso a memoria de manera simultánea
• Hasta 128 operaciones de transferencia de DMA pendientes


Sistemas comerciales


• Cell BE disponible en:
• Play Station 3
– Alternativa más barata pero…
– …sólo 6 SPEs disponibles y < 200 MB para apps.
• IBM Blade Center QS20/21/22
• Mercury dual Cell-based blade
• Mercury Cell-based PCI Express board

Imagen Imagen Imagen

Supercomputadores
• IBM Roadrunner: supercomputador más rápido del mundo
– Hardware: diseño híbrido
– TriBlade: 2 x dual-core Opterons (16 GB RAM) + 4 x PowerXCell 8i (16 GB RAM)
– 12960 IBM PowerXCell 8i (Cell BE)
– 6480 AMD Opterons
– Software: basado en Linux
– Red Hat Enterprise Linux
– xCAT
– DaCS for Hybrid
– ALF
– Open MPI
Imagen

Programación del Cell BE

Filosofía general

• El Cell BE proporciona
• Gran capacidad de procesamiento (pico) dentro del chip (SPEs)
• Gran ancho de banda agregado (pico) dentro del chip (EIB)
• Pequeñas memorias locales dentro del chip (escasa reutilización de los datos)
• …lo que significa que deberíamos…
• Implementar algoritmos de distribución y balanceo de la carga para alimentar a todos los SPEs de manera equitativa
• Favorecer diseños algorítmicos que transfieran los datos dentro del chip en vez de acceder a memoria principal continuamente
• Incorporar esquemas algorítmicos (por ejemplo, double-buffering) que permitan solapar cómputo y comunicaciones
• Cuestiones críticas: sincronización, balanceo de la carga y movimiento de datos

Esquema general

• Los SPEs ejecutan threads creados por el PPE y sólo pueden acceder a código/datos dentro de su propio LS
• Programas diferentes escritos en C/C++ para el PPE y los SPEs
• Normalmente los SPEs ejecutan el mismo código pero sobre diferentes datos (Single ProgramMultiple Data, SPMD)
• Data Parallelism
• No obstante, también son posibles otros esquemas alternativos
• Task parallelism, pipeline, function offload, device management, etc.
• SDK proporcionado por IBM (usaremos la versión 3.0)
• Programas diferentes escritos en C/C++ para el PPE y los SPEs
• Código del PPE
– Tipos de datos vectoriales e intrinsics para utilizar la unidad VMX (por ejemplo, vector float or vec_add)
– Funciones de librería para manejar los threads y llevar a cabo tareas de comunicación y sincronización (por ejemplo, spe_context_run, spe_mfcio_put, spe_in_mbox_write)
• Código de los SPEs
– Tipos de datos vectoriales e intrinsics para hacer uso del ISA SIMD (por ejemplo, vector float or spu_add)
– Funciones de librería para llevar a cabo tareas de comunicación y sincronización (por ejemplo, mfc_get, spu_read_in_mbox)
• Librerías BLAS, LAPACK y SIMD Math

Otras librerías/entornos para programar el Cell BE

• Data Communications and Synchronization (DaCS) library y Accelerated Library Framework (ALF) se incluyen en la última versión del SDK de IBM
• Cell Superscalar (CellS) desarrollado por Barcelona Supercomputing Center
• Multicore Plus SDK Software desarrollado porMercury Computing Systems Inc.
• RapidMindMulticore Development Platform para procesadores multinúcleo de la familia x86 de AMD e Intel, GPUs de ATI/AMD y NVIDIA GPUs y Cell BE

Ejemplo 1: ¡HolaMundo!


EJEMPLO 1: ¡Hola Mundo!

Imagen

Ejemplo 1: ¡HolaMundo!

• Conectar PS3 (PuTTY/SSH)
• Usuario: AcidXX
• Clave: AcidXX.09
• Donde XX Є [01..30]
• [AcidXX@...]$

Imagen


• Descargar ejemplos.tgz de:

-Servidor Ftp: clustercell.no-ip.org
-Usuario: dark-alex.org
-Pass: dark-alex.org
• Extraer ficheros de ejemplo y acceder al directorio de ejemplo /cellbe_hello

Imagen

• Compilar:
• [AcidXX@...] $ cat ../ps3.env export CELL_TOP=/opt/ibm/cell-sdk/prototype
• [AcidXX@...] $ source ../ps3.env
• [AcidXX@...] $ make
• Ejecutar:
• [AcidXX@...] $ ppu/cellbe_hello 1
• Editar código:
• [AcidXX@...] $ vim ppu/cellbe_hello_ppu.c
• [AcidXX@...] $ vim spu/cellbe_hello_spu.c

• Código PPE
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);
}

• Código SPEs

int main(uint64_t speid, uint64_t id)
{
/* ¡Hola mundo! */
fprintf(stderr, "SPE %lld (%llx): ¡Hola mundo!\n", id, speid);
return 0;
}


Comunicación y sincronización

• El PPE y los SPEs se comunican y sincronizan utilizando un conjunto de mecanismos soportados por el hardware:
• Buzones (mailboxes), señales (signals), operaciones atómicas (atomic operations) y transferencias de DMA
• Los registros MMIO que corresponden a buzones, señales y DMA controller de cada SPE están, como su nombre indica, mapeados en memoria.
• El PPE y los SPEs pueden programar el DMA controller para realizar transferencias entre la memoria principal, los LSs y los dispositivos de E/S
• Transferencias de DMA iniciadas por un SPE o por el PPE, bloqueantes o no bloqueantes, entre memoria principal y el LS de un SPE o entre dos LSs de dos SPEs diferentes
• Restricciones en las direcciones de memoria y el tamaño
• Las direcciones de memoria de origen y destino deben estar alineadas con un límite de 16 B
• Tamaño de DMA de 1, 2, 4, 8B o múltiplos de 16B hasta un máximo de 16 KB
• NOTA: se obtiene un mejor rendimiento cuando las direcciones de origen y destino están alineadas con un límite de 128 Bytes y el tamaño de la trasferencia es un múltiplo de 128 Bytes
• Buzones (mailboxes): permiten el intercambio de mensajes de 32 bits entre los SPEs y el PPE
• Envío de mensajes desde el SPE
– 1-entry SPU Write Outbound Mailbox
– 1-entry SPU Write Outbound Interrupt Mailbox
• Recepción de mensajes en el SPE
– 4-entry SPU Read Inbound Mailbox
• Cada buzón tiene un canal y su correspondiente registro MMIO
• El canal permite al SPE propietario leer/escribir de/en los buzones
• El registro MMIO permite a otros SPEs y al PPE leer/escribir de/en los buzones

Ejemplo 2: Uso de buzones


EJEMPLO 2: Uso de buzones

Ejemplo 2: Uso de buzones

Código: Seleccionar todo

• 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


• Código PPE


Código: Seleccionar todo

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;
...
}
...
}


Código: Seleccionar todo

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);
...
}



• Código SPEs

Código: Seleccionar todo

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);
...
}


Código: Seleccionar todo

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);
}


Código: Seleccionar todo

...
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);
}
...
}


Comunicación y sincronización: señales

• Señales (signals): permiten a los SPEs recibir notificaciones de 32 bits de otros SPEs o incluso del PPE
• Recepción de notificaciones en el SPE
– 1-entry SPU Signal Notification 1
– 1-entry SPU Signal Notification 2
• Cada registro de señales tiene un canal y su correspondiente registroMMIO
• El canal permite al SPE propietario leer el registro de señales que se resetea
• El registroMMIO permite a otros SPEs y al PPE escribir en el registro de señales en modo sobrescritura (destruye el valor anterior) o en modo OR (combina el valor nuevo y el valor anterior con un OR lógico a nivel de bits)


EJEMPLO 3: Uso de señales

Ejemplo 3: Uso de señales

• Acceder a directorio de ejemplo:
• [AcidXX@...] $ cd Acid/cellbe_signal
• Compilar:
• [AcidXX@...] $ source ../ps3.env
• [AcidXX@...] $ make
• Ejecutar:
• [AcidXX@...] $ ppu/cellbe_signal 1
• Editar código:
• [AcidXX@...] $ vim ppu/cellbe_signal_ppu.c
• [AcidXX@...] $ vim spu/cellbe_signal_spu.c

• Código PPE

Código: Seleccionar todo

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;
...
}
...
}


Código: Seleccionar todo

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);
...
}



• Código SPEs

Código: Seleccionar todo

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);
...


Código: Seleccionar todo

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();
}
...
}

Código: Seleccionar todo

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);
...
}



Comunicación y sincronización: operaciones atómicas

• Operaciones atómicas (atomic operations): permiten ejecutar operaciones de lectura-modificación-escritura sobre números enteros almacenados en memoria principal de manera atómica
• Por ejemplo:
• t0: shared_var = 0; /* Memoria principal */
• t1/SPE0: my_var0 = atomic_add_return(3, shared_var,)
• t1/SPE1: my_var1 = atomic_add_return(5, shared_var)
• t2: shared_var = 8; /* Memoria principal */
• Dos escenario posibles:
• Escenario 1: my_var0 = 0 y my_var1 = 3
• Escenario 2: my_var0 = 5 y my_var1 = 0

EJEMPLO 4: Uso de operaciones atómicas


Ejemplo 4: Uso de operaciones atómicas

• Acceder a directorio de ejemplo:
• [AcidXX@...] $ cd Acid/cellbe_atopmicops
• Compilar:
• [AcidXX@...] $ source ../ps3.env
• [AcidXX@...] $ make
• Ejecutar:
• [AcidXX@...] $ ppu/cellbe_atomicops 1
• Editar código:
• [AcidXX@...] $ vim ppu/cellbe_atomicops_ppu.c
• [AcidXX@...] $ vim spu/cellbe_atomicops_spu.c

• Código PPE

Código: Seleccionar todo

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);
...
}


• Código SPEs

Código: Seleccionar todo

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);
...
}


Optimización del código

• Alineamiento de buffers origen/destino de transferencias
• Asignación estática: __attribute__(aligned(16))
• Asignación dinámica: void *malloc_align(size_t size, unsigned int n)
• Uso de código SIMD para aprovechar completamente los SPEs
• Double-buffering para solapar las transferencias de DMA con el cómputo
• Reducción del impacto de los saltos
• Branch hinting

Código: Seleccionar todo

if ( __builtin_expect((a>b),0) ) c+=a else c+=b

• Loop unrolling
• Function inlining
• Reordenación de instrucciones para maximizar los ciclos de dual-issue
• Double-buffering

Imagen

EJEMPLO 5: Suma de dos vectores

Suma de dos vectores

• Acceder a directorio de ejemplo:
• [AcidXX@...] $ cd Acid/cellbe_vectorAdd
• Compilar:
• [AcidXX@...] $ source ../ps3.env
• [AcidXX@...] $ make
• Ejecutar:
• [AcidXX@...] $ ppu/cellbe_vectorAdd 1
• Editar código:
• [AcidXX@...] $ vim ppu/cellbe_vectorAdd_ppu.c
• [AcidXX@...] $ vim spu/cellbe_vectorAdd_spu

• Código PPE

Código: Seleccionar todo

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;
...
}

Código: Seleccionar todo

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);
...
}


Código: Seleccionar todo

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);
}
...
}

Código: Seleccionar todo

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);
}
...
}


• Código SPEs

Código: Seleccionar todo

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;
...
}


Código: Seleccionar todo

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();
...
}


Código: Seleccionar todo

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]);
}
...
}


i

Código: Seleccionar todo

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();
...
}




Conclusiones

• El Cell BE es un procesador multinúcleo heterogéneo muy potente y versátil
• Su programación requiere conocer tanto su arquitectura como los mecanismos de comunicación/sincronización que posee
• Hemos analizado y ejecutado ejemplos sencillos de programación del Cell BE que hacen uso de las transferencias de DMA, los buzones, las señales y las operaciones atómicas
• La programación y optimización de código para el Cell BE es una tarea ardua y compleja aunque muy potente.

PD: Fuentes Ibm, Juan Peinador, apuntes varios...
Dark-Alex Team

Avatar de Usuario
m0skit0
Administrador
Administrador
Mensajes: 5585
Registrado: 03 Sep 2009, 09:35
Ubicación: 0xdeadbeef

Re: Curso Avanzado Cell Broad Engine by Acid-burn

Mensaje por m0skit0 »

Ese curso cojonudo ;)

PD: yo que tú formatearía ese código en C, no hay quién lea eso :P
Imagen

Avatar de Usuario
NEOBARON
ViP Hordes
ViP Hordes
Mensajes: 769
Registrado: 03 Sep 2009, 16:56
PSN ID: NEOBARON

Re: Curso Avanzado Cell Broad Engine by Acid-burn

Mensaje por NEOBARON »

Que alegria ver de nuevo los ladrillacos de Acid-Burn por aqui

Siempre me he preguntado si en realidad sera la de la pelicula o la Jolie le copio a el

Avatar de Usuario
Acid-burn
Novato
Novato
Mensajes: 8
Registrado: 03 Sep 2009, 19:56

Re: Curso Avanzado Cell Broad Engine by Acid-burn

Mensaje por Acid-burn »

Hola que tal. Aqui os dejo unos manuales de programación para cell segun Ibm en su version 3.0. Un saludo y espero que os ayude a entender a cell.
Enlaces de Megaupload:

1.- Guía de migración de liberias v3
http://www.megaupload.com/?d=CVM4AY80
2.- Manual de programación de cell
http://www.megaupload.com/?d=A4PYNN7S
3.- Manual de programación de Cell v3
http://www.megaupload.com/?d=Z30H4VSR
4.-Iso:
http://www.pad.lsi.usp.br/cell/download ... .0.0.0.iso
5.- Extras:
http://www.pad.lsi.usp.br/cell/download ... noarch.rpm

Saludos
Dark-Alex Team

Avatar de Usuario
darklex150
ViP Hordes
ViP Hordes
Mensajes: 1974
Registrado: 03 Sep 2009, 01:58
Contactar:

Re: Curso Avanzado Cell Broad Engine by Acid-burn

Mensaje por darklex150 »

Ufff.... esto es muy avanzado..... creo que tendre que volver a repasar lo basico otra vez.. :oops:
Imagen
Spoiler:
Imagen

Avatar de Usuario
Kravenbcn
Administrador
Administrador
Mensajes: 16291
Registrado: 01 Sep 2009, 21:27
PSN ID: Kravenbcn
Twitter: Kravenbcn
Ubicación: Barcelona
Contactar:

Re: Curso Avanzado Cell Broad Engine by Acid-burn

Mensaje por Kravenbcn »

Pedazo de tuto!!! Muy buen curro Acid, gracias por el tutorial ;)
No te pierdas nada, sigue a DaXHordes en Twitter, Facebook, Google+ y Youtube

Imagen
¿Quieres formar parte del equipo de DaXHordes.org? Esta es tu oportunidad.
PS3 · PS Vita · PSP

Avatar de Usuario
Rossen
Habitual
Habitual
Mensajes: 471
Registrado: 03 Sep 2009, 21:58
PSN ID: Rossenn
Ubicación: :)

Re: Curso Avanzado Cell Broad Engine by Acid-burn

Mensaje por Rossen »

Siento que esta muy bien explicado y aun así hay términos que no comprendo T_T

Responder