| /* |
| * Copyright 2008 Sony Corporation of America |
| * |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a copy |
| * of this software and associated documentation files (the "Software"), to deal |
| * in 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: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * 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 |
| * AUTHORS 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 IN |
| * THE SOFTWARE. |
| */ |
| |
| #include <sys/time.h> |
| #include <string.h> |
| #include <pthread.h> |
| #include <libspe2.h> |
| #include <mars/task.h> |
| |
| #define INFO \ |
| "\ |
| Comparison: libmars v.s. libspe2 \n\ |
| -------------------------------- \n\ |
| This program compares the performance of running multiple \n\ |
| task contexts between libspe and libmars. This aims to show \n\ |
| the high cost of libspe's context switching. \n\ |
| \n\ |
| When a program needs to execute N number of MPU tasks \n\ |
| using libspe, N spe contexts must be created and executed. \n\ |
| During execution, the kernel's spufs scheduler will context \n\ |
| switch in and out these N spe contexts which entail very high \n\ |
| costs. \n\ |
| \n\ |
| The MARS library avoids the expensive spe context switches \n\ |
| by having the MARS kernel handle its own MARS task context \n\ |
| management, and keeping the MARS kernel resident on the MPUs. \n\ |
| \n\ |
| As the following results will show, as the number of tasks \n\ |
| increase, the slightly larger overhead of the MARS library is \n\ |
| quickly minisculed by the linearly increasing cost of libspe's \n\ |
| spe context switching. The resuling ERROR in libspe's results \n\ |
| is due to the fact that libspe has reached the limit of how \n\ |
| many spe contexts can be created at once. \n\ |
| \n\ |
| tasks: number of task contexts created \n\ |
| loop: number of iterations processed in each task context \n\ |
| \n" |
| |
| #define TIMER_START(timer)\ |
| {\ |
| struct timeval tv;\ |
| gettimeofday(&tv, NULL);\ |
| timer = tv.tv_sec * 1000000 + tv.tv_usec;\ |
| } |
| |
| #define TIMER_STOP(timer)\ |
| {\ |
| struct timeval tv;\ |
| gettimeofday(&tv, NULL);\ |
| timer = tv.tv_sec * 1000000 + tv.tv_usec - timer;\ |
| } |
| |
| extern struct spe_program_handle mpu_task_libmars_prog; |
| extern struct spe_program_handle mpu_task_libspe2_prog; |
| |
| typedef struct { |
| char name[32]; |
| int loop; |
| } pthread_arg; |
| |
| static void *spe_context_thread(void *arg) |
| { |
| struct mars_task_id task_id __attribute__((aligned(16))); |
| struct mars_task_args task_args __attribute__((aligned(16))); |
| task_args.type.u32[0] = ((pthread_arg *)arg)->loop; |
| strcpy((char *)&task_id.name, ((pthread_arg *)arg)->name); |
| |
| unsigned int entry = SPE_DEFAULT_ENTRY; |
| struct spe_context *spe; |
| |
| spe = spe_context_create(0, NULL); |
| spe_program_load(spe, &mpu_task_libspe2_prog); |
| spe_context_run(spe, &entry, 0, &task_id, &task_args, NULL); |
| spe_context_destroy(spe); |
| |
| pthread_exit(0); |
| |
| return NULL; |
| } |
| |
| static int libspe2(int task, int loop) |
| { |
| int i; |
| int ret = 0; |
| int initialized = 0; |
| |
| pthread_t spe_context_threads[task]; |
| pthread_arg spe_context_thread_arg[task]; |
| |
| for (i = 0; i < task; i++) { |
| sprintf(spe_context_thread_arg[i].name, "libspe2 Task %d", i); |
| spe_context_thread_arg[i].loop = loop; |
| ret = pthread_create(&spe_context_threads[i], NULL, |
| (void *)spe_context_thread, |
| (void *)&spe_context_thread_arg[i]); |
| if (ret) { |
| initialized = i; |
| break; |
| } |
| } |
| |
| if (ret) { |
| for (i = 0; i < initialized; i++) { |
| pthread_join(spe_context_threads[i], NULL); |
| } |
| return -1; |
| } |
| |
| for (i = 0; i < task; i++) { |
| ret = pthread_join(spe_context_threads[i], NULL); |
| if (ret) |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static int libmars(int task, int loop) |
| { |
| int i; |
| int ret; |
| char name[task][32]; |
| |
| struct mars_context *mars_ctx; |
| struct mars_task_id task_id[task]; |
| struct mars_task_args task_args; |
| |
| ret = mars_context_create(&mars_ctx, 0, 0); |
| if (ret) |
| return -1; |
| |
| for (i = 0; i < task; i++) { |
| sprintf((char *)&name[i], "libmars Task %d", i); |
| ret = mars_task_create(mars_ctx, &task_id[i], name[i], |
| mpu_task_libmars_prog.elf_image, 0); |
| if (ret) |
| return -1; |
| |
| task_args.type.u32[0] = loop; |
| ret = mars_task_schedule(&task_id[i], &task_args, 0); |
| if (ret) |
| return -1; |
| } |
| |
| for (i = 0; i < task; i++) { |
| ret = mars_task_wait(&task_id[i], NULL); |
| if (ret) |
| return -1; |
| |
| ret = mars_task_destroy(&task_id[i]); |
| if (ret) |
| return -1; |
| } |
| |
| ret = mars_context_destroy(mars_ctx); |
| if (ret) |
| return -1; |
| |
| return 0; |
| } |
| |
| static void compare(int task, int loop) |
| { |
| int ret_libspe2; |
| unsigned long long timer_libspe2; |
| TIMER_START(timer_libspe2); |
| ret_libspe2 = libspe2(task, loop); |
| TIMER_STOP(timer_libspe2); |
| |
| int ret_libmars; |
| unsigned long long timer_libmars; |
| TIMER_START(timer_libmars); |
| ret_libmars = libmars(task, loop); |
| TIMER_STOP(timer_libmars); |
| |
| printf("| %9d | %9d |", task, loop); |
| |
| if (ret_libspe2) |
| printf(" ERROR "); |
| else |
| printf(" %8.0f us ", (float)timer_libspe2); |
| |
| printf("|"); |
| |
| if (ret_libmars) |
| printf(" ERROR "); |
| else |
| printf(" %8.0f us ", (float)timer_libmars); |
| |
| printf("|\n"); |
| } |
| |
| int main(void) |
| { |
| int task, loop; |
| |
| printf(INFO); |
| |
| printf("-----------------------------------------------------\n"); |
| printf("| tasks | loop | libspe2 | libmars |\n"); |
| printf("-----------------------------------------------------\n"); |
| |
| for (task = 1; task <= 100; task *= 10) { |
| for (loop = 1; loop <= 1000000; loop *= 10) { |
| compare(task, loop); |
| } |
| } |
| |
| for (task = 200; task <= 400; task *= 2) { |
| for (loop = 1; loop <= 1000000; loop *= 10) { |
| compare(task, loop); |
| } |
| } |
| |
| printf("-----------------------------------------------------\n"); |
| |
| return 0; |
| } |