LCOV - code coverage report
Current view: top level - spdk/lib/trace - trace_flags.c (source / functions) Hit Total Coverage
Test: Combined Lines: 137 204 67.2 %
Date: 2024-07-13 19:46:08 Functions: 16 21 76.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 109 205 53.2 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2017 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : 
       8                 :            : #include "spdk/env.h"
       9                 :            : #include "spdk/trace.h"
      10                 :            : #include "spdk/log.h"
      11                 :            : #include "spdk/util.h"
      12                 :            : 
      13                 :            : struct spdk_trace_flags *g_trace_flags = NULL;
      14                 :            : static struct spdk_trace_register_fn *g_reg_fn_head = NULL;
      15                 :            : 
      16                 :       3848 : SPDK_LOG_REGISTER_COMPONENT(trace)
      17                 :            : 
      18                 :            : uint64_t
      19                 :        609 : spdk_trace_get_tpoint_mask(uint32_t group_id)
      20                 :            : {
      21         [ -  + ]:        609 :         if (group_id >= SPDK_TRACE_MAX_GROUP_ID) {
      22                 :          0 :                 SPDK_ERRLOG("invalid group ID %d\n", group_id);
      23                 :          0 :                 return 0ULL;
      24                 :            :         }
      25                 :            : 
      26         [ -  + ]:        609 :         if (g_trace_flags == NULL) {
      27                 :          0 :                 return 0ULL;
      28                 :            :         }
      29                 :            : 
      30                 :        609 :         return g_trace_flags->tpoint_mask[group_id];
      31                 :            : }
      32                 :            : 
      33                 :            : void
      34                 :       2993 : spdk_trace_set_tpoints(uint32_t group_id, uint64_t tpoint_mask)
      35                 :            : {
      36         [ -  + ]:       2993 :         if (g_trace_flags == NULL) {
      37                 :          0 :                 SPDK_ERRLOG("trace is not initialized\n");
      38                 :          0 :                 return;
      39                 :            :         }
      40                 :            : 
      41         [ -  + ]:       2993 :         if (group_id >= SPDK_TRACE_MAX_GROUP_ID) {
      42                 :          0 :                 SPDK_ERRLOG("invalid group ID %d\n", group_id);
      43                 :          0 :                 return;
      44                 :            :         }
      45                 :            : 
      46                 :       2993 :         g_trace_flags->tpoint_mask[group_id] |= tpoint_mask;
      47                 :            : }
      48                 :            : 
      49                 :            : void
      50                 :          0 : spdk_trace_clear_tpoints(uint32_t group_id, uint64_t tpoint_mask)
      51                 :            : {
      52         [ #  # ]:          0 :         if (g_trace_flags == NULL) {
      53                 :          0 :                 SPDK_ERRLOG("trace is not initialized\n");
      54                 :          0 :                 return;
      55                 :            :         }
      56                 :            : 
      57         [ #  # ]:          0 :         if (group_id >= SPDK_TRACE_MAX_GROUP_ID) {
      58                 :          0 :                 SPDK_ERRLOG("invalid group ID %d\n", group_id);
      59                 :          0 :                 return;
      60                 :            :         }
      61                 :            : 
      62                 :          0 :         g_trace_flags->tpoint_mask[group_id] &= ~tpoint_mask;
      63                 :            : }
      64                 :            : 
      65                 :            : uint64_t
      66                 :         21 : spdk_trace_get_tpoint_group_mask(void)
      67                 :            : {
      68                 :         21 :         uint64_t mask = 0x0;
      69                 :            :         int i;
      70                 :            : 
      71         [ +  + ]:        357 :         for (i = 0; i < SPDK_TRACE_MAX_GROUP_ID; i++) {
      72         [ +  + ]:        336 :                 if (spdk_trace_get_tpoint_mask(i) != 0) {
      73         [ -  + ]:         21 :                         mask |= (1ULL << i);
      74                 :            :                 }
      75                 :            :         }
      76                 :            : 
      77                 :         21 :         return mask;
      78                 :            : }
      79                 :            : 
      80                 :            : void
      81                 :          0 : spdk_trace_set_tpoint_group_mask(uint64_t tpoint_group_mask)
      82                 :            : {
      83                 :            :         int i;
      84                 :            : 
      85         [ #  # ]:          0 :         if (g_trace_flags == NULL) {
      86                 :          0 :                 SPDK_ERRLOG("trace is not initialized\n");
      87                 :          0 :                 return;
      88                 :            :         }
      89                 :            : 
      90         [ #  # ]:          0 :         for (i = 0; i < SPDK_TRACE_MAX_GROUP_ID; i++) {
      91   [ #  #  #  # ]:          0 :                 if (tpoint_group_mask & (1ULL << i)) {
      92                 :          0 :                         spdk_trace_set_tpoints(i, -1ULL);
      93                 :            :                 }
      94                 :            :         }
      95                 :            : }
      96                 :            : 
      97                 :            : void
      98                 :          0 : spdk_trace_clear_tpoint_group_mask(uint64_t tpoint_group_mask)
      99                 :            : {
     100                 :            :         int i;
     101                 :            : 
     102         [ #  # ]:          0 :         if (g_trace_flags == NULL) {
     103                 :          0 :                 SPDK_ERRLOG("trace is not initialized\n");
     104                 :          0 :                 return;
     105                 :            :         }
     106                 :            : 
     107         [ #  # ]:          0 :         for (i = 0; i < SPDK_TRACE_MAX_GROUP_ID; i++) {
     108   [ #  #  #  # ]:          0 :                 if (tpoint_group_mask & (1ULL << i)) {
     109                 :          0 :                         spdk_trace_clear_tpoints(i, -1ULL);
     110                 :            :                 }
     111                 :            :         }
     112                 :            : }
     113                 :            : 
     114                 :            : struct spdk_trace_register_fn *
     115                 :         45 : spdk_trace_get_first_register_fn(void)
     116                 :            : {
     117                 :         45 :         return g_reg_fn_head;
     118                 :            : }
     119                 :            : 
     120                 :            : struct spdk_trace_register_fn *
     121                 :        339 : spdk_trace_get_next_register_fn(struct spdk_trace_register_fn *register_fn)
     122                 :            : {
     123                 :        339 :         return register_fn->next;
     124                 :            : }
     125                 :            : 
     126                 :            : uint64_t
     127                 :         24 : spdk_trace_create_tpoint_group_mask(const char *group_name)
     128                 :            : {
     129                 :         24 :         uint64_t tpoint_group_mask = 0;
     130                 :            :         struct spdk_trace_register_fn *register_fn;
     131                 :            : 
     132                 :         24 :         register_fn = spdk_trace_get_first_register_fn();
     133   [ -  +  +  + ]:         24 :         if (strcmp(group_name, "all") == 0) {
     134         [ +  + ]:         24 :                 while (register_fn) {
     135         [ -  + ]:         22 :                         tpoint_group_mask |= (1UL << register_fn->tgroup_id);
     136                 :            : 
     137                 :         22 :                         register_fn = spdk_trace_get_next_register_fn(register_fn);
     138                 :            :                 }
     139                 :            :         } else {
     140         [ +  - ]:         66 :                 while (register_fn) {
     141   [ +  +  -  +  :         66 :                         if (strcmp(group_name, register_fn->name) == 0) {
                   +  + ]
     142                 :         22 :                                 break;
     143                 :            :                         }
     144                 :            : 
     145                 :         44 :                         register_fn = spdk_trace_get_next_register_fn(register_fn);
     146                 :            :                 }
     147                 :            : 
     148         [ +  - ]:         22 :                 if (register_fn != NULL) {
     149         [ -  + ]:         22 :                         tpoint_group_mask |= (1UL << register_fn->tgroup_id);
     150                 :            :                 }
     151                 :            :         }
     152                 :            : 
     153                 :         24 :         return tpoint_group_mask;
     154                 :            : }
     155                 :            : 
     156                 :            : int
     157                 :          0 : spdk_trace_enable_tpoint_group(const char *group_name)
     158                 :            : {
     159                 :          0 :         uint64_t tpoint_group_mask = 0;
     160                 :            : 
     161         [ #  # ]:          0 :         if (g_trace_flags == NULL) {
     162                 :          0 :                 return -1;
     163                 :            :         }
     164                 :            : 
     165                 :          0 :         tpoint_group_mask = spdk_trace_create_tpoint_group_mask(group_name);
     166         [ #  # ]:          0 :         if (tpoint_group_mask == 0) {
     167                 :          0 :                 return -1;
     168                 :            :         }
     169                 :            : 
     170                 :          0 :         spdk_trace_set_tpoint_group_mask(tpoint_group_mask);
     171                 :          0 :         return 0;
     172                 :            : }
     173                 :            : 
     174                 :            : int
     175                 :          0 : spdk_trace_disable_tpoint_group(const char *group_name)
     176                 :            : {
     177                 :          0 :         uint64_t tpoint_group_mask = 0;
     178                 :            : 
     179         [ #  # ]:          0 :         if (g_trace_flags == NULL) {
     180                 :          0 :                 return -1;
     181                 :            :         }
     182                 :            : 
     183                 :          0 :         tpoint_group_mask = spdk_trace_create_tpoint_group_mask(group_name);
     184         [ #  # ]:          0 :         if (tpoint_group_mask == 0) {
     185                 :          0 :                 return -1;
     186                 :            :         }
     187                 :            : 
     188                 :          0 :         spdk_trace_clear_tpoint_group_mask(tpoint_group_mask);
     189                 :          0 :         return 0;
     190                 :            : }
     191                 :            : 
     192                 :            : void
     193                 :         48 : spdk_trace_mask_usage(FILE *f, const char *tmask_arg)
     194                 :            : {
     195                 :            :         struct spdk_trace_register_fn *register_fn;
     196                 :         48 :         bool first_group_name = true;
     197                 :            : 
     198   [ -  +  -  + ]:         48 :         fprintf(f, " %s, --tpoint-group <group-name>[:<tpoint_mask>]\n", tmask_arg);
     199   [ -  +  -  + ]:         48 :         fprintf(f, "                           group_name - tracepoint group name ");
     200   [ -  +  -  + ]:         48 :         fprintf(f, "for spdk trace buffers (");
     201                 :            : 
     202                 :         48 :         register_fn = g_reg_fn_head;
     203         [ +  + ]:        213 :         while (register_fn) {
     204         [ +  + ]:        165 :                 if (first_group_name) {
     205   [ -  +  -  + ]:         48 :                         fprintf(f, "%s", register_fn->name);
     206                 :         48 :                         first_group_name = false;
     207                 :            :                 } else {
     208   [ -  +  -  + ]:        117 :                         fprintf(f, ", %s", register_fn->name);
     209                 :            :                 }
     210                 :        165 :                 register_fn = register_fn->next;
     211                 :            :         }
     212                 :            : 
     213   [ -  +  -  + ]:         48 :         fprintf(f, ", all)\n");
     214   [ -  +  -  + ]:         48 :         fprintf(f, "                           tpoint_mask - tracepoint mask for enabling individual");
     215   [ -  +  -  + ]:         48 :         fprintf(f, " tpoints inside a tracepoint group.");
     216   [ -  +  -  + ]:         48 :         fprintf(f, " First tpoint inside a group can be");
     217   [ -  +  -  + ]:         48 :         fprintf(f, " enabled by setting tpoint_mask to 1 (e.g. bdev:0x1).\n");
     218   [ -  +  -  + ]:         48 :         fprintf(f, "                            Groups and masks can be combined (e.g.");
     219   [ -  +  -  + ]:         48 :         fprintf(f, " thread,bdev:0x1).\n");
     220   [ -  +  -  + ]:         48 :         fprintf(f, "                            All available tpoints can be found in");
     221   [ -  +  -  + ]:         48 :         fprintf(f, " /include/spdk_internal/trace_defs.h\n");
     222                 :         48 : }
     223                 :            : 
     224                 :            : void
     225                 :       9649 : spdk_trace_register_owner(uint8_t type, char id_prefix)
     226                 :            : {
     227                 :            :         struct spdk_trace_owner *owner;
     228                 :            : 
     229         [ -  + ]:       9649 :         assert(type != OWNER_NONE);
     230                 :            : 
     231         [ -  + ]:       9649 :         if (g_trace_flags == NULL) {
     232                 :          0 :                 SPDK_ERRLOG("trace is not initialized\n");
     233                 :          0 :                 return;
     234                 :            :         }
     235                 :            : 
     236                 :            :         /* 'owner' has 256 entries and since 'type' is a uint8_t, it
     237                 :            :          * can't overrun the array.
     238                 :            :          */
     239                 :       9649 :         owner = &g_trace_flags->owner[type];
     240         [ -  + ]:       9649 :         assert(owner->type == 0);
     241                 :            : 
     242                 :       9649 :         owner->type = type;
     243                 :       9649 :         owner->id_prefix = id_prefix;
     244                 :            : }
     245                 :            : 
     246                 :            : void
     247                 :      10347 : spdk_trace_register_object(uint8_t type, char id_prefix)
     248                 :            : {
     249                 :            :         struct spdk_trace_object *object;
     250                 :            : 
     251         [ -  + ]:      10347 :         assert(type != OBJECT_NONE);
     252                 :            : 
     253         [ -  + ]:      10347 :         if (g_trace_flags == NULL) {
     254                 :          0 :                 SPDK_ERRLOG("trace is not initialized\n");
     255                 :          0 :                 return;
     256                 :            :         }
     257                 :            : 
     258                 :            :         /* 'object' has 256 entries and since 'type' is a uint8_t, it
     259                 :            :          * can't overrun the array.
     260                 :            :          */
     261                 :      10347 :         object = &g_trace_flags->object[type];
     262         [ -  + ]:      10347 :         assert(object->type == 0);
     263                 :            : 
     264                 :      10347 :         object->type = type;
     265                 :      10347 :         object->id_prefix = id_prefix;
     266                 :            : }
     267                 :            : 
     268                 :            : static void
     269                 :     155862 : trace_register_description(const struct spdk_trace_tpoint_opts *opts)
     270                 :            : {
     271                 :            :         struct spdk_trace_tpoint *tpoint;
     272                 :            :         size_t i, max_name_length;
     273                 :            : 
     274         [ -  + ]:     155862 :         assert(opts->tpoint_id != 0);
     275         [ -  + ]:     155862 :         assert(opts->tpoint_id < SPDK_TRACE_MAX_TPOINT_ID);
     276                 :            : 
     277   [ +  +  +  + ]:     155862 :         if (strnlen(opts->name, sizeof(tpoint->name)) == sizeof(tpoint->name)) {
     278                 :        698 :                 SPDK_ERRLOG("name (%s) too long\n", opts->name);
     279                 :            :         }
     280                 :            : 
     281                 :     155862 :         tpoint = &g_trace_flags->tpoint[opts->tpoint_id];
     282         [ -  + ]:     155862 :         assert(tpoint->tpoint_id == 0);
     283                 :            : 
     284                 :     155862 :         snprintf(tpoint->name, sizeof(tpoint->name), "%s", opts->name);
     285                 :     155862 :         tpoint->tpoint_id = opts->tpoint_id;
     286                 :     155862 :         tpoint->object_type = opts->object_type;
     287                 :     155862 :         tpoint->owner_type = opts->owner_type;
     288                 :     155862 :         tpoint->new_object = opts->new_object;
     289                 :            : 
     290                 :     155862 :         max_name_length = sizeof(tpoint->args[0].name);
     291         [ +  - ]:     341426 :         for (i = 0; i < SPDK_TRACE_MAX_ARGS_COUNT; ++i) {
     292   [ +  +  +  + ]:     341426 :                 if (!opts->args[i].name || opts->args[i].name[0] == '\0') {
     293                 :            :                         break;
     294                 :            :                 }
     295                 :            : 
     296      [ +  +  - ]:     185564 :                 switch (opts->args[i].type) {
     297                 :     168119 :                 case SPDK_TRACE_ARG_TYPE_INT:
     298                 :            :                 case SPDK_TRACE_ARG_TYPE_PTR:
     299                 :            :                         /* The integers and pointers have to be exactly 4 or 8 bytes */
     300   [ +  +  -  + ]:     168119 :                         assert(opts->args[i].size == 4 || opts->args[i].size == 8);
     301                 :     168119 :                         break;
     302                 :      17445 :                 case SPDK_TRACE_ARG_TYPE_STR:
     303                 :            :                         /* Strings need to have at least one byte for the NULL terminator */
     304         [ -  + ]:      17445 :                         assert(opts->args[i].size > 0);
     305                 :      17445 :                         break;
     306                 :          0 :                 default:
     307                 :          0 :                         assert(0 && "invalid trace argument type");
     308                 :            :                         break;
     309                 :            :                 }
     310                 :            : 
     311   [ -  +  -  + ]:     185564 :                 if (strnlen(opts->args[i].name, max_name_length) == max_name_length) {
     312                 :          0 :                         SPDK_ERRLOG("argument name (%s) is too long\n", opts->args[i].name);
     313                 :            :                 }
     314                 :            : 
     315                 :     185564 :                 snprintf(tpoint->args[i].name, sizeof(tpoint->args[i].name),
     316                 :     156793 :                          "%s", opts->args[i].name);
     317                 :     185564 :                 tpoint->args[i].type = opts->args[i].type;
     318                 :     185564 :                 tpoint->args[i].size = opts->args[i].size;
     319                 :            :         }
     320                 :            : 
     321                 :     155862 :         tpoint->num_args = i;
     322                 :     155862 : }
     323                 :            : 
     324                 :            : void
     325                 :     134610 : spdk_trace_register_description_ext(const struct spdk_trace_tpoint_opts *opts, size_t num_opts)
     326                 :            : {
     327                 :            :         size_t i;
     328                 :            : 
     329         [ -  + ]:     134610 :         if (g_trace_flags == NULL) {
     330                 :          0 :                 SPDK_ERRLOG("trace is not initialized\n");
     331                 :          0 :                 return;
     332                 :            :         }
     333                 :            : 
     334         [ +  + ]:     290472 :         for (i = 0; i < num_opts; ++i) {
     335                 :     155862 :                 trace_register_description(&opts[i]);
     336                 :            :         }
     337                 :            : }
     338                 :            : 
     339                 :            : void
     340                 :     124988 : spdk_trace_register_description(const char *name, uint16_t tpoint_id, uint8_t owner_type,
     341                 :            :                                 uint8_t object_type, uint8_t new_object,
     342                 :            :                                 uint8_t arg1_type, const char *arg1_name)
     343                 :            : {
     344                 :     124988 :         struct spdk_trace_tpoint_opts opts = {
     345                 :            :                 .name = name,
     346                 :            :                 .tpoint_id = tpoint_id,
     347                 :            :                 .owner_type = owner_type,
     348                 :            :                 .object_type = object_type,
     349                 :            :                 .new_object = new_object,
     350                 :            :                 .args = {{
     351                 :            :                                 .name = arg1_name,
     352                 :            :                                 .type = arg1_type,
     353                 :            :                                 .size = sizeof(uint64_t)
     354                 :            :                         }
     355                 :            :                 }
     356                 :            :         };
     357                 :            : 
     358                 :     124988 :         spdk_trace_register_description_ext(&opts, 1);
     359                 :     124988 : }
     360                 :            : 
     361                 :            : void
     362                 :      12966 : spdk_trace_tpoint_register_relation(uint16_t tpoint_id, uint8_t object_type, uint8_t arg_index)
     363                 :            : {
     364                 :            :         struct spdk_trace_tpoint *tpoint;
     365                 :            :         uint16_t i;
     366                 :            : 
     367         [ -  + ]:      12966 :         assert(object_type != OBJECT_NONE);
     368         [ -  + ]:      12966 :         assert(tpoint_id != OBJECT_NONE);
     369                 :            : 
     370         [ -  + ]:      12966 :         if (g_trace_flags == NULL) {
     371                 :          0 :                 SPDK_ERRLOG("trace is not initialized\n");
     372                 :          0 :                 return;
     373                 :            :         }
     374                 :            : 
     375                 :            :         /* We do not check whether a tpoint_id exists here, because
     376                 :            :          * there is no order in which trace definitions are registered.
     377                 :            :          * This way we can create relations between tpoint and objects
     378                 :            :          * that will be declared later. */
     379                 :      12966 :         tpoint = &g_trace_flags->tpoint[tpoint_id];
     380         [ +  - ]:      12966 :         for (i = 0; i < SPDK_COUNTOF(tpoint->related_objects); ++i) {
     381         [ +  - ]:      12966 :                 if (tpoint->related_objects[i].object_type == OBJECT_NONE) {
     382                 :      12966 :                         tpoint->related_objects[i].object_type = object_type;
     383                 :      12966 :                         tpoint->related_objects[i].arg_index = arg_index;
     384                 :      12966 :                         return;
     385                 :            :                 }
     386                 :            :         }
     387                 :          0 :         SPDK_ERRLOG("Unable to register new relation for tpoint %" PRIu16 ", object %" PRIu8 "\n",
     388                 :            :                     tpoint_id, object_type);
     389                 :            : }
     390                 :            : 
     391                 :            : void
     392                 :      25443 : spdk_trace_add_register_fn(struct spdk_trace_register_fn *reg_fn)
     393                 :            : {
     394                 :            :         struct spdk_trace_register_fn *_reg_fn;
     395                 :            : 
     396         [ -  + ]:      25443 :         if (reg_fn->name == NULL) {
     397                 :          0 :                 SPDK_ERRLOG("missing name for registering spdk trace tpoint group\n");
     398                 :          0 :                 assert(false);
     399                 :            :                 return;
     400                 :            :         }
     401                 :            : 
     402   [ -  +  -  + ]:      25443 :         if (strcmp(reg_fn->name, "all") == 0) {
     403                 :          0 :                 SPDK_ERRLOG("illegal name (%s) for tpoint group\n", reg_fn->name);
     404                 :          0 :                 assert(false);
     405                 :            :                 return;
     406                 :            :         }
     407                 :            : 
     408                 :            :         /* Ensure that no trace point group IDs and names are ever duplicated */
     409         [ +  + ]:     131248 :         for (_reg_fn = g_reg_fn_head; _reg_fn; _reg_fn = _reg_fn->next) {
     410         [ -  + ]:     105805 :                 if (reg_fn->tgroup_id == _reg_fn->tgroup_id) {
     411                 :          0 :                         SPDK_ERRLOG("group %d, %s has duplicate tgroup_id with %s\n",
     412                 :            :                                     reg_fn->tgroup_id, reg_fn->name, _reg_fn->name);
     413                 :          0 :                         assert(false);
     414                 :            :                         return;
     415                 :            :                 }
     416                 :            : 
     417   [ -  +  -  +  :     105805 :                 if (strcmp(reg_fn->name, _reg_fn->name) == 0) {
                   -  + ]
     418                 :          0 :                         SPDK_ERRLOG("name %s is duplicated between groups with ids %d and %d\n",
     419                 :            :                                     reg_fn->name, reg_fn->tgroup_id, _reg_fn->tgroup_id);
     420                 :          0 :                         assert(false);
     421                 :            :                         return;
     422                 :            :                 }
     423                 :            :         }
     424                 :            : 
     425                 :            :         /* Arrange trace registration in order on tgroup_id */
     426   [ +  +  +  + ]:      25443 :         if (g_reg_fn_head == NULL || reg_fn->tgroup_id < g_reg_fn_head->tgroup_id) {
     427                 :       9272 :                 reg_fn->next = g_reg_fn_head;
     428                 :       9272 :                 g_reg_fn_head = reg_fn;
     429                 :       9272 :                 return;
     430                 :            :         }
     431                 :            : 
     432         [ +  - ]:      57424 :         for (_reg_fn = g_reg_fn_head; _reg_fn; _reg_fn = _reg_fn->next) {
     433   [ +  +  +  + ]:      57424 :                 if (_reg_fn->next == NULL || reg_fn->tgroup_id < _reg_fn->next->tgroup_id) {
     434                 :      16171 :                         reg_fn->next = _reg_fn->next;
     435                 :      16171 :                         _reg_fn->next = reg_fn;
     436                 :      16171 :                         return;
     437                 :            :                 }
     438                 :            :         }
     439                 :            : }
     440                 :            : 
     441                 :            : void
     442                 :       3023 : spdk_trace_flags_init(void)
     443                 :            : {
     444                 :            :         struct spdk_trace_register_fn *reg_fn;
     445                 :            : 
     446                 :       3023 :         reg_fn = g_reg_fn_head;
     447         [ +  + ]:      25756 :         while (reg_fn) {
     448                 :      22733 :                 reg_fn->reg_fn();
     449                 :      22733 :                 reg_fn = reg_fn->next;
     450                 :            :         }
     451                 :       3023 : }

Generated by: LCOV version 1.14