Cell/BE task library Code
Brought to you by:
gshi
File | Date | Author | Commit |
---|---|---|---|
examples | 2009-06-25 | gshi | [r6] disable NUMA by default |
ppu | 2009-06-16 | gshi | [r4] Applying the patch from gcst to fix some hardco... |
spu | 2009-06-08 | gshi | [r1] initial code drop |
Makefile | 2009-06-08 | gshi | [r1] initial code drop |
README | 2009-06-25 | gshi | [r7] update the README, added some explanation to th... |
make_options | 2009-06-16 | gshi | [r4] Applying the patch from gcst to fix some hardco... |
# Illinois Open Source License # # University of Illinois/NCSA # Open Source License # # Copyright © 2009, University of Illinois. All rights reserved. # # Developed by: # # Innovative Systems Lab # National Center for Supercomputing Applications # http://www.ncsa.uiuc.edu/AboutUs/Directorates/ISL.html # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal with # the Software without restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the # Software, and to permit persons to whom the Software is furnished to do so, subject # to the following conditions: # # * Redistributions of source code must retain the above copyright notice, this list # of conditions and the following disclaimers. # # * Redistributions in binary form must reproduce the above copyright notice, this list # of conditions and the following disclaimers in the documentation and/or other materials # provided with the distribution. # # * Neither the names of the Innovative Systems Lab, the National Center for Supercomputing # Applications, nor the names of its contributors may be used to endorse or promote products # derived from this Software without specific prior written permission. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT # OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS WITH THE SOFTWARE. # This library is build upon libspe2 from IBM Cell SDK. The motivation for the library is to hide the tedious context/pthread creation, mailbox/signal/interrupt mailbox communication in order to start jobs in SPUs and give a clean interface to the programmer. Compiling the library After downloading and untaring the library, you can do "make" in the root directory and it should compile. Do a "make install" will install the necessary head files and libraries into your home directory: ${HOME}/celltask You can change where you want to install by editting the Makefiles in --------------------------------------------------------------------------------------- Examples: There are two examples in the example directories using the library. 1. examples/helloworld The simple program to show how to register a function, construct a task and retrive the parameters in the spu program 2. /examples/matmul This program is a more complicated example showing how to do an array of 4x4 matrix multiplication, using double buffering. --------------------------------------------------------------------------------------- A quick look of the APIs PPE: int ppu_task_init(int argc, char **argv, spe_program_handle_t spe_main); int ppu_task_run(volatile task_t * task); int ppu_task_wait(void); void ppu_task_debug_level_set(int); int ppu_task_debug_level_get(void); extern int ppu_task_spe_num_get(); extern int ppu_task_spe_num_set(int); int ppu_task_spu_run(volatile task_t* task, int sperank); int ppu_task_spu_wait(void); void ppu_task_spu_waiton(int); void ppu_task_spu_waitall(void); void ppu_task_spu_time_reset(void); double ppu_task_spu_time_get(void); void ppu_task_physid_as_rank_set(); void ppu_task_physid_as_rank_reset(); SPE: int spu_task_size_get(void); int spu_task_rank_get(void); int spu_task_init(unsigned long long); int spu_task_run(void); int spu_task_register(dotask_t,int); char* spu_task_ls_get(int); void spu_task_debug_level_set(int); int send_msg_to_mailbox(int rank, int value); int recv_msg_from_mailbox(void); void spu_barrier(void); What you care most are ppu_task_spe_num_set(), //Set the number of SPEs to use. This one should be called before youc call the ppu_task_init(). ppu_task_init(), //which will initialize the data structures, create threads, run spe context and assign each spe a rank ppu_task_run(), //This function launches a function call, blocking, and it uses all spes, i.e each spe get the same task struct //and they are to figure which part of work they should according to their rank. spu_task_init(), // init the task library in spe spu_task_register(), //this one register a task ( a function) to an index( integer) // this function can be called multiple time to register different tasks spu_task_run(), //blocking function, infinite loop, unless one task function returns non-zero indicating error Here is a simple example on how to use libtask library (PPE code) extern spe_program_handle_t spu_main; compute_task_t task __attribute__ ((aligned (128))); int main(int argc, char** argv) { int n = 1; ppu_task_spe_num_set(n); ppu_task_debug_level_set(0); if (ppu_task_init(0, NULL, spu_main) < 0){ printf("Init failed\n"); return -1; } task.common.cmd = COMPUTE_TASK; task.common.size = sizeof(task); task.a = 1; task.b = 2; ppu_task_run((task_t*)&task); return 0; } I uses the integer a and b to demonstrate how variables can be transfered to SPEs. The function ppu_task_debug_level_set() is to set the debug level, the default is 0 (no debug output); if it is set to nonzero, there will be verbose output. The task structure is customized, but the first 8 bytes must be task_t, typedef struct compute_task_s{ task_t common; int a; int b; }compute_task_t; The spe code is like the following int main(unsigned long long spu_id, unsigned long long parm) { int rank; int rc; spu_task_debug_level_set(0); spu_task_init(parm); spu_task_register(do_compute_db, COMPUTE_TASK); spu_task_run(); return 0; } where all functions are self-explanary. The do_compute_db is a function int do_compute_db(task_t* _task) { compute_task_t* task = (compute_task_t*)_task; spu_log("got paramters: a=%d, b=%d\n", task->a, task->b); return 0; } The whole example program are available in examples/helloworld/ Therefore, the program can focus on putting whatever paramers necessary for computation into the compute_task_t structure, assign the values to them in ppe, and retrive the values in spe. Each spe should do part of the whole computation according to its rank. You can get spe's rank from spu_task_rank_get(); There is another mode where each spes works its own, in that case, the ppe side should call the functions: ppu_task_spu_* I will write more about that if there is need to. Qestions/suggestions? Please send emails to gshi@ncsa.uiuc.edu