Signed-off-by: Robbie King <[email protected]>
---
helper/include/odph_linux.h | 34 +++--
platform/linux-generic/include/api/odp_coremask.h | 128 ++++++++++++------
platform/linux-generic/odp_coremask.c | 157 +++++++++++-----------
platform/linux-generic/odp_linux.c | 95 +++++++++----
4 files changed, 257 insertions(+), 157 deletions(-)
diff --git a/helper/include/odph_linux.h b/helper/include/odph_linux.h
index 4ed8bbe..fc7b88e 100644
--- a/helper/include/odph_linux.h
+++ b/helper/include/odph_linux.h
@@ -26,6 +26,8 @@ extern "C" {
#include <pthread.h>
#include <sys/types.h>
+#include <odp.h>
+
/** Linux pthread state information */
typedef struct {
pthread_t thread; /**< Pthread ID */
@@ -43,21 +45,34 @@ typedef struct {
/**
+ * Creates and pthread/process coremask
+ *
+ * @todo This code should move to somewhere test/example specific
+ * as opposed to a helper routine.
+ *
+ * Creates coremask based on starting CPU and a count, actual
+ * values returned
+ *
+ * @param num Number of threads to create, zero for all available
+ * @param first_cpu First physical CPU
+ * @param mask Coremask to initialize
+ * @return Actual values for "num" and "first_cpu" used to create mask
+ */
+void odph_linux_coremask_create(int *num, int *first_cpu, odp_coremask_t
*mask);
+
+/**
* Creates and launches pthreads
*
- * Creates, pins and launches num threads to separate CPU's starting from
- * first_cpu.
+ * Creates, pins and launches threads to separate CPU's based on the coremask.
*
* @param thread_tbl Thread table
- * @param num Number of threads to create
- * @param first_cpu First physical CPU
+ * @param mask Coremask
* @param start_routine Thread start function
* @param arg Thread argument
*/
void odph_linux_pthread_create(odph_linux_pthread_t *thread_tbl,
- int num, int first_cpu,
- void *(*start_routine) (void *), void *arg);
-
+ odp_coremask_t *mask,
+ void *(*start_routine) (void *), void *arg);
/**
* Waits pthreads to exit
@@ -91,14 +106,13 @@ int odph_linux_process_fork(odph_linux_process_t *proc,
int cpu);
* Forks and sets CPU affinity for child processes
*
* @param proc_tbl Process state info table (for output)
- * @param num Number of processes to create
- * @param first_cpu Destination CPU for the first process
+ * @param mask Coremask of processes to create
*
* @return On success: 1 for the parent, 0 for the child
* On failure: -1 for the parent, -2 for the child
*/
int odph_linux_process_fork_n(odph_linux_process_t *proc_tbl,
- int num, int first_cpu);
+ odp_coremask_t *mask);
/**
diff --git a/platform/linux-generic/include/api/odp_coremask.h
b/platform/linux-generic/include/api/odp_coremask.h
index d4172fa..1f8b7b9 100644
--- a/platform/linux-generic/include/api/odp_coremask.h
+++ b/platform/linux-generic/include/api/odp_coremask.h
@@ -18,7 +18,8 @@
extern "C" {
#endif
-
+#include <string.h>
+#include <sched.h>
#include <odp_std_types.h>
@@ -27,21 +28,15 @@ extern "C" {
* @{
*/
-/** @internal */
-#define ODP_COREMASK_SIZE_U64 1
-
/**
* Core mask
*
* Don't access directly, use access functions.
*/
typedef struct odp_coremask_t {
- uint64_t _u64[ODP_COREMASK_SIZE_U64]; /**< @private Mask*/
-
+ cpu_set_t set; /**< @private Mask*/
} odp_coremask_t;
-
-
/**
* Add core mask bits from a string
*
@@ -64,36 +59,13 @@ void odp_coremask_from_str(const char *str, odp_coremask_t
*mask);
*/
void odp_coremask_to_str(char *str, int len, const odp_coremask_t *mask);
-
-/**
- * Add core mask bits from a u64 array
- *
- * In the array core #0 is located at the least significant bit
- * of the first word (u64[0] = 0x1).
- *
- * Examples
- * core 0: u64[0] = 0x1
- * core 1: u64[0] = 0x2
- * ...
- * core 63: u64[0] = 0x8000 0000 0000 0000
- * core 64: u64[0] = 0x0, u64[1] = 0x1
- * core 65: u64[0] = 0x0, u64[1] = 0x2
- *
- * @param u64 An array of u64 bit words
- * @param num Number of u64 words in the array
- * @param mask Core mask to modify
- *
- * @note Supports currently only core indexes upto 63
- */
-void odp_coremask_from_u64(const uint64_t *u64, int num, odp_coremask_t *mask);
-
/**
* Clear entire mask
* @param mask Core mask to flush with zero value
*/
static inline void odp_coremask_zero(odp_coremask_t *mask)
{
- mask->_u64[0] = 0;
+ CPU_ZERO(&mask->set);
}
/**
@@ -101,14 +73,20 @@ static inline void odp_coremask_zero(odp_coremask_t *mask)
* @param core Core number
* @param mask add core number in core mask
*/
-void odp_coremask_set(int core, odp_coremask_t *mask);
+static inline void odp_coremask_set(int core, odp_coremask_t *mask)
+{
+ CPU_SET(core, &mask->set);
+}
/**
* Remove core from mask
* @param core Core number
* @param mask clear core number from core mask
*/
-void odp_coremask_clr(int core, odp_coremask_t *mask);
+static inline void odp_coremask_clr(int core, odp_coremask_t *mask)
+{
+ CPU_CLR(core, &mask->set);
+}
/**
* Test if core is a member of mask
@@ -116,16 +94,20 @@ void odp_coremask_clr(int core, odp_coremask_t *mask);
* @param mask Core mask to check if core num set or not
* @return non-zero if set otherwise 0
*/
-int odp_coremask_isset(int core, const odp_coremask_t *mask);
+static inline int odp_coremask_isset(int core, const odp_coremask_t *mask)
+{
+ return CPU_ISSET(core, &mask->set);
+}
/**
* Count number of cores in mask
* @param mask Core mask
* @return coremask count
*/
-int odp_coremask_count(const odp_coremask_t *mask);
-
-
+static inline int odp_coremask_count(const odp_coremask_t *mask)
+{
+ return CPU_COUNT(&mask->set);
+}
/**
* Logical AND over two source masks.
@@ -137,7 +119,7 @@ int odp_coremask_count(const odp_coremask_t *mask);
static inline void odp_coremask_and(odp_coremask_t *dest, odp_coremask_t *src1,
odp_coremask_t *src2)
{
- dest->_u64[0] = src1->_u64[0] & src2->_u64[0];
+ CPU_AND(&dest->set, &src1->set, &src2->set);
}
/**
@@ -150,7 +132,7 @@ static inline void odp_coremask_and(odp_coremask_t *dest,
odp_coremask_t *src1,
static inline void odp_coremask_or(odp_coremask_t *dest, odp_coremask_t *src1,
odp_coremask_t *src2)
{
- dest->_u64[0] = src1->_u64[0] | src2->_u64[0];
+ CPU_OR(&dest->set, &src1->set, &src2->set);
}
/**
@@ -163,7 +145,7 @@ static inline void odp_coremask_or(odp_coremask_t *dest,
odp_coremask_t *src1,
static inline void odp_coremask_xor(odp_coremask_t *dest, odp_coremask_t *src1,
odp_coremask_t *src2)
{
- dest->_u64[0] = src1->_u64[0] ^ src2->_u64[0];
+ CPU_XOR(&dest->set, &src1->set, &src2->set);
}
/**
@@ -172,7 +154,69 @@ static inline void odp_coremask_xor(odp_coremask_t *dest,
odp_coremask_t *src1,
static inline int odp_coremask_equal(odp_coremask_t *mask1,
odp_coremask_t *mask2)
{
- return (mask1->_u64[0] == mask2->_u64[0]);
+ return CPU_EQUAL(&mask1->set, &mask2->set);
+}
+
+/**
+ * Copy a core mask
+ */
+static inline void odp_coremask_copy(odp_coremask_t *dest, odp_coremask_t *src)
+{
+ memcpy(&dest->set, &src->set, sizeof(src->set));
+}
+
+/**
+ * Find first bit set in mask
+ *
+ * @return core else -1 if no bits set in coremask
+ */
+static inline int odp_coremask_ffs(const odp_coremask_t *mask)
+{
+ int core;
+
+ for (core = 0; core < CPU_SETSIZE; core++)
+ if (odp_coremask_isset(core, mask))
+ return core;
+ return -1;
+}
+
+/**
+ * Find last bit set in mask
+ *
+ * @return core else -1 if no bits set in coremask
+ */
+static inline int odp_coremask_fls(const odp_coremask_t *mask)
+{
+ int core;
+
+ for (core = CPU_SETSIZE - 1; core >= 0; core--)
+ if (odp_coremask_isset(core, mask))
+ return core;
+ return -1;
+}
+
+/**
+ * Find next core in mask
+ *
+ * Finds the next core (using find first set) in the source core mask,
+ * sets that core in the destination mask and clears it in the source mask.
+ *
+ * @param src Coremask to find next core in
+ * @param dst Coremask to move the found core to
+ * @return core found else -1
+ */
+static inline
+int odp_coremask_next_core(odp_coremask_t *dst, odp_coremask_t *src)
+{
+ int cpu = -1;
+
+ odp_coremask_zero(dst);
+ cpu = odp_coremask_ffs(src);
+ if (cpu >= 0) {
+ odp_coremask_clr(cpu, src);
+ odp_coremask_set(cpu, dst);
+ }
+ return cpu;
}
/**
diff --git a/platform/linux-generic/odp_coremask.c
b/platform/linux-generic/odp_coremask.c
index 54cd333..d987ee7 100644
--- a/platform/linux-generic/odp_coremask.c
+++ b/platform/linux-generic/odp_coremask.c
@@ -10,100 +10,99 @@
#include <stdlib.h>
#include <string.h>
-#define MAX_CORE_NUM 64
-
-
-void odp_coremask_from_str(const char *str, odp_coremask_t *mask)
+void odp_coremask_from_str(const char *str_in, odp_coremask_t *mask)
{
- uint64_t mask_u64;
-
- if (strlen(str) > 18) {
- /* more than 64 bits */
- return;
+ cpu_set_t cpuset;
+ const char *str = str_in;
+ const char *p;
+ int core = 0;
+ int len = strlen(str);
+
+ CPU_ZERO(&cpuset);
+ odp_coremask_zero(mask);
+
+ /* Strip leading "0x"/"0X" if present and verify length */
+ if ((len >= 2) && ((str[1] == 'x') || (str[1] == 'X'))) {
+ str += 2;
+ len -= 2;
}
+ if (!len)
+ return;
- mask_u64 = strtoull(str, NULL, 16);
+ /* Walk string from LSB setting core bits */
+ for (p = str + len - 1; (len > 0) && (core < CPU_SETSIZE); p--, len--) {
+ char c = *p;
+ int value;
+ int idx;
+
+ /* Convert hex nibble, abort when invalid value found */
+ if ((c >= '0') && (c <= '9'))
+ value = c - '0';
+ else if ((c >= 'A') && (c <= 'F'))
+ value = c - 'A' + 10;
+ else if ((c >= 'a') && (c <= 'f'))
+ value = c - 'a' + 10;
+ else
+ return;
+
+ /* Walk converted nibble and set bits in mask */
+ for (idx = 0; idx < 4; idx++, core++)
+ if (value & (1 << idx))
+ CPU_SET(core, &cpuset);
+ }
- odp_coremask_from_u64(&mask_u64, 1, mask);
+ /* Copy the computed mask */
+ memcpy(&mask->set, &cpuset, sizeof(cpuset));
}
-
void odp_coremask_to_str(char *str, int len, const odp_coremask_t *mask)
{
- int ret;
-
- ret = snprintf(str, len, "0x%"PRIx64"", mask->_u64[0]);
-
- if (ret >= 0 && ret < len) {
- /* force trailing zero */
- str[len-1] = '\0';
- }
-}
-
-
-void odp_coremask_from_u64(const uint64_t *u64, int num, odp_coremask_t *mask)
-{
- int i;
-
- if (num > ODP_COREMASK_SIZE_U64) {
- /* force max size */
- num = ODP_COREMASK_SIZE_U64;
- }
-
- for (i = 0; i < num; i++)
- mask->_u64[0] |= u64[i];
-}
+ char *p = str;
+ int core = odp_coremask_fls(mask);
+ int nibbles;
+ int value;
-void odp_coremask_set(int core, odp_coremask_t *mask)
-{
- /* should not be more than 63
- * core no. should be from 0..63= 64bit
- */
- if (core >= MAX_CORE_NUM) {
- ODP_ERR("invalid core count\n");
+ /* Quickly handle bad string length or empty mask */
+ if (len <= 0)
+ return;
+ *str = 0;
+ if (core < 0) {
+ if (len >= 4)
+ strcpy(str, "0x0");
return;
}
- mask->_u64[0] |= (1ULL << core);
-}
+ /* Compute number nibbles in coremask that have bits set */
+ nibbles = (core / 4) + 1;
-void odp_coremask_clr(int core, odp_coremask_t *mask)
-{
- /* should not be more than 63
- * core no. should be from 0..63= 64bit
- */
- if (core >= MAX_CORE_NUM) {
- ODP_ERR("invalid core count\n");
+ /* Verify minimum space (account for "0x" and termination) */
+ if (len < (3 + nibbles))
return;
- }
-
- mask->_u64[0] &= ~(1ULL << core);
-}
+ /* Prefix */
+ *p++ = '0';
+ *p++ = 'x';
-int odp_coremask_isset(int core, const odp_coremask_t *mask)
-{
- /* should not be more than 63
- * core no. should be from 0..63= 64bit
+ /*
+ * Now we can scan the cores down to zero and
+ * build the string one nibble at a time
*/
- if (core >= MAX_CORE_NUM) {
- ODP_ERR("invalid core count\n");
- return -1;
- }
-
- return (mask->_u64[0] >> core) & 1;
-}
-
-int odp_coremask_count(const odp_coremask_t *mask)
-{
- uint64_t coremask = mask->_u64[0];
- int cnt = 0;
-
- while (coremask != 0) {
- coremask >>= 1;
- if (coremask & 1)
- cnt++;
- }
-
- return cnt;
+ value = 0;
+ do {
+ /* Set bit to go into the current nibble */
+ if (CPU_ISSET(core, &mask->set))
+ value |= 1 << (core % 4);
+
+ /* If we are on a nibble boundary flush value to string */
+ if (0 == (core % 4)) {
+ if (value < 0xA)
+ *p++ = '0' + value;
+ else
+ *p++ = 'A' + value - 0xA;
+ value = 0;
+ }
+ } while (core--);
+
+ /* Terminate the string */
+ *p++ = 0;
}
diff --git a/platform/linux-generic/odp_linux.c
b/platform/linux-generic/odp_linux.c
index 79192cf..1b343b4 100644
--- a/platform/linux-generic/odp_linux.c
+++ b/platform/linux-generic/odp_linux.c
@@ -25,6 +25,7 @@
#include <odp_system_info.h>
#include <odp_debug_internal.h>
+#define MAX_WORKERS 32
typedef struct {
void *(*start_routine) (void *);
@@ -33,6 +34,40 @@ typedef struct {
} odp_start_args_t;
+void odph_linux_coremask_create(int *num, int *first_cpu, odp_coremask_t *mask)
+{
+ int i;
+ int cpu_count;
+
+ cpu_count = odp_sys_cpu_count();
+
+ /*
+ * If no user supplied number or it's too large, then attempt
+ * to use all CPUs, however use no more than MAX_WORKERS.
+ */
+ if (0 == *num)
+ *num = cpu_count;
+ if (cpu_count < *num)
+ *num = cpu_count;
+ if (MAX_WORKERS < *num)
+ *num = MAX_WORKERS;
+
+ /*
+ * Always force "first_cpu" to a valid core
+ */
+ if (*first_cpu >= cpu_count)
+ *first_cpu = cpu_count - 1;
+
+ /* Build the mask */
+ odp_coremask_zero(mask);
+ for (i = 0; i < *num; i++) {
+ int cpu;
+
+ cpu = (*first_cpu + i) % cpu_count;
+ odp_coremask_set(cpu, mask);
+ }
+}
+
static void *odp_run_start_routine(void *arg)
{
odp_start_args_t *start_args = arg;
@@ -55,33 +90,39 @@ static void *odp_run_start_routine(void *arg)
}
-void odph_linux_pthread_create(odph_linux_pthread_t *thread_tbl, int num,
- int first_cpu,
+void odph_linux_pthread_create(odph_linux_pthread_t *thread_tbl,
+ odp_coremask_t *mask_in,
void *(*start_routine) (void *), void *arg)
{
int i;
- cpu_set_t cpu_set;
+ int num;
+ odp_coremask_t mask;
odp_start_args_t *start_args;
int cpu_count;
int cpu;
- cpu_count = odp_sys_cpu_count();
+ odp_coremask_copy(&mask, mask_in);
+ num = odp_coremask_count(&mask);
- assert((first_cpu >= 0) && (first_cpu < cpu_count));
- assert((num >= 0) && (num <= cpu_count));
+ memset(thread_tbl, 0, num * sizeof(odph_linux_process_t));
- memset(thread_tbl, 0, num * sizeof(odph_linux_pthread_t));
+ cpu_count = odp_sys_cpu_count();
+
+ if (num < 1 || num > cpu_count) {
+ ODP_ERR("Bad num\n");
+ }
for (i = 0; i < num; i++) {
+ odp_coremask_t thd_mask;
+
+ cpu = odp_coremask_next_core(&thd_mask, &mask);
+
pthread_attr_init(&thread_tbl[i].attr);
- cpu = (first_cpu + i) % cpu_count;
thread_tbl[i].cpu = cpu;
- CPU_ZERO(&cpu_set);
- CPU_SET(cpu, &cpu_set);
pthread_attr_setaffinity_np(&thread_tbl[i].attr,
- sizeof(cpu_set_t), &cpu_set);
+ sizeof(cpu_set_t), &thd_mask.set);
start_args = malloc(sizeof(odp_start_args_t));
if (start_args == NULL)
@@ -109,30 +150,31 @@ void odph_linux_pthread_join(odph_linux_pthread_t
*thread_tbl, int num)
int odph_linux_process_fork_n(odph_linux_process_t *proc_tbl,
- int num, int first_cpu)
+ odp_coremask_t *mask_in)
{
- cpu_set_t cpu_set;
+ odp_coremask_t mask;
pid_t pid;
+ int num;
int cpu_count;
int cpu;
int i;
- memset(proc_tbl, 0, num*sizeof(odph_linux_process_t));
+ odp_coremask_copy(&mask, mask_in);
+ num = odp_coremask_count(&mask);
- cpu_count = odp_sys_cpu_count();
+ memset(proc_tbl, 0, num * sizeof(odph_linux_process_t));
- if (first_cpu < 0 || first_cpu >= cpu_count) {
- ODP_ERR("Bad first_cpu\n");
- return -1;
- }
+ cpu_count = odp_sys_cpu_count();
- if (num < 0 || num > cpu_count) {
+ if (num < 1 || num > cpu_count) {
ODP_ERR("Bad num\n");
return -1;
}
for (i = 0; i < num; i++) {
- cpu = (first_cpu + i) % cpu_count;
+ odp_coremask_t proc_mask;
+
+ cpu = odp_coremask_next_core(&proc_mask, &mask);
pid = fork();
if (pid < 0) {
@@ -148,10 +190,7 @@ int odph_linux_process_fork_n(odph_linux_process_t
*proc_tbl,
}
/* Child process */
- CPU_ZERO(&cpu_set);
- CPU_SET(cpu, &cpu_set);
-
- if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set)) {
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &proc_mask.set)) {
ODP_ERR("sched_setaffinity() failed\n");
return -2;
}
@@ -170,7 +209,11 @@ int odph_linux_process_fork_n(odph_linux_process_t
*proc_tbl,
int odph_linux_process_fork(odph_linux_process_t *proc, int cpu)
{
- return odph_linux_process_fork_n(proc, 1, cpu);
+ odp_coremask_t mask;
+
+ odp_coremask_zero(&mask);
+ odp_coremask_set(cpu, &mask);
+ return odph_linux_process_fork_n(proc, &mask);
}
--
1.9.3
_______________________________________________
lng-odp mailing list
[email protected]
http://lists.linaro.org/mailman/listinfo/lng-odp