Hlavní navigace

Základy programovania procesora Cell

28. 12. 2009
Doba čtení: 8 minut

Sdílet

V minulom dieli sme sa dozvedeli o heterogénnych procesoroch Cell, povedali sme si niečo o ich vnútornom usporiadaní a popísali sme jednotlivé časti Cell procesorov. V tejto časti seriálu si povieme niečo o tom, čo budeme potrebovať, ak chceme programovať aplikácie, ktoré okrem klasického PPE využijú aj SPE.

V tejto kapitole bude popísaný spôsob, ako vytvárať software, ktorý je schopný využiť možnosti CBEA t.j. zamestnať nie len PPE, ale aj dostupné SPE.

Prístup aplikácie k SPE zabezpečuje štandardizované nízkoúrovňové rozhranie menom SPE Runtime Management Library (libspe) – aktuálna verzia je libspe2. Ako to už väčšinou býva, aplikácie nemajú priamy prístup k fyzickým prostriedkom. Tento prístup riadi operačný systém. Aplikácia si vytvorí (skrz libspe API) len logickú reprezentáciu SPE, ktorú budeme nazývať SPU kontext, ktorú potom odovzdá operačnému systému, ktorý ju bude plánovať na jednotlivé dostupné SPE. Okrem správy kontextov poskytuje API libpse možnosť postarať sa o komunikáciu medzi PPE a SPE.

Vývojové prostredie

Na to, aby sme si mohli vyskúšať programovanie pre SPE, budeme potrebovať buď simulátor CBEA procesoru (existuje implementácia priamo od IBM), alebo nejaký použiteľný hardware, ideálne PlayStation 3. Tento článok je o autorových prvotných skúsenostiach s CBEA, preto sa bude venovať práve programovaniu na PS3. Na PS3 je teda nutné nainštalovať nejakú linuxovú distribúciu, napríklad PSUbuntu (návod je na psubuntu.com/wi­ki/Installati­onInstruction­s).

Potrebné balíčky

Na vývoj aplikácií pre SPE budeme potrebovať knižnicu libspe2, spu-gcc (spolu s spu-binutils) na preklad kódu v C do binárok pre SPE a ppu-gcc (spolu s ppu-binutils) na preklad a linkovanie kódu v C do špeciálnej binárky, ktorá pobeží čiastočne na PPE a čiastočne na SPE (obyčajným gcc by sme takúto binárku vyrobiť nemohli).

Formát binárnych súborov

Ako bolo spomenuté v predošlých kapitolách, PPE a SPE majú rôzne inštrukčné sady, preto ten istý kód preložený pre SPE bude vyzerať inak ako keď ho preložíme pre PPE.

Popíšeme si formát CESOF – CBEA Embedded SPE Object Format.

Toolchainy pre PPE a SPE (spu-gcc a ppu-gcc) produkujú binárky vo formáte ELF (Executable and Linkable Format – je to bežný formát binárnych súborov v linuxovom prostredí), budeme medzi nimi rozlišovať podľa mien : PPE-ELF a SPE-ELF (ich detailom sa venovať nebudeme, sú podrobne popísané v [1] a neobsahujú významné odchýlky od „obyčajného“ ELF formátu).

Formát CESOF je v skutočnosti formát PPE-ELF rozšírený o možnosť vložiť do PPE binárky SPE binárku. Okrem toho CESOF formát ešte umožňuje zdieľanie globálnych premenných medzi PPE a SPE kódom. Umožňuje to tak, že obsahuje navyše sekciu .spe-elf, ktorá je kontajnerom pre SPE binárku (formátu SPE-ELF). Každá SPE binárka navyše obsahuje okrem iných aj sekciu .toe, kde sa nachádzajú práve odkazy do hlavnej pamäte, na spomínané zdieľané dáta. Na obrázku je štruktúra CESOF formátu jasnejšia.

Cell struct

Na obrázku si všimnime .spe.elf sekciu v PPE-ELF súbore. Dostaneme sa k nej pomocou spu_program_han­dle štruktúry umiestnenej v PPE-ELF. Vpravo je pôvodná SPE-ELF binárka.

Takto vytvorený PPE-ELF môžeme spustiť na PPE a sme schopní preniesť a vykonať časť kódu na SPE (postup bude vysvetlený v ďalších kapitolách).

Existuje aj možnosť spúšťať SPE binárky bez nutnosti embedovať ich do PPE binárky. Umožňuje to utilitka s názvom elfspe. Jej použitie ale obmedzuje niektoré vlastnosti, vďaka ktorým je CBEA atraktívna architektúra (napríklad DMA).

Preklad a linkovanie programov

Na preklad a linkovanie programov pre CBEA budeme používať spomínané toolchainy spu-gcc a ppu-gcc. Pomocou spu-gcc najprv preložíme a zlinkujeme zdrojové kódy určené pre SPE. Podmienkou je to, že programy pre SPE musia byť linkované staticky.

spu-gcc spe_foo.c  -o spe_foo

Preložili sme kód v súbore spe_foo.c určený pre SPE do SPE-ELF binárky menom spe_foo.

Potom, čo sme vybudovali SPE binárku, pripravíme ju na embedovanie do PPE binárky. Na to nám poslúži utilita ppu-embedspu:

ppu-embedspu spe_foo spe_foo spe_foo.o

Prvým parametrom je meno, ktoré pomenuje štruktúru spe_program_han­dle, ktorú v PPE kóde použijeme ako odkaz na SPE program. Druhým parametrom je vstupný súbor (hodnota prepínača -o z volania spu-gcc) a nakoniec je meno pre výstupný súbor. Ppu-embedspu robí zhruba to, že „zabalí“ SPE binárku do .spe.elf sekcie a pripraví ju na linkovanie s PPE objektovými súbormi do CESOF binárky.

Posledným krokom bude preklad PPE kódu a jeho linkovanie s pripravenými SPE binárkami.

ppu-gcc spe_runner.c spe_foo.o -lspe2  -o test

Tu asi nie je čo vysvetľovať, spe_runner.c sa preloží a zlinkuje sa s spe_foo.o a knižnicou libspe2 do výslednej binárky s menom test, ktorú už môžeme bez problémov spustiť.

Hello world!

Teraz by sme už mali mať dostatok znalostí o tom, ako sa kompilujú a linkujú programy v tomto heterogénnom multiprocesorovm prostredí, skúsime si teda základ každého správneho tutoriálu, Hello world!

Zdrojový kód pre SPE, bude vyzerať jednoducho – vypíše jeden riadok na štandardný výstup a skončí.

#include <stdio.h>

int main(void){
    printf("Hello world!\n");
    return 0;
}

Keď tento kód preložíme pomocou spu-gcc, získame binárku pre SPE.

# spu-gcc hello_spe.c -o hello.spe

Obyčajné spustenie vyvolá chybu:

# ./hello.spe
-bash: ./hello.spe: cannot execute binary file

Zistíme teda nejaké základné informácie o tejto binárke…

# file hello.spe
hello.spe: ELF 32-bit MSB executable, Cell SPU, version 1 (SYSV), statically
linked, not stripped

Binárka je určená pre SPU, skúsime ju teda spustiť pomocou spomínaného elfspe.

# elfspe hello.spe
Hello world!

A konečne to funguje. Kód, ktorý napísal pozdrav, bežal na SPE. Ako dôkaz môže poslúžiť utilita spu-top a zabalenie výpisu Hello world do večného cyklu – vo výstupe spu-top sa pri behu objaví nejaká záťaž aj v riadku s názvom SPU, nie len CPU. (Poznámka: volanie printf vyvolá syscall, určitá záťaž sa preto prejaví aj na PPE (označené vo výpise ako CPU). SPE pri syscalle vygeneruje stop&signal inštrukciu a požiada PPE o I/O)

Zájdeme však ďalej. Skúsime vytvoriť program pre PPU, do ktorého vložíme binárku pre SPU a v PPU programe ju zavoláme.

Program pre PPU bude trochu zložitejší.

#include <libspe2.h>

extern spe_program_handle_t hello_spe_handle;

int main()
{
    int retval;
    unsigned int entry_point = SPE_DEFAULT_ENTRY;
    /*
    Required for continuing
        execution, SPE_DEFAULT_ENTRY is the standard starting offset.
    */
    spe_context_ptr_t my_context;

    /* Create the SPE Context */
    my_context = spe_context_create(SPE_EVENTS_ENABLE|SPE_MAP_PS, NULL);

    /* Load the embedded code into this context */
    spe_program_load(my_context, &hello_spe_handle);

    /* Run the SPE program until completion */
    do {
        retval = spe_context_run(my_context, &entry_point, 0, NULL, NULL,                               NULL);
    } while (retval > 0);

    spe_context_destroy(my_context);

    return 0;

}

Náš program pre PPE nebude robiť nič iné, len spustí program na SPU, počká, kým skončí a potom skončí on sám. Rozoberieme ho riadok po riadku.

Na prvom riadku sa inkluduje hlavičkový súbor knižnice libspe2, kde sú definované používané funkcie.

Na druhom riadku je externý odkaz na SPE program, vo forme štruktúry spe_program_han­dle. Jej meno je také, aké sme uviedli pri volaní ppu-embedspu – príprave SPU binárky na vloženie do PPE binárky.

Vo funkcii main je deklarovaná celočíselná premenná retval a definovaná premenná entry_point hodnoty SPE_DEFAULT_ENTRY. Tiež je deklarovaná premenná my_context typu spu_context_ptr_t. Je to odkaz na štruktúru reprezentujúcu spu kontext.

Na ďalšom riadku sa kontext vytvorí volaním spe_context_cre­ate. Prvým argumentom sme povedali, že chceme povoliť sledovanie udalostí na tomto kontexte a že chceme do hlavnej pamäte namapovať tzv. Problem State registry SPE (napríklad SPE Control Register). V tomto príklade je tento parameter nastavený len na ukážku, obvykle si vystačíte s hodnotou 0.

Druhý argument obsahuje prípadný gang, v ktorom chceme kontext vytvoriť (je tu možnosť vytvárať gangy t.j. skupiny kontextov, ktoré budú plánované súčasne na všetky SPE a budú vždy bežať paralelne). Funkcia vracia v prípade chyby hodnotu NULL a v errno nájdeme bližšie vysvetlenie chyby.

Keď máme pripravený kontext, „natiahneme“ doňho program, ktorý v ňom pobeží. To zariadime zavolaním spe_program_load, ktorá dostane kontext a handle na program, ktorý do kontextu natiahnuť.

Toto volanie zabezpečí to, že sa do LS SPE (lokálna pamäť na SPU, 256kB), s ktorým je kontext spriahnutý nahrá program zo .spe.elf sekcie CESOF binárky t.j. program pre SPE. Funkcia vracia 0, ak prebehla korektne, –1 inak a v errno v tomto prípade nájdeme detail chyby.

Chýba posledný krok – spustiť pripravený program na SPU. Na to slúži funkcia spe_context_run, ktorá si zaslúži podrobné vysvetlenie.

Prvý argument je zrejmý – kontext, ktorý má bežať.

Druhým argumentom je inštrukčný pointer. Pri volaní funkcie obsahuje adresu, kde sa má začať vykonávať kód, po návrate z funkcie obsahuje adresu, kde sa kód vykonávať prestal. To umožňuje SPE na chvíľu prerušiť beh, kontaktovať PPE s nejakou žiadosťou a pokračovať ďalej tam, kde skončil. Tretím argumentom, ktorým sú tzv. runflags, ktorými môžeme nakonfigurovať chovanie behu tohto kontextu. Štvrtý argument sú dáta aplikácie, ktoré sú predané SPE programu ako druhý parameter funkcie main (na SPE). Piaty argument sú informácie o prostredí, ktoré sa predajú ako tretí parameter funkcie main (na SPE). Ako posledný je nepovinný pointer na štruktúru typu spe_stop_info_t, ktorá obsahuje detaily o tom, prečo SPE prerušil beh.

Volanie spe_context_run ešte zabalíme do while cyklu, aby výpočet pokračoval aj po prerušení, ktoré je iné ako signalizácia ukončenia programu (ukončenie programu signalizuje návratová hodnota 0). Po ukončení cyklu okolo spe_context_run sa uvoľní vzniknutý kontext a program končí.

Nakoniec skúsime náš kód preložiť, zlinkovať do jednej binárky a spustiť.

# spu-gcc hello_spe.c -o hello.spe # ppu-embedspu hello_spe_handle hello.spe hello.spe.o # ppu-gcc hello_ppe.c hello.spe.o -lspe2 -o hello # ./hello
Hello world!

Vytvorili sme program, ktorý sme spustili na PPE a on spustil jednu svoju časť na SPE t.j. spojili sme do jednej binárky kódy dvoch rôznych architektúr. V ďalšom dieli si ukážeme, ako použiť DMA na prenos dát do pamäte SPE a ako využiť všetky dostupné SPE v našom systéme.

Literatúra

1 – Cell Broadband Engine Programming Handbook Including the PowerXCell 8i Processor , v 1.11

UX DAy - tip 2

2 – SPE Runtime Management Library Version 2.3

3 – www.kernel.org/…ingTutorial/

Byl pro vás článek přínosný?

Autor článku

Matej Dioszegi pracuje v Laboratořích CZ.NIC. Věnuje se především technologii DNSSEC, o které také přednáší.