[Cbe-oss-dev] [PATCH 13/22]MARS/base: No busy wait

Yuji Mano yuji.mano at am.sony.com
Wed Jan 21 11:29:15 EST 2009


From: Kazunori Asayama <asayama at sm.sony.co.jp>

Remove busy loops from host side code (base)

This patch removes busy loops from host side code by using futex.

Signed-off-by: Kazunori Asayama <asayama at sm.sony.co.jp>
Signed-off-by: Yuji Mano <yuji.mano at am.sony.com>
---
 base/include/host/mars/base.h             |    2 
 base/include/mpu/mars/module.h            |   11 +++
 base/src/common/kernel_internal_types.h   |    3 +
 base/src/common/workload_internal_types.h |    2 
 base/src/host/lib/cond_cell.c             |   60 ++++++++++++++++++++
 base/src/host/lib/mpu_cell.c              |   86 +++++++++++++++++++++++++++++-
 base/src/mpu/kernel/kernel.c              |   27 +++++++++
 base/src/mpu/lib/module.c                 |    5 +
 scripts/acinclude.m4                      |   23 ++++++++
 9 files changed, 215 insertions(+), 4 deletions(-)

--- a/base/include/host/mars/base.h
+++ b/base/include/host/mars/base.h
@@ -232,6 +232,8 @@ int mars_ea_cond_wait(uint64_t watch_poi
 		      int (*test_cond)(uint32_t , void *),
 		      void *test_cond_param);
 
+int mars_ea_cond_signal(uint64_t watch_point_ea, int broadcast);
+
 #ifdef MARS_ENABLE_DISCRETE_SHARED_MEMORY
 #  define mars_ea_work_area_get(ea, boundary, size) mars_alloca_align(boundary, size)
 #else /* !MARS_ENABLE_DISCRETE_SHARED_MEMORY */
--- a/base/include/mpu/mars/module.h
+++ b/base/include/mpu/mars/module.h
@@ -289,6 +289,17 @@ void mars_module_workload_yield(void);
  */
 void mars_module_workload_finish(void);
 
+/**
+ * \ingroup group_mars_workload_module
+ * \brief <b>[MPU]</b> Notify host a particular 32-bit area is modified.
+ *
+ * \param[in] watch_point_ea	- ea of modified area
+ *
+ * \return
+ *	MARS_SUCCESS		- signal sent to host
+ */
+int mars_module_host_signal_send(uint64_t watch_point_ea);
+
 #if defined(__cplusplus)
 }
 #endif
--- a/base/src/common/kernel_internal_types.h
+++ b/base/src/common/kernel_internal_types.h
@@ -70,6 +70,9 @@ struct mars_kernel_syscalls {
 				struct mars_workload_context **workload);
 	int	(*workload_schedule_end)(uint16_t id);
 	int	(*workload_schedule_cancel)(uint16_t id);
+
+	int	(*host_signal_send)(uint64_t watch_point_ea);
+
 	void	(*exit)(uint8_t state);
 };
 
--- a/base/src/common/workload_internal_types.h
+++ b/base/src/common/workload_internal_types.h
@@ -104,6 +104,8 @@
 	(*bits) = ((*(bits) & ~MARS_BITS_MASK_##name) | \
 		((uint64_t)(val) << MARS_BITS_SHIFT_##name))
 
+#define MARS_HOST_SIGNAL_EXIT			0
+
 /* 128 byte workload queue header structure */
 struct mars_workload_queue_header {
 	uint64_t queue_ea;
--- a/base/src/host/lib/cond_cell.c
+++ b/base/src/host/lib/cond_cell.c
@@ -36,20 +36,76 @@
  */
 
 #include <sched.h>
+#include <errno.h>
+#include <limits.h>
 
 #include "config.h"
 
 #include "mars/base.h"
+#include "mars/error.h"
+
+#ifdef ENABLE_COND_WAIT_FUTEX
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <linux/futex.h>
+
+static int futex_wait(void *ptr, int val)
+{
+	int ret;
+
+	ret = syscall(__NR_futex, ptr, FUTEX_WAIT, val, NULL, NULL, 0);
+	if (ret && errno != EWOULDBLOCK)
+		return MARS_ERROR_INTERNAL;
+
+	return MARS_SUCCESS;
+}
+
+static int futex_wake(void *ptr, int val)
+{
+	int ret;
+
+	ret = syscall(__NR_futex, ptr, FUTEX_WAKE, val, NULL, NULL, 0);
+	if (ret < 0)
+		return MARS_ERROR_INTERNAL;
+
+	return MARS_SUCCESS;
+}
+
+#endif
 
 int mars_ea_cond_wait(uint64_t watch_point_ea,
 		      int (*test_cond)(uint32_t , void *),
 		      void *test_cond_param)
 {
+	int i = 0;
 	int ret;
 
-	while ((ret = (*test_cond)(mars_ea_get_uint32(watch_point_ea),
-				   test_cond_param)) < 0)
+	while (1) {
+		uint32_t val = mars_ea_get_uint32(watch_point_ea);
+
+		ret = (*test_cond)(val, test_cond_param);
+		if (ret >= 0)
+			break;
+
+#ifdef ENABLE_COND_WAIT_FUTEX
+		ret = futex_wait(mars_ea_to_ptr(watch_point_ea), val);
+		if (ret != MARS_SUCCESS)
+			break;
+#else
 		sched_yield();
+#endif
+	}
 
 	return ret;
 }
+
+int mars_ea_cond_signal(uint64_t watch_point_ea, int broadcast)
+{
+#ifdef ENABLE_COND_WAIT_FUTEX
+	futex_wake(mars_ea_to_ptr(watch_point_ea),
+		   broadcast ? INT_MAX : 1);
+#endif
+
+	return MARS_SUCCESS;
+}
--- a/base/src/host/lib/mpu_cell.c
+++ b/base/src/host/lib/mpu_cell.c
@@ -40,10 +40,12 @@
 
 #include "config.h"
 
+#include "mars/base.h"
 #include "mars/context.h"
 #include "mars/error.h"
 
 #include "context_internal.h"
+#include "workload_internal_types.h"
 #include "numa_internal.h"
 
 #ifdef MARS_ENABLE_NUMA
@@ -100,13 +102,87 @@ int mars_mpu_max(int *num)
 	return MARS_SUCCESS;
 }
 
+#ifdef ENABLE_COND_WAIT_FUTEX
+
+static void *mpu_handler_thread(void *arg)
+{
+	int ret;
+	spe_context_ptr_t spe = (spe_context_ptr_t)arg;
+
+	while (1) {
+  		unsigned int ea_h, ea_l;
+		uint64_t ea;
+
+		ret = spe_out_intr_mbox_read(spe, &ea_l, 1,
+					     SPE_MBOX_ANY_BLOCKING);
+		if (ret < 1)
+			goto error;
+
+		ret = spe_out_mbox_read(spe, &ea_h, 1);
+		if (ret != 1)
+			goto error;
+
+		ea = ((uint64_t)ea_h << 32) | ea_l;
+		if (ea == MARS_HOST_SIGNAL_EXIT)
+			break;
+
+		mars_ea_cond_signal(ea, 1);
+	}
+
+	return (void *)(uintptr_t)MARS_SUCCESS;
+
+error:
+	return (void *)(uintptr_t)MARS_ERROR_INTERNAL;
+}
+
+static int handler_thread_create(pthread_t *thread, spe_context_ptr_t spe)
+{
+	int ret;
+
+	ret = pthread_create(thread, NULL, mpu_handler_thread, spe);
+	if (ret)
+		return MARS_ERROR_INTERNAL;
+
+	return MARS_SUCCESS;
+}
+
+static int handler_thread_join(pthread_t thread)
+{
+	int ret;
+
+	ret = pthread_join(thread, NULL);
+	if (ret)
+		return MARS_ERROR_INTERNAL;
+
+	return MARS_SUCCESS;
+}
+
+#else /* !ENABLE_COND_WAIT_FUTEX */
+
+static int handler_thread_create(pthread_t *thread, spe_context_ptr_t spe)
+{
+	(void)thread;
+
+	return MARS_SUCCESS;
+}
+
+static int handler_thread_join(pthread_t thread)
+{
+	(void)thread;
+
+	return MARS_SUCCESS;
+}
+
+#endif /* !ENABLE_COND_WAIT_FUTEX */
+
 static void *mpu_context_thread(void *arg)
 {
 	int ret;
 	unsigned int entry = SPE_DEFAULT_ENTRY;
 	struct mars_kernel_params *params = (struct mars_kernel_params *)arg;
-	struct spe_context *spe;
+	spe_context_ptr_t spe;
 	spe_program_handle_t prog;
+	pthread_t handler_thread;
 
 	spe = spe_context_create(0, NULL);
 	if (!spe)
@@ -121,12 +197,20 @@ static void *mpu_context_thread(void *ar
 		return (void *)MARS_ERROR_INTERNAL;
 	}
 
+	ret = handler_thread_create(&handler_thread, spe);
+	if (ret) {
+		spe_context_destroy(spe);
+		return (void *)ret;
+	}
+
 	ret = spe_context_run(spe, &entry, 0, params, NULL, NULL);
 	if (ret) {
 		spe_context_destroy(spe);
 		return (void *)MARS_ERROR_INTERNAL;
 	}
 
+	handler_thread_join(handler_thread);
+
 	ret = spe_context_destroy(spe);
 	if (ret)
 		return (void *)MARS_ERROR_INTERNAL;
--- a/base/src/mpu/kernel/kernel.c
+++ b/base/src/mpu/kernel/kernel.c
@@ -402,6 +402,16 @@ static int module_workload_schedule_canc
 			    NULL);
 }
 
+static int module_host_signal_send(uint64_t watch_point_ea)
+{
+#ifdef ENABLE_COND_WAIT_FUTEX
+	spu_write_out_mbox((uint32_t)(watch_point_ea >> 32));
+	spu_write_out_intr_mbox((uint32_t)(watch_point_ea & 0xffffffff));
+#endif
+
+	return MARS_SUCCESS;
+}
+
 static void module_exit(uint8_t state)
 {
 	workload_state = state;
@@ -412,7 +422,6 @@ static void module_exit(uint8_t state)
 		"br	_module_exit;"
 	);
 }
-
 static struct mars_kernel_syscalls kernel_syscalls =
 {
 	get_ticks,
@@ -429,6 +438,7 @@ static struct mars_kernel_syscalls kerne
 	module_workload_schedule_begin,
 	module_workload_schedule_end,
 	module_workload_schedule_cancel,
+	module_host_signal_send,
 	module_exit
 };
 
@@ -540,6 +550,16 @@ static int reserve_block(int block)
 	return index;
 }
 
+static void notify_host_bits(uint64_t block_ea, int index)
+{
+	uint64_t bits_ea =
+		block_ea +
+		offsetof(struct mars_workload_queue_block, bits) +
+		sizeof(uint64_t) * index;
+
+	module_host_signal_send(bits_ea);
+}
+
 static void release_block(int block, int index)
 {
 	uint64_t block_ea = get_block_ea(block);
@@ -550,6 +570,9 @@ static void release_block(int block, int
 	MARS_BITS_SET(&queue_block.bits[index], STATE, workload_state);
 
 	mars_mutex_unlock_put(block_ea, (struct mars_mutex *)&queue_block);
+
+	if (workload_state == MARS_WORKLOAD_STATE_FINISHED)
+		notify_host_bits(block_ea, index);
 }
 
 static int __attribute__((noinline)) reserve_workload(void)
@@ -716,5 +739,7 @@ int main(unsigned long long mpu_context_
 		}
 	}
 
+	module_host_signal_send(MARS_HOST_SIGNAL_EXIT);
+
 	return MARS_SUCCESS;
 }
--- a/base/src/mpu/lib/module.c
+++ b/base/src/mpu/lib/module.c
@@ -163,3 +163,8 @@ void mars_module_workload_finish(void)
 {
 	(*kernel_syscalls->exit)(MARS_WORKLOAD_STATE_FINISHED);
 }
+
+int mars_module_host_signal_send(uint64_t watch_point_ea)
+{
+	return (*kernel_syscalls->host_signal_send)(watch_point_ea);
+}
--- a/scripts/acinclude.m4
+++ b/scripts/acinclude.m4
@@ -66,6 +66,28 @@ AC_ARG_ENABLE(
 AC_MSG_RESULT([using enable-discrete-shared-memory ${enable_discrete_shared_memory}])
 ]) # AC_CONFIG_MARS_DISCRETE_SHARED_MEMORY
 
+AC_DEFUN([AC_CONFIG_MARS_COND_WAIT],[
+AC_ARG_ENABLE([cond-wait],
+	[AS_HELP_STRING([--enable-cond-wait=TYPE],
+		[specify how to wait for conditions (busy | futex)])],
+	[],[AS_CASE([$with_mars_platform],
+		[cell],[enable_cond_wait=futex],
+		[enable_cond_wait=busy])])
+
+AS_CASE([$enable_cond_wait],
+	[busy],[
+		AC_DEFINE([ENABLE_COND_WAIT_BUSY],[1],
+			[Define to 1 if busy loop is used to wait for conditions.])],
+	[futex],[
+		AS_CASE([$with_mars_platform],
+			[cell],[],
+			[AC_MSG_ERROR([futex is not supported on other platforms than Cell/B.E.])])
+		AC_DEFINE([ENABLE_COND_WAIT_FUTEX],[1],
+			[Define to 1 if futex is used to wait for conditions.])],
+	[AC_MSG_ERROR([invalid option --enable-cond-wait=$enable_cond_wait])])
+
+AC_MSG_RESULT([using enable-cond-wait $enable_cond_wait])
+]) # AC_CONFIG_MARS_COND_WAIT
 
 AC_DEFUN([AC_CONFIG_DEBUG],[
 
@@ -95,6 +117,7 @@ AC_DEFUN([AC_CONFIG_MARS],[
 
 AC_CONFIG_MARS_PLATFORM
 AC_CONFIG_MARS_DISCRETE_SHARED_MEMORY
+AC_CONFIG_MARS_COND_WAIT
 AC_CONFIG_DEBUG
 AC_CONFIG_MARS_POST
 






More information about the cbe-oss-dev mailing list