[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