LCOV - code coverage report
Current view: top level - lib - ovs-numa.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 144 207 69.6 %
Date: 2016-09-14 01:02:56 Functions: 20 27 74.1 %
Branches: 77 154 50.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2014 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : #include "ovs-numa.h"
      19                 :            : 
      20                 :            : #include <ctype.h>
      21                 :            : #include <errno.h>
      22                 :            : #ifdef __linux__
      23                 :            : #include <dirent.h>
      24                 :            : #include <stddef.h>
      25                 :            : #include <string.h>
      26                 :            : #include <sys/types.h>
      27                 :            : #include <unistd.h>
      28                 :            : #endif /* __linux__ */
      29                 :            : 
      30                 :            : #include "hash.h"
      31                 :            : #include "openvswitch/hmap.h"
      32                 :            : #include "openvswitch/list.h"
      33                 :            : #include "ovs-thread.h"
      34                 :            : #include "openvswitch/vlog.h"
      35                 :            : 
      36                 :      20190 : VLOG_DEFINE_THIS_MODULE(ovs_numa);
      37                 :            : 
      38                 :            : /* ovs-numa module
      39                 :            :  * ===============
      40                 :            :  *
      41                 :            :  * This module stores the affinity information of numa nodes and cpu cores.
      42                 :            :  * It also provides functions to bookkeep the pin of threads on cpu cores.
      43                 :            :  *
      44                 :            :  * It is assumed that the numa node ids and cpu core ids all start from 0 and
      45                 :            :  * range continuously.  So, for example, if 'ovs_numa_get_n_cores()' returns N,
      46                 :            :  * user can assume core ids from 0 to N-1 are all valid and there is a
      47                 :            :  * 'struct cpu_core' for each id.
      48                 :            :  *
      49                 :            :  * NOTE, this module should only be used by the main thread.
      50                 :            :  *
      51                 :            :  * NOTE, the assumption above will fail when cpu hotplug is used.  In that
      52                 :            :  * case ovs-numa will not function correctly.  For now, add a TODO entry
      53                 :            :  * for addressing it in the future.
      54                 :            :  *
      55                 :            :  * TODO: Fix ovs-numa when cpu hotplug is used.
      56                 :            :  */
      57                 :            : 
      58                 :            : #define MAX_NUMA_NODES 128
      59                 :            : 
      60                 :            : /* numa node. */
      61                 :            : struct numa_node {
      62                 :            :     struct hmap_node hmap_node;     /* In the 'all_numa_nodes'. */
      63                 :            :     struct ovs_list cores;          /* List of cpu cores on the numa node. */
      64                 :            :     int numa_id;                    /* numa node id. */
      65                 :            : };
      66                 :            : 
      67                 :            : /* Cpu core on a numa node. */
      68                 :            : struct cpu_core {
      69                 :            :     struct hmap_node hmap_node;/* In the 'all_cpu_cores'. */
      70                 :            :     struct ovs_list list_node; /* In 'numa_node->cores' list. */
      71                 :            :     struct numa_node *numa;    /* numa node containing the core. */
      72                 :            :     unsigned core_id;          /* Core id. */
      73                 :            :     bool available;            /* If the core can be pinned. */
      74                 :            :     bool pinned;               /* If a thread has been pinned to the core. */
      75                 :            : };
      76                 :            : 
      77                 :            : /* Contains all 'struct numa_node's. */
      78                 :            : static struct hmap all_numa_nodes = HMAP_INITIALIZER(&all_numa_nodes);
      79                 :            : /* Contains all 'struct cpu_core's. */
      80                 :            : static struct hmap all_cpu_cores = HMAP_INITIALIZER(&all_cpu_cores);
      81                 :            : /* True if numa node and core info are correctly extracted. */
      82                 :            : static bool found_numa_and_core;
      83                 :            : /* True if the module was initialized with dummy options. In this case, the
      84                 :            :  * module must not interact with the actual cpus/nodes in the system. */
      85                 :            : static bool dummy_numa = false;
      86                 :            : /* If 'dummy_numa' is true, contains a copy of the dummy numa configuration
      87                 :            :  * parameter */
      88                 :            : static char *dummy_config;
      89                 :            : 
      90                 :            : static struct numa_node *get_numa_by_numa_id(int numa_id);
      91                 :            : 
      92                 :            : #ifdef __linux__
      93                 :            : /* Returns true if 'str' contains all digits.  Returns false otherwise. */
      94                 :            : static bool
      95                 :       2392 : contain_all_digits(const char *str)
      96                 :            : {
      97                 :       2392 :     return str[strspn(str, "0123456789")] == '\0';
      98                 :            : }
      99                 :            : #endif /* __linux__ */
     100                 :            : 
     101                 :            : static struct numa_node *
     102                 :        631 : insert_new_numa_node(int numa_id)
     103                 :            : {
     104                 :        631 :     struct numa_node *n = xzalloc(sizeof *n);
     105                 :            : 
     106                 :        631 :     hmap_insert(&all_numa_nodes, &n->hmap_node, hash_int(numa_id, 0));
     107                 :        631 :     ovs_list_init(&n->cores);
     108                 :        631 :     n->numa_id = numa_id;
     109                 :            : 
     110                 :        631 :     return n;
     111                 :            : }
     112                 :            : 
     113                 :            : static struct cpu_core *
     114                 :       1318 : insert_new_cpu_core(struct numa_node *n, unsigned core_id)
     115                 :            : {
     116                 :       1318 :     struct cpu_core *c = xzalloc(sizeof *c);
     117                 :            : 
     118                 :       1318 :     hmap_insert(&all_cpu_cores, &c->hmap_node, hash_int(core_id, 0));
     119                 :       1318 :     ovs_list_insert(&n->cores, &c->list_node);
     120                 :       1318 :     c->core_id = core_id;
     121                 :       1318 :     c->numa = n;
     122                 :       1318 :     c->available = true;
     123                 :            : 
     124                 :       1318 :     return c;
     125                 :            : }
     126                 :            : 
     127                 :            : /* Has the same effect as discover_numa_and_core(), but instead of reading
     128                 :            :  * sysfs entries, extracts the info from 'dummy_config'.
     129                 :            :  *
     130                 :            :  * 'dummy_config' lists the numa_ids of each CPU separated by a comma, e.g.
     131                 :            :  * - "0,0,0,0": four cores on numa socket 0.
     132                 :            :  * - "0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1": 16 cores on two numa sockets.
     133                 :            :  * - "0,0,0,0,1,1,1,1": 8 cores on two numa sockets.
     134                 :            :  *
     135                 :            :  * The different numa ids must be consecutives or the function will abort. */
     136                 :            : static void
     137                 :         19 : discover_numa_and_core_dummy(const char *dummy_config)
     138                 :            : {
     139                 :         19 :     char *conf = xstrdup(dummy_config);
     140                 :         19 :     char *id, *saveptr = NULL;
     141                 :         19 :     unsigned i = 0;
     142                 :         19 :     long max_numa_id = 0;
     143                 :            : 
     144         [ +  + ]:        141 :     for (id = strtok_r(conf, ",", &saveptr); id;
     145                 :        122 :          id = strtok_r(NULL, ",", &saveptr)) {
     146                 :            :         struct hmap_node *hnode;
     147                 :            :         struct numa_node *n;
     148                 :            :         long numa_id;
     149                 :            : 
     150                 :        122 :         numa_id = strtol(id, NULL, 10);
     151 [ +  - ][ -  + ]:        122 :         if (numa_id < 0 || numa_id >= MAX_NUMA_NODES) {
     152         [ #  # ]:          0 :             VLOG_WARN("Invalid numa node %ld", numa_id);
     153                 :          0 :             continue;
     154                 :            :         }
     155                 :            : 
     156                 :        122 :         max_numa_id = MAX(max_numa_id, numa_id);
     157                 :            : 
     158                 :        122 :         hnode = hmap_first_with_hash(&all_numa_nodes, hash_int(numa_id, 0));
     159                 :            : 
     160         [ +  + ]:        122 :         if (hnode) {
     161                 :         89 :             n = CONTAINER_OF(hnode, struct numa_node, hmap_node);
     162                 :            :         } else {
     163                 :         33 :             n = insert_new_numa_node(numa_id);
     164                 :            :         }
     165                 :            : 
     166                 :        122 :         insert_new_cpu_core(n, i);
     167                 :            : 
     168                 :        122 :         i++;
     169                 :            :     }
     170                 :            : 
     171                 :         19 :     free(conf);
     172                 :            : 
     173         [ -  + ]:         19 :     if (max_numa_id + 1 != hmap_count(&all_numa_nodes)) {
     174                 :          0 :         ovs_fatal(0, "dummy numa contains non consecutive numa ids");
     175                 :            :     }
     176                 :         19 : }
     177                 :            : 
     178                 :            : /* Discovers all numa nodes and the corresponding cpu cores.
     179                 :            :  * Constructs the 'struct numa_node' and 'struct cpu_core'. */
     180                 :            : static void
     181                 :        598 : discover_numa_and_core(void)
     182                 :            : {
     183                 :            : #ifdef __linux__
     184                 :            :     int i;
     185                 :            :     DIR *dir;
     186                 :        598 :     bool numa_supported = true;
     187                 :            : 
     188                 :            :     /* Check if NUMA supported on this system. */
     189                 :        598 :     dir = opendir("/sys/devices/system/node");
     190                 :            : 
     191 [ -  + ][ #  # ]:        598 :     if (!dir && errno == ENOENT) {
     192                 :          0 :         numa_supported = false;
     193                 :            :     }
     194         [ +  - ]:        598 :     if (dir) {
     195                 :        598 :         closedir(dir);
     196                 :            :     }
     197                 :            : 
     198         [ +  - ]:       1196 :     for (i = 0; i < MAX_NUMA_NODES; i++) {
     199                 :            :         char* path;
     200                 :            : 
     201         [ +  - ]:       1196 :         if (numa_supported) {
     202                 :            :             /* Constructs the path to node /sys/devices/system/nodeX. */
     203                 :       1196 :             path = xasprintf("/sys/devices/system/node/node%d", i);
     204                 :            :         } else {
     205                 :          0 :             path = xasprintf("/sys/devices/system/cpu/");
     206                 :            :         }
     207                 :            : 
     208                 :       1196 :         dir = opendir(path);
     209                 :            : 
     210                 :            :         /* Creates 'struct numa_node' if the 'dir' is non-null. */
     211         [ +  + ]:       1196 :         if (dir) {
     212                 :            :             struct numa_node *n;
     213                 :            :             struct dirent *subdir;
     214                 :            : 
     215                 :        598 :             n = insert_new_numa_node(i);
     216                 :            : 
     217         [ +  + ]:      28704 :             while ((subdir = readdir(dir)) != NULL) {
     218         [ +  + ]:      28106 :                 if (!strncmp(subdir->d_name, "cpu", 3)
     219         [ +  + ]:       2392 :                     && contain_all_digits(subdir->d_name + 3)) {
     220                 :            :                     unsigned core_id;
     221                 :            : 
     222                 :       1196 :                     core_id = strtoul(subdir->d_name + 3, NULL, 10);
     223                 :       1196 :                     insert_new_cpu_core(n, core_id);
     224                 :            :                 }
     225                 :            :             }
     226                 :        598 :             closedir(dir);
     227         [ -  + ]:        598 :         } else if (errno != ENOENT) {
     228         [ #  # ]:          0 :             VLOG_WARN("opendir(%s) failed (%s)", path,
     229                 :            :                       ovs_strerror(errno));
     230                 :            :         }
     231                 :            : 
     232                 :       1196 :         free(path);
     233 [ +  + ][ +  - ]:       1196 :         if (!dir || !numa_supported) {
     234                 :            :             break;
     235                 :            :         }
     236                 :            :     }
     237                 :            : #endif /* __linux__ */
     238                 :        598 : }
     239                 :            : 
     240                 :            : /* Gets 'struct cpu_core' by 'core_id'. */
     241                 :            : static struct cpu_core*
     242                 :         31 : get_core_by_core_id(unsigned core_id)
     243                 :            : {
     244                 :         31 :     struct cpu_core *core = NULL;
     245                 :            : 
     246         [ +  - ]:         31 :     if (ovs_numa_core_id_is_valid(core_id)) {
     247                 :         31 :         core = CONTAINER_OF(hmap_first_with_hash(&all_cpu_cores,
     248                 :            :                                                  hash_int(core_id, 0)),
     249                 :            :                             struct cpu_core, hmap_node);
     250                 :            :     }
     251                 :            : 
     252                 :         31 :     return core;
     253                 :            : }
     254                 :            : 
     255                 :            : /* Gets 'struct numa_node' by 'numa_id'. */
     256                 :            : static struct numa_node*
     257                 :         87 : get_numa_by_numa_id(int numa_id)
     258                 :            : {
     259                 :         87 :     struct numa_node *numa = NULL;
     260                 :            : 
     261         [ +  - ]:         87 :     if (ovs_numa_numa_id_is_valid(numa_id)) {
     262                 :         87 :         numa = CONTAINER_OF(hmap_first_with_hash(&all_numa_nodes,
     263                 :            :                                                  hash_int(numa_id, 0)),
     264                 :            :                             struct numa_node, hmap_node);
     265                 :            :     }
     266                 :            : 
     267                 :         87 :     return numa;
     268                 :            : }
     269                 :            : 
     270                 :            : 
     271                 :            : 
     272                 :            : static bool
     273                 :        617 : ovs_numa_init__(const char *dummy_config)
     274                 :            : {
     275                 :            :     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
     276                 :            : 
     277         [ +  - ]:        617 :     if (ovsthread_once_start(&once)) {
     278                 :            :         const struct numa_node *n;
     279                 :            : 
     280         [ +  + ]:        617 :         if (!dummy_config) {
     281                 :        598 :             discover_numa_and_core();
     282                 :            :         } else {
     283                 :         19 :             discover_numa_and_core_dummy(dummy_config);
     284                 :            :         }
     285                 :            : 
     286 [ +  + ][ -  + ]:       1248 :         HMAP_FOR_EACH(n, hmap_node, &all_numa_nodes) {
     287         [ +  - ]:        631 :             VLOG_INFO("Discovered %"PRIuSIZE" CPU cores on NUMA node %d",
     288                 :            :                       ovs_list_size(&n->cores), n->numa_id);
     289                 :            :         }
     290                 :            : 
     291         [ +  - ]:        617 :         VLOG_INFO("Discovered %"PRIuSIZE" NUMA nodes and %"PRIuSIZE" CPU cores",
     292                 :            :                    hmap_count(&all_numa_nodes), hmap_count(&all_cpu_cores));
     293                 :            : 
     294 [ +  - ][ +  - ]:        617 :         if (hmap_count(&all_numa_nodes) && hmap_count(&all_cpu_cores)) {
     295                 :        617 :             found_numa_and_core = true;
     296                 :            :         }
     297                 :            : 
     298                 :        617 :         ovsthread_once_done(&once);
     299                 :            : 
     300                 :        617 :         return true;
     301                 :            :     } else {
     302                 :          0 :         return false;
     303                 :            :     }
     304                 :            : }
     305                 :            : 
     306                 :            : /* Extracts the numa node and core info from the 'config'.  This is useful for
     307                 :            :  * testing purposes.  The function must be called once, before ovs_numa_init().
     308                 :            :  *
     309                 :            :  * The format of 'config' is explained in the comment above
     310                 :            :  * discover_numa_and_core_dummy().*/
     311                 :            : void
     312                 :         19 : ovs_numa_set_dummy(const char *config)
     313                 :            : {
     314                 :         19 :     dummy_numa = true;
     315         [ -  + ]:         19 :     ovs_assert(config);
     316                 :         19 :     free(dummy_config);
     317                 :         19 :     dummy_config = xstrdup(config);
     318                 :         19 : }
     319                 :            : 
     320                 :            : /* Initializes the numa module. */
     321                 :            : void
     322                 :        617 : ovs_numa_init(void)
     323                 :            : {
     324         [ +  + ]:        617 :     if (dummy_numa) {
     325                 :         19 :         ovs_numa_init__(dummy_config);
     326                 :            :     } else {
     327                 :        598 :         ovs_numa_init__(NULL);
     328                 :            :     }
     329                 :        617 : }
     330                 :            : 
     331                 :            : bool
     332                 :        166 : ovs_numa_numa_id_is_valid(int numa_id)
     333                 :            : {
     334 [ +  - ][ +  - ]:        166 :     return found_numa_and_core && numa_id < ovs_numa_get_n_numas();
     335                 :            : }
     336                 :            : 
     337                 :            : bool
     338                 :         31 : ovs_numa_core_id_is_valid(unsigned core_id)
     339                 :            : {
     340 [ +  - ][ +  - ]:         31 :     return found_numa_and_core && core_id < ovs_numa_get_n_cores();
     341                 :            : }
     342                 :            : 
     343                 :            : bool
     344                 :          0 : ovs_numa_core_is_pinned(unsigned core_id)
     345                 :            : {
     346                 :          0 :     struct cpu_core *core = get_core_by_core_id(core_id);
     347                 :            : 
     348         [ #  # ]:          0 :     if (core) {
     349                 :          0 :         return core->pinned;
     350                 :            :     }
     351                 :            : 
     352                 :          0 :     return false;
     353                 :            : }
     354                 :            : 
     355                 :            : /* Returns the number of numa nodes. */
     356                 :            : int
     357                 :        166 : ovs_numa_get_n_numas(void)
     358                 :            : {
     359         [ +  - ]:        166 :     return found_numa_and_core ? hmap_count(&all_numa_nodes)
     360                 :            :                                : OVS_NUMA_UNSPEC;
     361                 :            : }
     362                 :            : 
     363                 :            : /* Returns the number of cpu cores. */
     364                 :            : int
     365                 :        643 : ovs_numa_get_n_cores(void)
     366                 :            : {
     367         [ +  - ]:        643 :     return found_numa_and_core ? hmap_count(&all_cpu_cores)
     368                 :            :                                : OVS_CORE_UNSPEC;
     369                 :            : }
     370                 :            : 
     371                 :            : /* Given 'core_id', returns the corresponding numa node id.  Returns
     372                 :            :  * OVS_NUMA_UNSPEC if 'core_id' is invalid. */
     373                 :            : int
     374                 :          0 : ovs_numa_get_numa_id(unsigned core_id)
     375                 :            : {
     376                 :          0 :     struct cpu_core *core = get_core_by_core_id(core_id);
     377                 :            : 
     378         [ #  # ]:          0 :     if (core) {
     379                 :          0 :         return core->numa->numa_id;
     380                 :            :     }
     381                 :            : 
     382                 :          0 :     return OVS_NUMA_UNSPEC;
     383                 :            : }
     384                 :            : 
     385                 :            : /* Returns the number of cpu cores on numa node.  Returns OVS_CORE_UNSPEC
     386                 :            :  * if 'numa_id' is invalid. */
     387                 :            : int
     388                 :          0 : ovs_numa_get_n_cores_on_numa(int numa_id)
     389                 :            : {
     390                 :          0 :     struct numa_node *numa = get_numa_by_numa_id(numa_id);
     391                 :            : 
     392         [ #  # ]:          0 :     if (numa) {
     393                 :          0 :         return ovs_list_size(&numa->cores);
     394                 :            :     }
     395                 :            : 
     396                 :          0 :     return OVS_CORE_UNSPEC;
     397                 :            : }
     398                 :            : 
     399                 :            : /* Returns the number of cpu cores that are available and unpinned
     400                 :            :  * on numa node.  Returns OVS_CORE_UNSPEC if 'numa_id' is invalid. */
     401                 :            : int
     402                 :         34 : ovs_numa_get_n_unpinned_cores_on_numa(int numa_id)
     403                 :            : {
     404                 :         34 :     struct numa_node *numa = get_numa_by_numa_id(numa_id);
     405                 :            : 
     406         [ +  - ]:         34 :     if (numa) {
     407                 :            :         struct cpu_core *core;
     408                 :         34 :         int count = 0;
     409                 :            : 
     410         [ +  + ]:        163 :         LIST_FOR_EACH(core, list_node, &numa->cores) {
     411 [ +  + ][ +  - ]:        129 :             if (core->available && !core->pinned) {
     412                 :         99 :                 count++;
     413                 :            :             }
     414                 :            :         }
     415                 :         34 :         return count;
     416                 :            :     }
     417                 :            : 
     418                 :          0 :     return OVS_CORE_UNSPEC;
     419                 :            : }
     420                 :            : 
     421                 :            : /* Given 'core_id', tries to pin that core.  Returns true, if succeeds.
     422                 :            :  * False, if the core has already been pinned, or if it is invalid or
     423                 :            :  * not available. */
     424                 :            : bool
     425                 :          0 : ovs_numa_try_pin_core_specific(unsigned core_id)
     426                 :            : {
     427                 :          0 :     struct cpu_core *core = get_core_by_core_id(core_id);
     428                 :            : 
     429         [ #  # ]:          0 :     if (core) {
     430 [ #  # ][ #  # ]:          0 :         if (core->available && !core->pinned) {
     431                 :          0 :             core->pinned = true;
     432                 :          0 :             return true;
     433                 :            :         }
     434                 :            :     }
     435                 :            : 
     436                 :          0 :     return false;
     437                 :            : }
     438                 :            : 
     439                 :            : /* Searches through all cores for an unpinned and available core.  Returns
     440                 :            :  * the 'core_id' if found and sets the 'core->pinned' to true.  Otherwise,
     441                 :            :  * returns OVS_CORE_UNSPEC. */
     442                 :            : unsigned
     443                 :          0 : ovs_numa_get_unpinned_core_any(void)
     444                 :            : {
     445                 :            :     struct cpu_core *core;
     446                 :            : 
     447 [ #  # ][ #  # ]:          0 :     HMAP_FOR_EACH(core, hmap_node, &all_cpu_cores) {
     448 [ #  # ][ #  # ]:          0 :         if (core->available && !core->pinned) {
     449                 :          0 :             core->pinned = true;
     450                 :          0 :             return core->core_id;
     451                 :            :         }
     452                 :            :     }
     453                 :            : 
     454                 :          0 :     return OVS_CORE_UNSPEC;
     455                 :            : }
     456                 :            : 
     457                 :            : /* Searches through all cores on numa node with 'numa_id' for an
     458                 :            :  * unpinned and available core.  Returns the core_id if found and
     459                 :            :  * sets the 'core->pinned' to true.  Otherwise, returns OVS_CORE_UNSPEC. */
     460                 :            : unsigned
     461                 :         53 : ovs_numa_get_unpinned_core_on_numa(int numa_id)
     462                 :            : {
     463                 :         53 :     struct numa_node *numa = get_numa_by_numa_id(numa_id);
     464                 :            : 
     465         [ +  - ]:         53 :     if (numa) {
     466                 :            :         struct cpu_core *core;
     467                 :            : 
     468         [ +  - ]:        137 :         LIST_FOR_EACH(core, list_node, &numa->cores) {
     469 [ +  + ][ +  + ]:        137 :             if (core->available && !core->pinned) {
     470                 :         53 :                 core->pinned = true;
     471                 :         53 :                 return core->core_id;
     472                 :            :             }
     473                 :            :         }
     474                 :            :     }
     475                 :            : 
     476                 :          0 :     return OVS_CORE_UNSPEC;
     477                 :            : }
     478                 :            : 
     479                 :            : /* Unpins the core with 'core_id'. */
     480                 :            : void
     481                 :         31 : ovs_numa_unpin_core(unsigned core_id)
     482                 :            : {
     483                 :         31 :     struct cpu_core *core = get_core_by_core_id(core_id);
     484                 :            : 
     485         [ +  - ]:         31 :     if (core) {
     486                 :         31 :         core->pinned = false;
     487                 :            :     }
     488                 :         31 : }
     489                 :            : 
     490                 :            : /* Given the 'numa_id', returns dump of all cores on the numa node. */
     491                 :            : struct ovs_numa_dump *
     492                 :          0 : ovs_numa_dump_cores_on_numa(int numa_id)
     493                 :            : {
     494                 :          0 :     struct ovs_numa_dump *dump = xmalloc(sizeof *dump);
     495                 :          0 :     struct numa_node *numa = get_numa_by_numa_id(numa_id);
     496                 :            : 
     497                 :          0 :     ovs_list_init(&dump->dump);
     498                 :            : 
     499         [ #  # ]:          0 :     if (numa) {
     500                 :            :         struct cpu_core *core;
     501                 :            : 
     502         [ #  # ]:          0 :         LIST_FOR_EACH(core, list_node, &numa->cores) {
     503                 :          0 :             struct ovs_numa_info *info = xmalloc(sizeof *info);
     504                 :            : 
     505                 :          0 :             info->numa_id = numa->numa_id;
     506                 :          0 :             info->core_id = core->core_id;
     507                 :          0 :             ovs_list_insert(&dump->dump, &info->list_node);
     508                 :            :         }
     509                 :            :     }
     510                 :            : 
     511                 :          0 :     return dump;
     512                 :            : }
     513                 :            : 
     514                 :            : void
     515                 :          0 : ovs_numa_dump_destroy(struct ovs_numa_dump *dump)
     516                 :            : {
     517                 :            :     struct ovs_numa_info *iter;
     518                 :            : 
     519         [ #  # ]:          0 :     if (!dump) {
     520                 :          0 :         return;
     521                 :            :     }
     522                 :            : 
     523         [ #  # ]:          0 :     LIST_FOR_EACH_POP (iter, list_node, &dump->dump) {
     524                 :          0 :         free(iter);
     525                 :            :     }
     526                 :            : 
     527                 :          0 :     free(dump);
     528                 :            : }
     529                 :            : 
     530                 :            : /* Reads the cpu mask configuration from 'cmask' and sets the
     531                 :            :  * 'available' of corresponding cores.  For unspecified cores,
     532                 :            :  * sets 'available' to false. */
     533                 :            : void
     534                 :         14 : ovs_numa_set_cpu_mask(const char *cmask)
     535                 :            : {
     536                 :         14 :     int core_id = 0;
     537                 :            :     int i;
     538                 :            : 
     539         [ -  + ]:         14 :     if (!found_numa_and_core) {
     540                 :          0 :         return;
     541                 :            :     }
     542                 :            : 
     543                 :            :     /* If no mask specified, resets the 'available' to true for all cores. */
     544         [ +  + ]:         14 :     if (!cmask) {
     545                 :            :         struct cpu_core *core;
     546                 :            : 
     547 [ +  + ][ -  + ]:         11 :         HMAP_FOR_EACH(core, hmap_node, &all_cpu_cores) {
     548                 :          9 :             core->available = true;
     549                 :            :         }
     550                 :            : 
     551                 :          2 :         return;
     552                 :            :     }
     553                 :            : 
     554         [ +  + ]:         21 :     for (i = strlen(cmask) - 1; i >= 0; i--) {
     555                 :         16 :         char hex = toupper((unsigned char)cmask[i]);
     556                 :            :         int bin, j;
     557                 :            : 
     558 [ +  - ][ +  + ]:         16 :         if (hex >= '0' && hex <= '9') {
     559                 :         12 :             bin = hex - '0';
     560 [ +  - ][ +  - ]:          4 :         } else if (hex >= 'A' && hex <= 'F') {
     561                 :          4 :             bin = hex - 'A' + 10;
     562                 :            :         } else {
     563                 :          0 :             bin = 0;
     564         [ #  # ]:          0 :             VLOG_WARN("Invalid cpu mask: %c", cmask[i]);
     565                 :            :         }
     566                 :            : 
     567         [ +  + ]:         57 :         for (j = 0; j < 4; j++) {
     568                 :            :             struct cpu_core *core;
     569                 :            : 
     570                 :         48 :             core = CONTAINER_OF(hmap_first_with_hash(&all_cpu_cores,
     571                 :            :                                                      hash_int(core_id++, 0)),
     572                 :            :                                 struct cpu_core, hmap_node);
     573                 :         48 :             core->available = (bin >> j) & 0x1;
     574                 :            : 
     575         [ +  + ]:         48 :             if (core_id >= hmap_count(&all_cpu_cores)) {
     576                 :          7 :                 return;
     577                 :            :             }
     578                 :            :     }
     579                 :            :     }
     580                 :            : 
     581                 :            :     /* For unspecified cores, sets 'available' to false.  */
     582         [ +  + ]:         28 :     while (core_id < hmap_count(&all_cpu_cores)) {
     583                 :            :         struct cpu_core *core;
     584                 :            : 
     585                 :         23 :         core = CONTAINER_OF(hmap_first_with_hash(&all_cpu_cores,
     586                 :            :                                                  hash_int(core_id++, 0)),
     587                 :            :                             struct cpu_core, hmap_node);
     588                 :         23 :         core->available = false;
     589                 :            :     }
     590                 :            : }
     591                 :            : 
     592                 :         53 : int ovs_numa_thread_setaffinity_core(unsigned core_id OVS_UNUSED)
     593                 :            : {
     594         [ +  - ]:         53 :     if (dummy_numa) {
     595                 :            :         /* Nothing to do */
     596                 :         53 :         return 0;
     597                 :            :     }
     598                 :            : 
     599                 :            : #ifdef __linux__
     600                 :            :     cpu_set_t cpuset;
     601                 :            :     int err;
     602                 :            : 
     603                 :          0 :     CPU_ZERO(&cpuset);
     604         [ #  # ]:          0 :     CPU_SET(core_id, &cpuset);
     605                 :          0 :     err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
     606         [ #  # ]:          0 :     if (err) {
     607         [ #  # ]:          0 :         VLOG_ERR("Thread affinity error %d",err);
     608                 :          0 :         return err;
     609                 :            :     }
     610                 :            : 
     611                 :         53 :     return 0;
     612                 :            : #else /* !__linux__ */
     613                 :            :     return EOPNOTSUPP;
     614                 :            : #endif /* __linux__ */
     615                 :            : }

Generated by: LCOV version 1.12