X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=lib%2Fovs-numa.c;h=2765ae2db6e4a9cbf3ceb9d9db83f39916d72f7b;hb=d0a46cb4608e632f5028034762f0adde2ce947a0;hp=7da14073e58ff149274145f42d36c47572e6295e;hpb=46a14035521c52bf38d6e32927a8e33f19c76fff;p=cascardo%2Fovs.git diff --git a/lib/ovs-numa.c b/lib/ovs-numa.c index 7da14073e..2765ae2db 100644 --- a/lib/ovs-numa.c +++ b/lib/ovs-numa.c @@ -32,7 +32,7 @@ #include "hmap.h" #include "list.h" #include "ovs-thread.h" -#include "vlog.h" +#include "openvswitch/vlog.h" VLOG_DEFINE_THIS_MODULE(ovs_numa); @@ -47,6 +47,8 @@ VLOG_DEFINE_THIS_MODULE(ovs_numa); * user can assume core ids from 0 to N-1 are all valid and there is a * 'struct cpu_core' for each id. * + * NOTE, this module should only be used by the main thread. + * * NOTE, the assumption above will fail when cpu hotplug is used. In that * case ovs-numa will not function correctly. For now, add a TODO entry * for addressing it in the future. @@ -59,16 +61,17 @@ VLOG_DEFINE_THIS_MODULE(ovs_numa); /* numa node. */ struct numa_node { struct hmap_node hmap_node; /* In the 'all_numa_nodes'. */ - struct list cores; /* List of cpu cores on the numa node. */ + struct ovs_list cores; /* List of cpu cores on the numa node. */ int numa_id; /* numa node id. */ }; /* Cpu core on a numa node. */ struct cpu_core { struct hmap_node hmap_node;/* In the 'all_cpu_cores'. */ - struct list list_node; /* In 'numa_node->cores' list. */ + struct ovs_list list_node; /* In 'numa_node->cores' list. */ struct numa_node *numa; /* numa node containing the core. */ - int core_id; /* Core id. */ + unsigned core_id; /* Core id. */ + bool available; /* If the core can be pinned. */ bool pinned; /* If a thread has been pinned to the core. */ }; @@ -93,13 +96,29 @@ discover_numa_and_core(void) { int n_cpus = 0; int i; + DIR *dir; + bool numa_supported = true; + + /* Check if NUMA supported on this system. */ + dir = opendir("/sys/devices/system/node"); + + if (!dir && errno == ENOENT) { + numa_supported = false; + } + if (dir) { + closedir(dir); + } for (i = 0; i < MAX_NUMA_NODES; i++) { - DIR *dir; char* path; - /* Constructs the path to node /sys/devices/system/nodeX. */ - path = xasprintf("/sys/devices/system/node/node%d", i); + if (numa_supported) { + /* Constructs the path to node /sys/devices/system/nodeX. */ + path = xasprintf("/sys/devices/system/node/node%d", i); + } else { + path = xasprintf("/sys/devices/system/cpu/"); + } + dir = opendir(path); /* Creates 'struct numa_node' if the 'dir' is non-null. */ @@ -115,7 +134,7 @@ discover_numa_and_core(void) 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; + unsigned core_id; core_id = strtoul(subdir->d_name + 3, NULL, 10); hmap_insert(&all_cpu_cores, &c->hmap_node, @@ -123,19 +142,20 @@ discover_numa_and_core(void) list_insert(&n->cores, &c->list_node); c->core_id = core_id; c->numa = n; + c->available = true; n_cpus++; } } VLOG_INFO("Discovered %"PRIuSIZE" CPU cores on NUMA node %d", list_size(&n->cores), n->numa_id); - free(path); closedir(dir); - } else { - if (errno != ENOENT) { - VLOG_WARN("opendir(%s) failed (%s)", path, - ovs_strerror(errno)); - } - free(path); + } else if (errno != ENOENT) { + VLOG_WARN("opendir(%s) failed (%s)", path, + ovs_strerror(errno)); + } + + free(path); + if (!dir || !numa_supported) { break; } } @@ -147,6 +167,37 @@ discover_numa_and_core(void) } } +/* Gets 'struct cpu_core' by 'core_id'. */ +static struct cpu_core* +get_core_by_core_id(unsigned core_id) +{ + struct cpu_core *core = NULL; + + if (ovs_numa_core_id_is_valid(core_id)) { + core = CONTAINER_OF(hmap_first_with_hash(&all_cpu_cores, + hash_int(core_id, 0)), + struct cpu_core, hmap_node); + } + + return core; +} + +/* Gets 'struct numa_node' by 'numa_id'. */ +static struct numa_node* +get_numa_by_numa_id(int numa_id) +{ + struct numa_node *numa = NULL; + + if (ovs_numa_numa_id_is_valid(numa_id)) { + numa = CONTAINER_OF(hmap_first_with_hash(&all_numa_nodes, + hash_int(numa_id, 0)), + struct numa_node, hmap_node); + } + + return numa; +} + + /* Extracts the numa node and core info from the 'sysfs'. */ void ovs_numa_init(void) @@ -166,11 +217,23 @@ ovs_numa_numa_id_is_valid(int numa_id) } bool -ovs_numa_core_id_is_valid(int core_id) +ovs_numa_core_id_is_valid(unsigned core_id) { return found_numa_and_core && core_id < ovs_numa_get_n_cores(); } +bool +ovs_numa_core_is_pinned(unsigned core_id) +{ + struct cpu_core *core = get_core_by_core_id(core_id); + + if (core) { + return core->pinned; + } + + return false; +} + /* Returns the number of numa nodes. */ int ovs_numa_get_n_numas(void) @@ -190,17 +253,14 @@ ovs_numa_get_n_cores(void) /* Given 'core_id', returns the corresponding numa node id. Returns * OVS_NUMA_UNSPEC if 'core_id' is invalid. */ int -ovs_numa_get_numa_id(int core_id) +ovs_numa_get_numa_id(unsigned core_id) { - if (ovs_numa_core_id_is_valid(core_id)) { - struct cpu_core *core; - - core = CONTAINER_OF(hmap_first_with_hash(&all_cpu_cores, - hash_int(core_id, 0)), - struct cpu_core, hmap_node); + struct cpu_core *core = get_core_by_core_id(core_id); + if (core) { return core->numa->numa_id; } + return OVS_NUMA_UNSPEC; } @@ -209,38 +269,31 @@ ovs_numa_get_numa_id(int core_id) int ovs_numa_get_n_cores_on_numa(int numa_id) { - if (ovs_numa_numa_id_is_valid(numa_id)) { - struct numa_node *numa; - - numa = CONTAINER_OF(hmap_first_with_hash(&all_numa_nodes, - hash_int(numa_id, 0)), - struct numa_node, hmap_node); + struct numa_node *numa = get_numa_by_numa_id(numa_id); + if (numa) { return list_size(&numa->cores); } return OVS_CORE_UNSPEC; } -/* Returns the number of unpinned cpu cores on numa node. Returns - * OVS_CORE_UNSPEC if 'numa_id' is invalid. */ +/* Returns the number of cpu cores that are available and unpinned + * on numa node. Returns OVS_CORE_UNSPEC if 'numa_id' is invalid. */ int ovs_numa_get_n_unpinned_cores_on_numa(int numa_id) { - if (ovs_numa_numa_id_is_valid(numa_id)) { - struct numa_node *numa; + struct numa_node *numa = get_numa_by_numa_id(numa_id); + + if (numa) { struct cpu_core *core; int count = 0; - numa = CONTAINER_OF(hmap_first_with_hash(&all_numa_nodes, - hash_int(numa_id, 0)), - struct numa_node, hmap_node); LIST_FOR_EACH(core, list_node, &numa->cores) { - if (!core->pinned) { + if (core->available && !core->pinned) { count++; } } - return count; } @@ -248,17 +301,15 @@ ovs_numa_get_n_unpinned_cores_on_numa(int numa_id) } /* Given 'core_id', tries to pin that core. Returns true, if succeeds. - * False, if the core has already been pinned or if 'core_id' is invalid. */ + * False, if the core has already been pinned, or if it is invalid or + * not available. */ bool -ovs_numa_try_pin_core_specific(int core_id) +ovs_numa_try_pin_core_specific(unsigned core_id) { - if (ovs_numa_core_id_is_valid(core_id)) { - struct cpu_core *core; + struct cpu_core *core = get_core_by_core_id(core_id); - core = CONTAINER_OF(hmap_first_with_hash(&all_cpu_cores, - hash_int(core_id, 0)), - struct cpu_core, hmap_node); - if (!core->pinned) { + if (core) { + if (core->available && !core->pinned) { core->pinned = true; return true; } @@ -267,16 +318,16 @@ ovs_numa_try_pin_core_specific(int core_id) return false; } -/* Searches through all cores for an unpinned core. Returns the core_id - * if found and set the 'core->pinned' to true. Otherwise, returns - * OVS_CORE_UNSPEC. */ -int +/* Searches through all cores for an unpinned and available core. Returns + * the 'core_id' if found and sets the 'core->pinned' to true. Otherwise, + * returns OVS_CORE_UNSPEC. */ +unsigned ovs_numa_get_unpinned_core_any(void) { struct cpu_core *core; HMAP_FOR_EACH(core, hmap_node, &all_cpu_cores) { - if (!core->pinned) { + if (core->available && !core->pinned) { core->pinned = true; return core->core_id; } @@ -285,21 +336,19 @@ ovs_numa_get_unpinned_core_any(void) return OVS_CORE_UNSPEC; } -/* Searches through all cores on numa node with 'numa_id' for an unpinned - * core. Returns the core_id if found and sets the 'core->pinned' to true. - * Otherwise, returns OVS_CORE_UNSPEC. */ -int +/* Searches through all cores on numa node with 'numa_id' for an + * unpinned and available core. Returns the core_id if found and + * sets the 'core->pinned' to true. Otherwise, returns OVS_CORE_UNSPEC. */ +unsigned ovs_numa_get_unpinned_core_on_numa(int numa_id) { - if (ovs_numa_numa_id_is_valid(numa_id)) { - struct numa_node *numa; + struct numa_node *numa = get_numa_by_numa_id(numa_id); + + if (numa) { struct cpu_core *core; - numa = CONTAINER_OF(hmap_first_with_hash(&all_numa_nodes, - hash_int(numa_id, 0)), - struct numa_node, hmap_node); LIST_FOR_EACH(core, list_node, &numa->cores) { - if (!core->pinned) { + if (core->available && !core->pinned) { core->pinned = true; return core->core_id; } @@ -309,17 +358,112 @@ ovs_numa_get_unpinned_core_on_numa(int numa_id) return OVS_CORE_UNSPEC; } -/* Resets the 'core->pinned' for the core with 'core_id'. */ +/* Unpins the core with 'core_id'. */ void -ovs_numa_unpin_core(int core_id) +ovs_numa_unpin_core(unsigned core_id) { - if (ovs_numa_core_id_is_valid(core_id)) { + struct cpu_core *core = get_core_by_core_id(core_id); + + if (core) { + core->pinned = false; + } +} + +/* Given the 'numa_id', returns dump of all cores on the numa node. */ +struct ovs_numa_dump * +ovs_numa_dump_cores_on_numa(int numa_id) +{ + struct ovs_numa_dump *dump = NULL; + struct numa_node *numa = get_numa_by_numa_id(numa_id); + + if (numa) { + struct cpu_core *core; + + dump = xmalloc(sizeof *dump); + list_init(&dump->dump); + LIST_FOR_EACH(core, list_node, &numa->cores) { + struct ovs_numa_info *info = xmalloc(sizeof *info); + + info->numa_id = numa->numa_id; + info->core_id = core->core_id; + list_insert(&dump->dump, &info->list_node); + } + } + + return dump; +} + +void +ovs_numa_dump_destroy(struct ovs_numa_dump *dump) +{ + struct ovs_numa_info *iter; + + LIST_FOR_EACH_POP (iter, list_node, &dump->dump) { + free(iter); + } + + free(dump); +} + +/* Reads the cpu mask configuration from 'cmask' and sets the + * 'available' of corresponding cores. For unspecified cores, + * sets 'available' to false. */ +void +ovs_numa_set_cpu_mask(const char *cmask) +{ + int core_id = 0; + int i; + + if (!found_numa_and_core) { + return; + } + + /* If no mask specified, resets the 'available' to true for all cores. */ + if (!cmask) { + struct cpu_core *core; + + HMAP_FOR_EACH(core, hmap_node, &all_cpu_cores) { + core->available = true; + } + + return; + } + + for (i = strlen(cmask) - 1; i >= 0; i--) { + char hex = toupper(cmask[i]); + int bin, j; + + if (hex >= '0' && hex <= '9') { + bin = hex - '0'; + } else if (hex >= 'A' && hex <= 'F') { + bin = hex - 'A' + 10; + } else { + bin = 0; + VLOG_WARN("Invalid cpu mask: %c", cmask[i]); + } + + for (j = 0; j < 4; j++) { + struct cpu_core *core; + + core = CONTAINER_OF(hmap_first_with_hash(&all_cpu_cores, + hash_int(core_id++, 0)), + struct cpu_core, hmap_node); + core->available = (bin >> j) & 0x1; + + if (core_id >= hmap_count(&all_cpu_cores)) { + return; + } + } + } + + /* For unspecified cores, sets 'available' to false. */ + while (core_id < hmap_count(&all_cpu_cores)) { struct cpu_core *core; core = CONTAINER_OF(hmap_first_with_hash(&all_cpu_cores, - hash_int(core_id, 0)), + hash_int(core_id++, 0)), struct cpu_core, hmap_node); - core->pinned = false; + core->available = false; } }