LCOV - code coverage report
Current view: top level - lib/util - cpuset.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 177 184 96.2 %
Date: 2024-12-16 14:02:50 Functions: 19 19 100.0 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2017 Intel Corporation. All rights reserved.
       3             :  *   All rights reserved.
       4             :  */
       5             : 
       6             : #include "spdk/cpuset.h"
       7             : #include "spdk/log.h"
       8             : 
       9             : struct spdk_cpuset *
      10           3 : spdk_cpuset_alloc(void)
      11             : {
      12           3 :         return (struct spdk_cpuset *)calloc(1, sizeof(struct spdk_cpuset));
      13             : }
      14             : 
      15             : void
      16           3 : spdk_cpuset_free(struct spdk_cpuset *set)
      17             : {
      18           3 :         free(set);
      19           3 : }
      20             : 
      21             : bool
      22           3 : spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2)
      23             : {
      24           3 :         assert(set1 != NULL);
      25           3 :         assert(set2 != NULL);
      26           3 :         return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0;
      27             : }
      28             : 
      29             : void
      30          31 : spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
      31             : {
      32          31 :         assert(dst != NULL);
      33          31 :         assert(src != NULL);
      34          31 :         memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus));
      35          31 : }
      36             : 
      37             : void
      38         179 : spdk_cpuset_negate(struct spdk_cpuset *set)
      39             : {
      40             :         unsigned int i;
      41         179 :         assert(set != NULL);
      42       23091 :         for (i = 0; i < sizeof(set->cpus); i++) {
      43       22912 :                 set->cpus[i] = ~set->cpus[i];
      44       22912 :         }
      45         179 : }
      46             : 
      47             : void
      48          13 : spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
      49             : {
      50             :         unsigned int i;
      51          13 :         assert(dst != NULL);
      52          13 :         assert(src != NULL);
      53        1677 :         for (i = 0; i < sizeof(src->cpus); i++) {
      54        1664 :                 dst->cpus[i] &= src->cpus[i];
      55        1664 :         }
      56          13 : }
      57             : 
      58             : void
      59           3 : spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
      60             : {
      61             :         unsigned int i;
      62           3 :         assert(dst != NULL);
      63           3 :         assert(src != NULL);
      64         387 :         for (i = 0; i < sizeof(src->cpus); i++) {
      65         384 :                 dst->cpus[i] |= src->cpus[i];
      66         384 :         }
      67           3 : }
      68             : 
      69             : void
      70          18 : spdk_cpuset_xor(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
      71             : {
      72             :         unsigned int i;
      73          18 :         assert(dst != NULL);
      74          18 :         assert(src != NULL);
      75        2322 :         for (i = 0; i < sizeof(src->cpus); i++) {
      76        2304 :                 dst->cpus[i] ^= src->cpus[i];
      77        2304 :         }
      78          18 : }
      79             : 
      80             : void
      81          77 : spdk_cpuset_zero(struct spdk_cpuset *set)
      82             : {
      83          77 :         assert(set != NULL);
      84          77 :         memset(set->cpus, 0, sizeof(set->cpus));
      85          77 : }
      86             : 
      87             : void
      88        3350 : spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state)
      89             : {
      90        3350 :         assert(set != NULL);
      91        3350 :         assert(cpu < sizeof(set->cpus) * 8);
      92        3350 :         if (state) {
      93        3349 :                 set->cpus[cpu / 8] |= (1U << (cpu % 8));
      94        3349 :         } else {
      95           1 :                 set->cpus[cpu / 8] &= ~(1U << (cpu % 8));
      96             :         }
      97        3350 : }
      98             : 
      99             : bool
     100       19531 : spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu)
     101             : {
     102       19531 :         assert(set != NULL);
     103       19531 :         assert(cpu < sizeof(set->cpus) * 8);
     104       19531 :         return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U;
     105             : }
     106             : 
     107             : void
     108          21 : spdk_cpuset_for_each_cpu(const struct spdk_cpuset *set,
     109             :                          void (*fn)(void *ctx, uint32_t cpu), void *ctx)
     110             : {
     111             :         uint8_t n;
     112             :         unsigned int i, j;
     113        2709 :         for (i = 0; i < sizeof(set->cpus); i++) {
     114        2688 :                 n = set->cpus[i];
     115       24192 :                 for (j = 0; j < 8; j++) {
     116       21504 :                         if (n & (1 << j)) {
     117        1056 :                                 fn(ctx, i * 8 + j);
     118        1056 :                         }
     119       21504 :                 }
     120        2688 :         }
     121          21 : }
     122             : 
     123             : static void
     124        1043 : count_fn(void *ctx, uint32_t cpu)
     125             : {
     126        1043 :         uint32_t *count = ctx;
     127             : 
     128        1043 :         (*count)++;
     129        1043 : }
     130             : 
     131             : uint32_t
     132          20 : spdk_cpuset_count(const struct spdk_cpuset *set)
     133             : {
     134          20 :         uint32_t count = 0;
     135             : 
     136          20 :         spdk_cpuset_for_each_cpu(set, count_fn, &count);
     137          20 :         return count;
     138             : }
     139             : 
     140             : const char *
     141           3 : spdk_cpuset_fmt(struct spdk_cpuset *set)
     142             : {
     143           3 :         uint32_t lcore, lcore_max = 0;
     144             :         int val, i, n;
     145             :         char *ptr;
     146             :         static const char *hex = "0123456789abcdef";
     147             : 
     148           3 :         assert(set != NULL);
     149             : 
     150        3075 :         for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) {
     151        3072 :                 if (spdk_cpuset_get_cpu(set, lcore)) {
     152        1031 :                         lcore_max = lcore;
     153        1031 :                 }
     154        3072 :         }
     155             : 
     156           3 :         ptr = set->str;
     157           3 :         n = lcore_max / 8;
     158           3 :         val = set->cpus[n];
     159             : 
     160             :         /* Store first number only if it is not leading zero */
     161           3 :         if ((val & 0xf0) != 0) {
     162           1 :                 *(ptr++) = hex[(val & 0xf0) >> 4];
     163           1 :         }
     164           3 :         *(ptr++) = hex[val & 0x0f];
     165             : 
     166         132 :         for (i = n - 1; i >= 0; i--) {
     167         129 :                 val = set->cpus[i];
     168         129 :                 *(ptr++) = hex[(val & 0xf0) >> 4];
     169         129 :                 *(ptr++) = hex[val & 0x0f];
     170         129 :         }
     171           3 :         *ptr = '\0';
     172             : 
     173           3 :         return set->str;
     174             : }
     175             : 
     176             : static int
     177          75 : hex_value(uint8_t c)
     178             : {
     179             : #define V(x, y) [x] = y + 1
     180             :         static const int8_t val[256] = {
     181             :                 V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4),
     182             :                 V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9),
     183             :                 V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF),
     184             :                 V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF),
     185             :         };
     186             : #undef V
     187             : 
     188          75 :         return val[c] - 1;
     189             : }
     190             : 
     191             : static int
     192          11 : parse_list(const char *mask, struct spdk_cpuset *set)
     193             : {
     194             :         char *end;
     195          11 :         const char *ptr = mask;
     196             :         uint32_t lcore;
     197             :         uint32_t lcore_min, lcore_max;
     198             : 
     199          11 :         spdk_cpuset_zero(set);
     200          11 :         lcore_min = UINT32_MAX;
     201             : 
     202          11 :         ptr++;
     203          11 :         end = (char *)ptr;
     204          11 :         do {
     205          20 :                 while (isblank(*ptr)) {
     206           0 :                         ptr++;
     207             :                 }
     208          20 :                 if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') {
     209           5 :                         goto invalid_character;
     210             :                 }
     211             : 
     212          15 :                 errno = 0;
     213          15 :                 lcore = strtoul(ptr, &end, 10);
     214          15 :                 if (errno) {
     215           1 :                         SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask);
     216           1 :                         return -1;
     217             :                 }
     218             : 
     219          14 :                 if (lcore >= sizeof(set->cpus) * 8) {
     220           1 :                         SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask);
     221           1 :                         return -1;
     222             :                 }
     223             : 
     224          13 :                 while (isblank(*end)) {
     225           0 :                         end++;
     226             :                 }
     227             : 
     228          13 :                 if (*end == '-') {
     229           6 :                         lcore_min = lcore;
     230          13 :                 } else if (*end == ',' || *end == ']') {
     231           7 :                         lcore_max = lcore;
     232           7 :                         if (lcore_min == UINT32_MAX) {
     233           2 :                                 lcore_min = lcore;
     234           2 :                         }
     235           7 :                         if (lcore_min > lcore_max) {
     236           1 :                                 SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n",
     237             :                                             lcore_min, lcore_max);
     238           1 :                                 return -1;
     239             :                         }
     240        1172 :                         for (lcore = lcore_min; lcore <= lcore_max; lcore++) {
     241        1166 :                                 spdk_cpuset_set_cpu(set, lcore, true);
     242        1166 :                         }
     243           6 :                         lcore_min = UINT32_MAX;
     244           6 :                 } else {
     245           0 :                         goto invalid_character;
     246             :                 }
     247             : 
     248          12 :                 ptr = end + 1;
     249             : 
     250          12 :         } while (*end != ']');
     251             : 
     252           3 :         return 0;
     253             : 
     254             : invalid_character:
     255           5 :         if (*end == '\0') {
     256           1 :                 SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask);
     257           1 :         } else {
     258           4 :                 SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end);
     259             :         }
     260           5 :         return -1;
     261          11 : }
     262             : 
     263             : static int
     264           5 : parse_mask(const char *mask, struct spdk_cpuset *set, size_t len)
     265             : {
     266             :         int i, j;
     267             :         char c;
     268             :         int val;
     269           5 :         uint32_t lcore = 0;
     270             : 
     271           5 :         if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) {
     272           3 :                 mask += 2;
     273           3 :                 len -= 2;
     274           3 :         }
     275             : 
     276           5 :         spdk_cpuset_zero(set);
     277          95 :         for (i = len - 1; i >= 0; i--) {
     278          90 :                 c = mask[i];
     279          90 :                 if (c == ',') {
     280             :                         /* Linux puts comma delimiters in its cpumasks, just skip them. */
     281          15 :                         continue;
     282             :                 }
     283          75 :                 val = hex_value(c);
     284          75 :                 if (val < 0) {
     285             :                         /* Invalid character */
     286           0 :                         SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c);
     287           0 :                         return -1;
     288             :                 }
     289         375 :                 for (j = 0; j < 4 && lcore < SPDK_CPUSET_SIZE; j++, lcore++) {
     290         300 :                         if ((1 << j) & val) {
     291          47 :                                 spdk_cpuset_set_cpu(set, lcore, true);
     292          47 :                         }
     293         300 :                 }
     294          75 :         }
     295             : 
     296           5 :         return 0;
     297           5 : }
     298             : 
     299             : int
     300          19 : spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask)
     301             : {
     302             :         int ret;
     303             :         size_t len;
     304             : 
     305          19 :         if (mask == NULL || set == NULL) {
     306           2 :                 return -1;
     307             :         }
     308             : 
     309          17 :         while (isblank(*mask)) {
     310           0 :                 mask++;
     311             :         }
     312             : 
     313          17 :         len = strlen(mask);
     314          17 :         while (len > 0 && isblank(mask[len - 1])) {
     315           0 :                 len--;
     316             :         }
     317             : 
     318          17 :         if (len == 0) {
     319           1 :                 return -1;
     320             :         }
     321             : 
     322          16 :         if (mask[0] == '[') {
     323          11 :                 ret = parse_list(mask, set);
     324          11 :         } else {
     325           5 :                 ret = parse_mask(mask, set, len);
     326             :         }
     327             : 
     328          16 :         return ret;
     329          19 : }

Generated by: LCOV version 1.15