On Mon, Jun 23, 2014 at 12:37 PM, Alex Wang <al...@nicira.com> wrote: > Signed-off-by: Alex Wang <al...@nicira.com> > --- > lib/automake.mk | 2 + > lib/ovs-numa.c | 208 > +++++++++++++++++++++++++++++++++++++++++++++++ > lib/ovs-numa.h | 33 ++++++++ > tests/ofproto-macros.at | 1 + > vswitchd/bridge.c | 2 + > 5 files changed, 246 insertions(+) > create mode 100644 lib/ovs-numa.c > create mode 100644 lib/ovs-numa.h > > diff --git a/lib/automake.mk b/lib/automake.mk > index 3f984d9..ca6c890 100644 > --- a/lib/automake.mk > +++ b/lib/automake.mk > @@ -150,6 +150,8 @@ lib_libopenvswitch_la_SOURCES = \ > lib/ovs-atomic-locked.h \ > lib/ovs-atomic-pthreads.h \ > lib/ovs-atomic.h \ > + lib/ovs-numa.c \ > + lib/ovs-numa.h \ This looks POSIX specific. Can you include it only for ! WIN32.
(I hope functionally non-POSIX platforms would still work with this series). > lib/ovs-rcu.c \ > lib/ovs-rcu.h \ > lib/ovs-thread.c \ > diff --git a/lib/ovs-numa.c b/lib/ovs-numa.c > new file mode 100644 > index 0000000..2bcef72 > --- /dev/null > +++ b/lib/ovs-numa.c > @@ -0,0 +1,208 @@ > +/* > + * Copyright (c) 2014 Nicira, Inc. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#include <config.h> > +#include "ovs-numa.h" > + > +#include <ctype.h> > +#include <dirent.h> > +#include <sys/types.h> > + > +#include "hash.h" > +#include "hmap.h" > +#include "list.h" > +#include "ovs-thread.h" > +#include "vlog.h" > + > +VLOG_DEFINE_THIS_MODULE(ovs_numa); > + > +#define MAX_CPU_SOCKETS 8 > + > +#define SYS_SOCKET_DIR "/sys/devices/system/node/node%d" > + > +/* Cpu socket. */ > +struct cpu_socket { > + struct hmap_node hmap_node; /* In the 'all_cpu_sockets'. */ > + struct list cores; /* List of cpu cores on the socket. */ > + uint32_t socket_id; /* Socket id. */ > +}; > + > +/* Cpu core on a cpu socket. */ > +struct cpu_core { > + struct hmap_node hmap_node;/* In the 'all_cpu_coress'. */ > + struct list list_node; /* In 'cpu_socket->cores' list. */ > + struct cpu_socket *socket; /* Socket containing the core. */ > + uint32_t core_id; /* Core id. */ > + bool pinned; /* If a thread has been pinned to the core. */ > +}; > + > +/* Contains all 'struct cpu_socket's. */ > +static struct hmap all_cpu_sockets = HMAP_INITIALIZER(&all_cpu_sockets); > +/* Contains all 'struct cpu_core's. */ > +static struct hmap all_cpu_cores = HMAP_INITIALIZER(&all_cpu_cores); > + > +/* Returns true if 'str' contains all digits. Returns false otherwise. */ > +static bool > +contain_all_digits(const char *str) > +{ > + size_t i = 0; > + > + while (str[i] != '\0') { > + if (!isdigit(str[i++])) { > + return false; > + } > + } > + > + return true; > +} > + > +/* Discovers all cpu sockets and the corresponding cpu cores for each socket. > + * Constructs the 'struct cpu_socket' and 'struct cpu_core'. */ > +static void > +discover_sockets_and_cores(void) > +{ > + int n_cpus = 0; > + int i; > + > + for (i = 0; i < MAX_CPU_SOCKETS; i++) { > + DIR *dir; > + char path[PATH_MAX]; > + int path_len; > + > + /* Constructs the path to node /sys/devices/system/nodeX. */ > + path_len = snprintf(path, sizeof(path), SYS_SOCKET_DIR, i); > + > + if (path_len <= 0 || path_len >= sizeof(path)) { > + VLOG_WARN("Path to cpu socket %d exceeds the length limit", i); > + break; > + } > + > + dir = opendir(path); > + > + /* Creates 'struct cpu_socket' if the 'dir' is non-null. */ > + if (dir) { > + struct cpu_socket *s = xzalloc(sizeof *s); > + struct dirent *subdir; > + char *endptr = NULL; > + > + hmap_insert(&all_cpu_sockets, &s->hmap_node, hash_int(i, 0)); > + list_init(&s->cores); > + s->socket_id = i; > + > + while ((subdir = readdir(dir)) != NULL) { > + if (!strncmp(subdir->d_name, "cpu", 3) > + && contain_all_digits(subdir->d_name + 3)){ > + struct cpu_core *c = xzalloc(sizeof *c); > + uint32_t core_id; > + > + core_id = strtoul(subdir->d_name + 3, &endptr, 10); > + hmap_insert(&all_cpu_cores, &c->hmap_node, > + hash_int(core_id, 0)); > + list_insert(&s->cores, &c->list_node); > + c->core_id = core_id; > + n_cpus++; > + } > + } > + } else { > + break; > + } > + closedir(dir); > + } > + > + VLOG_INFO("Discovered %"PRIu64" CPU Sockets and %d CPU cores", > + hmap_count(&all_cpu_sockets), n_cpus); > +} > + > +/* Extracts the numa node and core info from the 'sysfs'. */ > +void > +ovs_numa_init(void) > +{ > + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; > + > + if (ovsthread_once_start(&once)) { > + discover_sockets_and_cores(); > + ovsthread_once_done(&once); > + } > +} > + > +/* Returns the number of cpu sockets. */ > +uint32_t > +ovs_numa_get_n_sockets(void) > +{ > + return hmap_count(&all_cpu_sockets); > +} > + > +/* Returns the number of cpu cores. */ > +uint32_t > +ovs_numa_get_n_cores(void) > +{ > + return hmap_count(&all_cpu_cores); > +} > + > +/* Searches through all cores for an unpinned core. Returns the core_id > + * if found and set the 'core->pinned' to true. Otherwise, returns -1. */ > +int > +ovs_numa_get_unpinned_core_any(void) > +{ > + struct cpu_core *core; > + > + HMAP_FOR_EACH(core, hmap_node, &all_cpu_cores) { > + if (!core->pinned) { > + core->pinned = true; > + return core->core_id; > + } > + } > + > + return -1; > +} > + > +/* Searches through all cores on socket with 'socket_id' for an unpinned > core. > + * Returns the core_id if found and sets the 'core->pinned' to true. > + * Otherwise, returns -1. */ > +int > +ovs_numa_get_unpinned_core_on_socket(uint32_t socket_id) > +{ > + struct cpu_socket *socket; > + struct cpu_core *core; > + > + CPU_SOCKET_ID_ASSERT(socket_id); > + > + socket = CONTAINER_OF(hmap_first_with_hash(&all_cpu_sockets, > + hash_int(socket_id, 0)), > + struct cpu_socket, hmap_node); > + LIST_FOR_EACH(core, list_node, &socket->cores) { > + if (!core->pinned) { > + core->pinned = true; > + return core->core_id; > + } > + } > + > + return -1; > +} > + > +/* Resets the 'core->pinned' for the core with 'core_id'. */ > +void > +ovs_numa_unpin_core(uint32_t core_id) > +{ > + struct cpu_core *core; > + > + CPU_CORE_ID_ASSERT(core_id); > + > + core = CONTAINER_OF(hmap_first_with_hash(&all_cpu_cores, > + hash_int(core_id, 0)), > + struct cpu_core, hmap_node); > + core->pinned = false; > +} > diff --git a/lib/ovs-numa.h b/lib/ovs-numa.h > new file mode 100644 > index 0000000..3e31d9e > --- /dev/null > +++ b/lib/ovs-numa.h > @@ -0,0 +1,33 @@ > +/* > + * Copyright (c) 2014 Nicira, Inc. > + * > + * Licensed under the Apache License, Version 2.0 (the "License"); > + * you may not use this file except in compliance with the License. > + * You may obtain a copy of the License at: > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, software > + * distributed under the License is distributed on an "AS IS" BASIS, > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > + * See the License for the specific language governing permissions and > + * limitations under the License. > + */ > + > +#ifndef OVS_NUMA_H > +#define OVS_NUMA_H 1 > + > +#include <stdint.h> > + > +#define CPU_SOCKET_ID_ASSERT(SID) ovs_assert((SID) < > ovs_numa_get_n_sockets()) > +#define CPU_CORE_ID_ASSERT(CID) ovs_assert((CID) < ovs_numa_get_n_cores()) > + > +void ovs_numa_init(void); > + > +uint32_t ovs_numa_get_n_sockets(void); > +uint32_t ovs_numa_get_n_cores(void); > +int ovs_numa_get_unpinned_core_any(void); > +int ovs_numa_get_unpinned_core_on_socket(uint32_t socket_id); > +void ovs_numa_unpin_core(uint32_t core_id); > + > +#endif /* ovs-thread.h */ > diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at > index 85ecc5c..77b9b39 100644 > --- a/tests/ofproto-macros.at > +++ b/tests/ofproto-macros.at > @@ -76,6 +76,7 @@ m4_define([OVS_VSWITCHD_START], > AT_CHECK([ovs-vswitchd --detach --no-chdir --pidfile --enable-dummy$3 > --disable-system --log-file -vvconn -vofproto_dpif], [0], [], [stderr]) > AT_CAPTURE_FILE([ovs-vswitchd.log]) > AT_CHECK([[sed < stderr ' > +/ovs_numa|INFO|Discovered /d > /vlog|INFO|opened log file/d > /vswitchd|INFO|ovs-vswitchd (Open vSwitch)/d > /reconnect|INFO|/d > diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c > index 1fa1820..797584b 100644 > --- a/vswitchd/bridge.c > +++ b/vswitchd/bridge.c > @@ -41,6 +41,7 @@ > #include "ofpbuf.h" > #include "ofproto/bond.h" > #include "ofproto/ofproto.h" > +#include "ovs-numa.h" > #include "poll-loop.h" > #include "seq.h" > #include "sha1.h" > @@ -439,6 +440,7 @@ bridge_init(const char *remote) > lacp_init(); > bond_init(); > cfm_init(); > + ovs_numa_init(); > stp_init(); > } > > -- > 1.7.9.5 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev