[Cbe-oss-dev] [PATCH 1/5] libspe2: Add separate tests for each SPE event

Kazunori Asayama asayama at sm.sony.co.jp
Thu Apr 24 22:37:48 EST 2008


This patch adds separate tests for each SPE event to the libspe2 test
suite.

Signed-off-by: Kazunori Asayama <asayama at sm.sony.co.jp>

---
 tests/libspe2.event/Makefile               |   18 +
 tests/libspe2.event/spu_event_stop.c       |   46 +++++
 tests/libspe2.event/spu_event_wbox.c       |   49 +++++
 tests/libspe2.event/test_event.c           |   18 -
 tests/libspe2.event/test_event_ibox.c      |  204 ++++++++++++++++++++++
 tests/libspe2.event/test_event_stop.c      |  239 ++++++++++++++++++++++++++
 tests/libspe2.event/test_event_tag_group.c |  263 +++++++++++++++++++++++++++++
 tests/libspe2.event/test_event_wbox.c      |  209 +++++++++++++++++++++++
 tests/make.rules                           |    2 
 9 files changed, 1029 insertions(+), 19 deletions(-)

Index: b/tests/make.rules
===================================================================
--- a/tests/make.rules	2008-04-21 12:19:42.000000000 +0900
+++ b/tests/make.rules	2008-04-21 12:19:47.000000000 +0900
@@ -56,7 +56,7 @@ $(checks): check-%: %
 	fi
 
 clean:
-	-$(RM) *.elf *.o *.tmp
+	-$(RM) *.elf *.o *.tmp `find . -maxdepth 1 -type l`
 
 distclean: clean
 	-$(RM) *~
Index: b/tests/libspe2.event/Makefile
===================================================================
--- a/tests/libspe2.event/Makefile	2008-04-21 12:19:42.000000000 +0900
+++ b/tests/libspe2.event/Makefile	2008-04-21 12:19:47.000000000 +0900
@@ -24,10 +24,28 @@ TEST_TOP = ..
 include $(TEST_TOP)/make.defines
 
 main_progs = \
+	test_event_stop.elf \
+	test_event_ibox.elf \
+	test_event_tag_group.elf \
+	test_event_wbox.elf \
 	test_event.elf \
 	test_event_error.elf
 
 
 include $(TEST_TOP)/make.rules
 
+test_event_stop.elf: spu_event_stop.embed.o
+
+test_event_ibox.elf: spu_ibox.embed.o
+
+test_event_tag_group.elf: spu_proxy_dma.embed.o
+
+test_event_wbox.elf: spu_event_wbox.embed.o
+
 test_event.elf: spu_event.embed.o
+
+spu_ibox.c: ../libspe2.mfc/spu_ibox.c
+	ln -sf $< $@
+
+spu_proxy_dma.c: ../libspe2.mfc/spu_proxy_dma.c
+	ln -sf $< $@
Index: b/tests/libspe2.event/test_event_stop.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ b/tests/libspe2.event/test_event_stop.c	2008-04-21 12:19:47.000000000 +0900
@@ -0,0 +1,239 @@
+/*
+ *  libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS
+ *
+ *  Copyright (C) 2008 Sony Computer Entertainment Inc.
+ *  Copyright 2008 Sony Corp.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* This test checks if the SPE_EVENT_SPE_STOPPED event support works
+   correctly. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+
+#include "ppu_libspe2_test.h"
+
+#define COUNT 3000
+
+extern spe_program_handle_t spu_event_stop;
+
+typedef struct spe_thread_params
+{
+  spe_context_ptr_t spe;
+  int index;
+  pthread_t tid;
+  unsigned int num_stop;
+} spe_thread_params_t;
+
+static const spe_stop_info_t expected_stop_info = {
+  .stop_reason = SPE_STOP_AND_SIGNAL,
+  .result.spe_signal_code = STOP_DATA,
+};
+
+static void *spe_thread_proc(void *arg)
+{
+  spe_thread_params_t *params = (spe_thread_params_t *)arg;
+  spe_context_ptr_t spe = params->spe;
+  unsigned int entry = SPE_DEFAULT_ENTRY;
+  spe_stop_info_t stop_info;
+  int ret;
+  unsigned int i;
+
+  if (spe_program_load(spe, &spu_event_stop)) {
+    eprintf("spe[%d]: spe_program_load: %s\n", params->index, strerror(errno));
+    fatal();
+  }
+
+  global_sync(NUM_SPES);
+
+  for (i = 0; ; i++) { /* run until the SPE exits */
+    ret = spe_context_run(spe, &entry, 0,
+			  (void*)STOP_DATA, (void*)COUNT, &stop_info);
+    if (ret == 0) { /* exit */
+      if (i != COUNT) {
+	eprintf("spe[%d]: spe_context_run: Unexpected exit\n", params->index);
+	fatal();
+      }
+      if (check_exit_code(&stop_info, 0)) {
+	fatal();
+      }
+      break;
+    }
+    else if (ret > 0) { /* user stop code */
+      if (check_stop_info(&stop_info, &expected_stop_info)) {
+	fatal();
+      }
+    }
+    else { /* error */
+      eprintf("spe[%d]: spe_context_run: %s\n", params->index, strerror(errno));
+      fatal();
+    }
+  }
+
+  return NULL;
+}
+
+static int test(int argc, char **argv)
+{
+  int ret;
+  spe_thread_params_t params[NUM_SPES];
+  spe_event_handler_ptr_t evhandler;
+#define MAX_EVENT NUM_SPES
+  spe_event_unit_t event[MAX_EVENT];
+  int i;
+  int exit_count;
+  spe_stop_info_t stop_info;
+  int num_events;
+
+  /* initialize SPE contexts */
+  for (i = 0; i < NUM_SPES; i++) {
+    params[i].index = i;
+    params[i].num_stop = 0;
+    params[i].spe = spe_context_create(SPE_EVENTS_ENABLE, NULL);
+    if (!params[i].spe) {
+      eprintf("spe_context_create: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+
+  /* register events */
+  evhandler = spe_event_handler_create();
+  if (!evhandler) {
+    eprintf("spe_event_handler_create: %s\n", strerror(errno));
+    fatal();
+  }
+
+  for (i = 0; i < NUM_SPES; i++) {
+    event[0].events = SPE_EVENT_SPE_STOPPED;
+    event[0].spe = params[i].spe;
+    event[0].data.u32 = i;
+    ret = spe_event_handler_register(evhandler, event);
+    if (ret == -1) {
+      eprintf("spe_event_handler_register: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+
+  /* should be empty */
+  ret = spe_stop_info_read(params[0].spe, &stop_info);
+  if (ret == 0) {
+    eprintf("spe_stop_info_read: unexpected data.\n");
+    fatal();
+  }
+  else if (ret == -1) {
+    if (errno != EAGAIN) {
+      eprintf("spe_stop_info_read: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+  else {
+    eprintf("spe_stop_info_read: unexpected return code (%d).\n", ret);
+    fatal();
+  }
+
+  /* run SPE contexts */
+  for (i = 0; i < NUM_SPES; i++) {
+    ret = pthread_create(&params[i].tid, NULL, spe_thread_proc, params + i);
+    if (ret) {
+      eprintf("pthread_create: %s\n", strerror(ret));
+      fatal();
+    }
+  }
+
+  /* event loop */
+  exit_count = 0;
+  while (exit_count < NUM_SPES) {
+    /* wait for the next event */
+    ret = num_events = spe_event_wait(evhandler, event, MAX_EVENT, -1);
+    if (ret == -1) {
+      eprintf("spe_event_wait: %s\n", strerror(errno));
+      fatal();
+    }
+    else if (ret == 0) {
+      eprintf("spe_event_wait: Unexpected timeout.\n");
+      fatal();
+    }
+
+    /* process events */
+    for (i = 0; i < num_events; i++) {
+      spe_thread_params_t *cur_params;
+      tprintf("event %u/%u: spe[%u]\n", i, num_events, (unsigned int)event[i].data.u32);
+      cur_params = params + event[i].data.u32;
+      if (event[i].events & SPE_EVENT_SPE_STOPPED) {
+	ret = spe_stop_info_read(event[i].spe, &stop_info);
+	if (ret == -1) {
+	  eprintf("spe[%u]: spe_stop_info_read: %s\n",
+		  event[i].data.u32, strerror(errno));
+	  fatal();
+	}
+	else if (stop_info.stop_reason == SPE_EXIT) {
+	  if (check_exit_code(&stop_info, 0)) {
+	    fatal();
+	  }
+	  exit_count++;
+	}
+	else { /* user stop code */
+	  if (check_stop_info(&stop_info, &expected_stop_info)) {
+	    fatal();
+	  }
+	  cur_params->num_stop++;
+	}
+      }
+      else {
+	eprintf("event %u/%u: spe[%u]: Unexpected event (0x%08x)\n",
+		i, num_events, (unsigned int)event->data.u32, event->events);
+	fatal();
+      }
+    }
+  }
+
+  /* cleanup and check result */
+  for (i = 0; i < NUM_SPES; i++) {
+    pthread_join(params[i].tid, NULL);
+
+    if (params[i].num_stop > COUNT) {
+      eprintf("spe[%u]: too many events (%u/%u).\n", i, params[i].num_stop, COUNT);
+      failed();
+    }
+    else if (params[i].num_stop < COUNT) {
+      eprintf("spe[%u]: events were lost (%u/%u).\n", i, params[i].num_stop, COUNT);
+      failed();
+    }
+
+    ret = spe_context_destroy(params[i].spe);
+    if (ret) {
+      eprintf("spe_context_destroy: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+
+  ret = spe_event_handler_destroy(evhandler);
+  if (ret) {
+    fatal();
+  }
+
+  return 0;
+}
+
+int main(int argc, char **argv)
+{
+  return ppu_main(argc, argv, test);
+}
Index: b/tests/libspe2.event/test_event_ibox.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ b/tests/libspe2.event/test_event_ibox.c	2008-04-21 12:19:47.000000000 +0900
@@ -0,0 +1,204 @@
+/*
+ *  libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS
+ *
+ *  Copyright (C) 2008 Sony Computer Entertainment Inc.
+ *  Copyright 2008 Sony Corp.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* This test checks if the SPE_EVENT_OUT_INTR_MBOX event support works
+   correctly. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+
+#include "ppu_libspe2_test.h"
+
+#define COUNT 10000
+
+extern spe_program_handle_t spu_ibox;
+
+typedef struct spe_thread_params
+{
+  spe_context_ptr_t spe;
+  int index;
+  pthread_t tid;
+  unsigned int num_ibox;
+} spe_thread_params_t;
+
+static void *spe_thread_proc(void *arg)
+{
+  spe_thread_params_t *params = (spe_thread_params_t *)arg;
+  spe_context_ptr_t spe = params->spe;
+  unsigned int entry = SPE_DEFAULT_ENTRY;
+  spe_stop_info_t stop_info;
+  int ret;
+
+  if (spe_program_load(spe, &spu_ibox)) {
+    eprintf("spe[%d]: spe_program_load: %s\n", params->index, strerror(errno));
+    fatal();
+  }
+
+  global_sync(NUM_SPES);
+
+  ret = spe_context_run(spe, &entry, 0, (void*)COUNT, 0, &stop_info);
+  if (ret == 0) {
+    if (check_exit_code(&stop_info, 0)) {
+      fatal();
+    }
+  }
+  else if (ret > 0) {
+    eprintf("spe[%d]: spe_context_run: Unexpected stop and signal\n", params->index);
+  }
+  else {
+    eprintf("spe[%d]: spe_context_run: %s\n", params->index, strerror(errno));
+    fatal();
+  }
+
+  return NULL;
+}
+
+static int test(int argc, char **argv)
+{
+  int ret;
+  spe_thread_params_t params[NUM_SPES];
+  spe_event_handler_ptr_t evhandler;
+#define MAX_EVENT NUM_SPES
+  spe_event_unit_t event[MAX_EVENT];
+  int i;
+  int exit_count;
+  int num_events;
+
+  /* initialize SPE contexts */
+  for (i = 0; i < NUM_SPES; i++) {
+    params[i].index = i;
+    params[i].num_ibox = 0;
+    params[i].spe = spe_context_create(SPE_EVENTS_ENABLE, NULL);
+    if (!params[i].spe) {
+      eprintf("spe_context_create: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+
+  /* register events */
+  evhandler = spe_event_handler_create();
+  if (!evhandler) {
+    eprintf("spe_event_handler_create: %s\n", strerror(errno));
+    fatal();
+  }
+
+  for (i = 0; i < NUM_SPES; i++) {
+    event[0].events = SPE_EVENT_OUT_INTR_MBOX;
+    event[0].spe = params[i].spe;
+    event[0].data.u32 = i;
+    ret = spe_event_handler_register(evhandler, event);
+    if (ret == -1) {
+      eprintf("spe_event_handler_register: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+
+  /* run SPE contexts */
+  for (i = 0; i < NUM_SPES; i++) {
+    ret = pthread_create(&params[i].tid, NULL, spe_thread_proc, params + i);
+    if (ret) {
+      eprintf("pthread_create: %s\n", strerror(ret));
+      fatal();
+    }
+  }
+
+  /* event loop */
+  exit_count = 0;
+  while (exit_count < NUM_SPES) {
+    /* wait for the next event */
+    ret = num_events = spe_event_wait(evhandler, event, MAX_EVENT, -1);
+    if (ret == -1) {
+      eprintf("spe_event_wait: %s\n", strerror(errno));
+      fatal();
+    }
+    else if (ret == 0) {
+      eprintf("spe_event_wait: Unexpected timeout.\n");
+      fatal();
+    }
+
+    /* process events */
+    for (i = 0; i < num_events; i++) {
+      spe_thread_params_t *cur_params;
+      tprintf("event %u/%u: spe[%u]\n", i, num_events, (unsigned int)event[i].data.u32);
+      cur_params = params + event[i].data.u32;
+      if (event[i].events & SPE_EVENT_OUT_INTR_MBOX) {
+	unsigned int data = -1;
+	ret = spe_out_intr_mbox_read(event[i].spe, &data, 1, SPE_MBOX_ANY_NONBLOCKING);
+	if (ret == -1) {
+	  eprintf("spe[%u]: spe_out_intr_mbox_read: %s\n",
+		  event[i].data.u32, strerror(errno));
+	  fatal();
+	}
+	tprintf("spe[%u]: ibox: 0x%08x(%u)\n", event[i].data.u32, data, data);
+	if (cur_params->num_ibox + 1 != data) {
+	  eprintf("spe[%u]: Unexpected ibox data: %u: Expected: %u\n",
+		  event[i].data.u32, data, cur_params->num_ibox + 1);
+	  fatal();
+	}
+	cur_params->num_ibox = data;
+	if (cur_params->num_ibox == COUNT) { /* done */
+	  exit_count++;
+	}
+      }
+      else {
+	eprintf("event %u/%u: spe[%u]: Unexpected event (0x%08x)\n",
+		i, num_events, (unsigned int)event[i].data.u32, event[i].events);
+	fatal();
+      }
+    }
+  }
+
+  /* cleanup and check result */
+  for (i = 0; i < NUM_SPES; i++) {
+    pthread_join(params[i].tid, NULL);
+
+    if (params[i].num_ibox > COUNT) {
+      eprintf("spe[%u]: too many events (%u/%u)\n", i, params[i].num_ibox, COUNT);
+      failed();
+    }
+    else if (params[i].num_ibox < COUNT) {
+      eprintf("spe[%u]: events were lost (%u/%u)\n", i, params[i].num_ibox, COUNT);
+      failed();
+    }
+
+    ret = spe_context_destroy(params[i].spe);
+    if (ret) {
+      eprintf("spe_context_destroy: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+
+  ret = spe_event_handler_destroy(evhandler);
+  if (ret) {
+    fatal();
+  }
+
+  return 0;
+}
+
+int main(int argc, char **argv)
+{
+  return ppu_main(argc, argv, test);
+}
Index: b/tests/libspe2.event/spu_event_wbox.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ b/tests/libspe2.event/spu_event_wbox.c	2008-04-21 12:19:47.000000000 +0900
@@ -0,0 +1,49 @@
+/*
+ *  libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS
+ *
+ *  Copyright (C) 2008 Sony Computer Entertainment Inc.
+ *  Copyright 2008 Sony Corp.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <spu_intrinsics.h>
+#include <spu_mfcio.h>
+
+#include "spu_libspe2_test.h"
+
+#define SPIN 50000
+
+int main(unsigned long long spe,
+	 unsigned long long argp, unsigned long long envp)
+{
+  unsigned int i;
+  unsigned long long sum = 0;
+
+  for (i = 0; i < argp; i++) {
+    unsigned int n;
+    if (i % (WBOX_DEPTH * 2) == 0) {
+      spin(SPIN); /* stall wbox intentionally to test wbox events */
+    }
+    n = spu_read_in_mbox();
+    sum += n;
+  }
+
+  if (sum != argp * (argp + 1) / 2) { /* unexpected data */
+    return 1;
+  }
+
+  return 0;
+}
Index: b/tests/libspe2.event/test_event_wbox.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ b/tests/libspe2.event/test_event_wbox.c	2008-04-21 12:19:47.000000000 +0900
@@ -0,0 +1,209 @@
+/*
+ *  libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS
+ *
+ *  Copyright (C) 2008 Sony Computer Entertainment Inc.
+ *  Copyright 2008 Sony Corp.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* This test checks if the SPE_EVENT_IN_MBOX event support works
+   correctly. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+
+#include "ppu_libspe2_test.h"
+
+#define COUNT 10000
+
+extern spe_program_handle_t spu_event_wbox;
+
+typedef struct spe_thread_params
+{
+  spe_context_ptr_t spe;
+  int index;
+  pthread_t tid;
+  unsigned int num_wbox;
+} spe_thread_params_t;
+
+static void *spe_thread_proc(void *arg)
+{
+  spe_thread_params_t *params = (spe_thread_params_t *)arg;
+  spe_context_ptr_t spe = params->spe;
+  unsigned int entry = SPE_DEFAULT_ENTRY;
+  spe_stop_info_t stop_info;
+  int ret;
+
+  if (spe_program_load(spe, &spu_event_wbox)) {
+    eprintf("spe[%d]: spe_program_load: %s\n", params->index, strerror(errno));
+    fatal();
+  }
+
+  global_sync(NUM_SPES);
+
+  ret = spe_context_run(spe, &entry, 0, (void*)COUNT, 0, &stop_info);
+  if (ret == 0) {
+    if (check_exit_code(&stop_info, 0)) {
+      fatal();
+    }
+  }
+  else if (ret > 0) {
+    eprintf("spe[%d]: spe_context_run: Unexpected stop and signal\n", params->index);
+  }
+  else {
+    eprintf("spe[%d]: spe_context_run: %s\n", params->index, strerror(errno));
+    fatal();
+  }
+
+  return NULL;
+}
+
+static int test(int argc, char **argv)
+{
+  int ret;
+  spe_thread_params_t params[NUM_SPES];
+  spe_event_handler_ptr_t evhandler;
+#define MAX_EVENT NUM_SPES
+  spe_event_unit_t event[MAX_EVENT];
+  int i;
+  int exit_count;
+  int num_events;
+
+  /* initialize SPE contexts */
+  for (i = 0; i < NUM_SPES; i++) {
+    params[i].index = i;
+    params[i].num_wbox = 0;
+    params[i].spe = spe_context_create(SPE_EVENTS_ENABLE, NULL);
+    if (!params[i].spe) {
+      eprintf("spe_context_create: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+
+  /* register events */
+  evhandler = spe_event_handler_create();
+  if (!evhandler) {
+    eprintf("spe_event_handler_create: %s\n", strerror(errno));
+    fatal();
+  }
+
+  for (i = 0; i < NUM_SPES; i++) {
+    event[0].events = SPE_EVENT_IN_MBOX;
+    event[0].spe = params[i].spe;
+    event[0].data.u32 = i;
+    ret = spe_event_handler_register(evhandler, event);
+    if (ret == -1) {
+      eprintf("spe_event_handler_register: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+
+  /* run SPE contexts */
+  for (i = 0; i < NUM_SPES; i++) {
+    ret = pthread_create(&params[i].tid, NULL, spe_thread_proc, params + i);
+    if (ret) {
+      eprintf("pthread_create: %s\n", strerror(ret));
+      fatal();
+    }
+  }
+
+  /* event loop */
+  exit_count = 0;
+  while (exit_count < NUM_SPES) {
+    /* wait for the next event */
+    ret = num_events = spe_event_wait(evhandler, event, MAX_EVENT, -1);
+    if (ret == -1) {
+      eprintf("spe_event_wait: %s\n", strerror(errno));
+      fatal();
+    }
+    else if (ret == 0) {
+      eprintf("spe_event_wait: Unexpected timeout.\n");
+      fatal();
+    }
+
+    /* process events */
+    for (i = 0; i < num_events; i++) {
+      spe_thread_params_t *cur_params;
+      tprintf("event %u/%u: spe[%u]\n", i, num_events, (unsigned int)event[i].data.u32);
+      cur_params = params + event[i].data.u32;
+      if (event[i].events & SPE_EVENT_IN_MBOX) {
+	unsigned data[WBOX_DEPTH];
+	int num_wbox =
+	  cur_params->num_wbox + WBOX_DEPTH > COUNT ? COUNT - cur_params->num_wbox : WBOX_DEPTH;
+	int j;
+	for (j = 0; j < num_wbox; j++) {
+	  data[j] = cur_params->num_wbox + j + 1;
+	}
+	ret = spe_in_mbox_write(event[i].spe, data, num_wbox, SPE_MBOX_ANY_NONBLOCKING);
+	if (ret == -1) {
+	  eprintf("spe[%u]: spe_in_mbox_write: %s\n",
+		  event[i].data.u32, strerror(errno));
+	  fatal();
+	}
+	else if (ret == 0) {
+	  /* It should be possible to write data immediately, just
+	     after receiving 'SPE_EVENT_IN_MBOX' events. */
+	  eprintf("spe[%u]: spe_in_mbox_write: wbox event received, but no space\n",
+		  event[i].data.u32);
+	  fatal();
+	}
+	cur_params->num_wbox += ret;
+	if (cur_params->num_wbox >= COUNT) { /* done */
+	  exit_count++;
+	  event[i].spe = cur_params->spe;
+	  event[i].events = SPE_EVENT_IN_MBOX;
+	  ret = spe_event_handler_deregister(evhandler, event + i);
+	  if (ret == -1) {
+	    eprintf("spe_event_handler_deregister: %s\n", strerror(errno));
+	    fatal();
+	  }
+	}
+      }
+      else {
+	eprintf("event %u/%u: spe[%u]: Unexpected event (0x%08x)\n",
+		i, num_events, (unsigned int)event[i].data.u32, event[i].events);
+	fatal();
+      }
+    }
+  }
+
+  /* cleanup */
+  for (i = 0; i < NUM_SPES; i++) {
+    pthread_join(params[i].tid, NULL);
+
+    ret = spe_context_destroy(params[i].spe);
+    if (ret) {
+      eprintf("spe_context_destroy: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+
+  ret = spe_event_handler_destroy(evhandler);
+  if (ret) {
+    fatal();
+  }
+
+  return 0;
+}
+
+int main(int argc, char **argv)
+{
+  return ppu_main(argc, argv, test);
+}
Index: b/tests/libspe2.event/test_event_tag_group.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ b/tests/libspe2.event/test_event_tag_group.c	2008-04-21 12:19:47.000000000 +0900
@@ -0,0 +1,263 @@
+/*
+ *  libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS
+ *
+ *  Copyright (C) 2008 Sony Computer Entertainment Inc.
+ *  Copyright 2008 Sony Corp.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* This test checks if the SPE_EVENT_TAG_GROUP event support works
+   correctly. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <errno.h>
+#include <string.h>
+
+#include "ppu_libspe2_test.h"
+
+#define COUNT 10000
+#define DMA_SIZE MAX_DMA_SIZE
+
+extern spe_program_handle_t spu_proxy_dma;
+
+static unsigned char data_buf[DMA_SIZE] __attribute__((aligned(16)));
+
+typedef struct spe_thread_params
+{
+  spe_context_ptr_t spe;
+  int index;
+  pthread_t tid;
+  unsigned int num_dma;
+  unsigned int dma_ls;
+  int dma_tag;
+} spe_thread_params_t;
+
+static void *spe_thread_proc(void *arg)
+{
+  spe_thread_params_t *params = (spe_thread_params_t *)arg;
+  spe_context_ptr_t spe = params->spe;
+  unsigned int entry = SPE_DEFAULT_ENTRY;
+  spe_stop_info_t stop_info;
+  int ret;
+
+  if (spe_program_load(spe, &spu_proxy_dma)) {
+    eprintf("spe[%d]: spe_program_load: %s\n", params->index, strerror(errno));
+    fatal();
+  }
+
+  ret = spe_context_run(spe, &entry, 0, (void*)COUNT, 0, &stop_info);
+  if (ret == 0) {
+    if (check_exit_code(&stop_info, 0)) {
+      fatal();
+    }
+  }
+  else if (ret > 0) {
+    eprintf("spe[%d]: spe_context_run: Unexpected stop and signal\n", params->index);
+  }
+  else {
+    eprintf("spe[%d]: spe_context_run: %s\n", params->index, strerror(errno));
+    fatal();
+  }
+
+  return NULL;
+}
+
+static int test(int argc, char **argv)
+{
+  int ret;
+  spe_thread_params_t params[NUM_SPES];
+  spe_event_handler_ptr_t evhandler;
+#define MAX_EVENT NUM_SPES
+  spe_event_unit_t event[MAX_EVENT];
+  int i;
+  int exit_count;
+  int num_events;
+
+  /* initialize test data */
+  generate_data(data_buf, 0, DMA_SIZE);
+
+  /* initialize SPE contexts */
+  for (i = 0; i < NUM_SPES; i++) {
+    params[i].index = i;
+    params[i].num_dma = 0;
+    params[i].dma_tag = 3;
+    params[i].spe = spe_context_create(SPE_EVENTS_ENABLE, NULL);
+    if (!params[i].spe) {
+      eprintf("spe_context_create: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+
+  /* register events */
+  evhandler = spe_event_handler_create();
+  if (!evhandler) {
+    eprintf("spe_event_handler_create: %s\n", strerror(errno));
+    fatal();
+  }
+
+  for (i = 0; i < NUM_SPES; i++) {
+    event[0].events = SPE_EVENT_TAG_GROUP;
+    event[0].spe = params[i].spe;
+    event[0].data.u32 = i;
+    ret = spe_event_handler_register(evhandler, event);
+    if (ret == -1) {
+      eprintf("spe_event_handler_register: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+
+
+  /* run SPE contexts */
+  for (i = 0; i < NUM_SPES; i++) {
+    ret = pthread_create(&params[i].tid, NULL, spe_thread_proc, params + i);
+    if (ret) {
+      eprintf("pthread_create: %s\n", strerror(ret));
+      fatal();
+    }
+    /* get DMA buffer area */
+    ret = spe_out_intr_mbox_read(params[i].spe, &params[i].dma_ls, 1, SPE_MBOX_ANY_BLOCKING);
+    if (ret != 1) {
+      eprintf("dma_ls: Not available.\n");
+      fatal();
+    }
+    tprintf("spe[%u]: DMA buffer: 0x%08x: Tag: %d\n",
+	    i, params[i].dma_ls, params[i].dma_tag);
+  }
+
+  /* issue initial DMAs */
+  for (i = 0; i < NUM_SPES; i++) {
+    ret = spe_mfcio_get(params[i].spe, params[i].dma_ls,
+			data_buf, DMA_SIZE, params[i].dma_tag, 0, 0);
+    if (ret) {
+      eprintf("spe[%d]: spe_mfcio_get: %s\n", params->index, strerror(errno));
+      return 1;
+    }
+  }
+
+  /* event loop */
+  exit_count = 0;
+  while (exit_count < NUM_SPES) {
+    /* wait for the next event */
+    ret = num_events = spe_event_wait(evhandler, event, MAX_EVENT, -1);
+    if (ret == -1) {
+      eprintf("spe_event_wait: %s\n", strerror(errno));
+      fatal();
+    }
+    else if (ret == 0) {
+      eprintf("spe_event_wait: Unexpected timeout.\n");
+      continue;
+      fatal();
+    }
+
+    /* process events */
+    for (i = 0; i < num_events; i++) {
+      spe_thread_params_t *cur_params;
+      tprintf("event %u/%u: spe[%u]\n", i, num_events, (unsigned int)event[i].data.u32);
+      cur_params = params + event[i].data.u32;
+      if (event[i].events & SPE_EVENT_TAG_GROUP) {
+	unsigned int status;
+	ret = spe_mfcio_tag_status_read(event[i].spe, 1 << cur_params->dma_tag,
+					SPE_TAG_IMMEDIATE, &status);
+	if (ret) {
+	  eprintf("spe[%u]: spe_mfcio_tag_status_read: %s\n",
+		  event[i].data.u32, strerror(errno));
+	  fatal();
+	}
+	if (status != (1 << cur_params->dma_tag)) {
+	  eprintf("spe[%u]: spe_mfcio_tag_status_read: Unexpected status 0x%08x: Expected: 0x%08x\n",
+		  event[i].data.u32, status, (1 << cur_params->dma_tag));
+	  fatal();
+	}
+	cur_params->num_dma++;
+	if (cur_params->num_dma == COUNT) { /* done */
+	  exit_count++;
+#if 1
+	  /* FIXME: This routine is workaround to avoid kernel's bug,
+	   * so it should be removed in the future. Currently, if poll
+	   * system call is called on "mfc" (spufs_mfc_poll) when
+	   * there is no outstanding DMA, the kernel hangs because
+	   * spufs_mfc_poll repeatedly issues tag group query with
+	   * 'all' query type for empty tag group mask. Therefore, we
+	   * unregister tag group event on completed SPEs here.
+	   */
+	  event[i].spe = cur_params->spe;
+	  event[i].events = SPE_EVENT_TAG_GROUP;
+	  ret = spe_event_handler_deregister(evhandler, event + i);
+	  if (ret == -1) {
+	    eprintf("spe_event_handler_deregister: %s\n", strerror(errno));
+	    fatal();
+	  }
+#endif
+	}
+	else { /* issue next DMA */
+	  ret = spe_mfcio_get(cur_params->spe, cur_params->dma_ls,
+			      data_buf, DMA_SIZE, cur_params->dma_tag, 0, 0);
+	  if (ret) {
+	    eprintf("spe[%d]: spe_mfcio_get: %s\n", cur_params->index, strerror(errno));
+	    fatal();
+	  }
+	}
+      }
+      else {
+	eprintf("event %u/%u: spe[%u]: Unexpected event (0x%08x)\n",
+		i, num_events, (unsigned int)event[i].data.u32, event[i].events);
+	fatal();
+      }
+    }
+  }
+
+  /* cleanup and check result */
+  for (i = 0; i < NUM_SPES; i++) {
+    /* notify test has finished */
+    ret = spe_in_mbox_write(params[i].spe, (unsigned int *)data_buf, 1, SPE_MBOX_ALL_BLOCKING);
+    if (ret == -1) {
+      eprintf("spe[%u]: spe_in_mbox_write: %s\n", i, strerror(errno));
+      fatal();
+    }
+
+    pthread_join(params[i].tid, NULL);
+
+    if (params[i].num_dma > COUNT) {
+      eprintf("spe[%u]: too many events (%u/%u)\n", i, params[i].num_dma, COUNT);
+      failed();
+    }
+    else if (params[i].num_dma < COUNT) {
+      eprintf("spe[%u]: events were lost (%u/%u)\n", i, params[i].num_dma, COUNT);
+      failed();
+    }
+
+    ret = spe_context_destroy(params[i].spe);
+    if (ret) {
+      eprintf("spe_context_destroy: %s\n", strerror(errno));
+      fatal();
+    }
+  }
+
+  ret = spe_event_handler_destroy(evhandler);
+  if (ret) {
+    fatal();
+  }
+
+  return 0;
+}
+
+int main(int argc, char **argv)
+{
+  return ppu_main(argc, argv, test);
+}
Index: b/tests/libspe2.event/spu_event_stop.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ b/tests/libspe2.event/spu_event_stop.c	2008-04-21 12:19:47.000000000 +0900
@@ -0,0 +1,46 @@
+/*
+ *  libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS
+ *
+ *  Copyright (C) 2008 Sony Computer Entertainment Inc.
+ *  Copyright 2008 Sony Corp.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* This program executes the stop instruction for the specified stop code.
+ */
+
+#include "spu_libspe2_test.h"
+
+int main(unsigned long long spe,
+	 unsigned long long argp /* stop code */,
+	 unsigned long long envp /* count */)
+{
+  unsigned int i;
+
+  for (i = 0; i < envp; i++) {
+    __vector unsigned int prog = {
+      (unsigned int)argp, /* stop instruction */
+      0x4020007f,     /* nop */
+      0x4020007f,     /* nop */
+      0x35000000      /* bi $0 */
+    };
+
+    asm("sync");
+    ((void (*)())&prog)();
+  }
+
+  return 0;
+}
Index: b/tests/libspe2.event/test_event.c
===================================================================
--- a/tests/libspe2.event/test_event.c	2008-04-21 11:38:30.000000000 +0900
+++ b/tests/libspe2.event/test_event.c	2008-04-21 12:30:51.000000000 +0900
@@ -224,7 +224,6 @@ static int test(int argc, char **argv)
   spe_event_unit_t event[MAX_EVENT];
   int i;
   int exit_count;
-  spe_stop_info_t stop_info;
   int num_events;
 
   /* initialize SPE contexts */
@@ -268,23 +267,6 @@ static int test(int argc, char **argv)
     }
   }
 
-  /* should be empty */
-  ret = spe_stop_info_read(params[0].spe, &stop_info);
-  if (ret == 0) {
-    eprintf("spe_stop_info_read: unexpected data.\n");
-    fatal();
-  }
-  else if (ret == -1) {
-    if (errno != EAGAIN) {
-      eprintf("spe_stop_info_read: %s\n", strerror(errno));
-      fatal();
-    }
-  }
-  else {
-    eprintf("spe_stop_info_read: unexpected return code (%d).\n", ret);
-    fatal();
-  }
-
   /* run SPE contexts */
   for (i = 0; i < NUM_SPES; i++) {
     ret = pthread_create(&params[i].tid, NULL, spe_thread_proc, params + i);




More information about the cbe-oss-dev mailing list