LCOV - code coverage report
Current view: top level - spdk/app/trace_record - trace_record.c (source / functions) Hit Total Coverage
Test: Combined Lines: 231 372 62.1 %
Date: 2024-07-14 06:08:52 Functions: 13 15 86.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 125 383 32.6 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2018 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : 
       8                 :            : #include "spdk/env.h"
       9                 :            : #include "spdk/string.h"
      10                 :            : #include "spdk/trace.h"
      11                 :            : #include "spdk/util.h"
      12                 :            : #include "spdk/barrier.h"
      13                 :            : 
      14                 :            : #define TRACE_FILE_COPY_SIZE    (32 * 1024)
      15                 :            : #define TRACE_PATH_MAX          2048
      16                 :            : 
      17                 :            : static char *g_exe_name;
      18                 :            : static int g_verbose = 1;
      19                 :            : static uint64_t g_tsc_rate;
      20                 :            : static uint64_t g_utsc_rate;
      21                 :            : static bool g_shutdown = false;
      22                 :            : static uint64_t g_file_size;
      23                 :            : 
      24                 :            : struct lcore_trace_record_ctx {
      25                 :            :         char lcore_file[TRACE_PATH_MAX];
      26                 :            :         int fd;
      27                 :            :         bool valid;
      28                 :            :         struct spdk_trace_history *in_history;
      29                 :            :         struct spdk_trace_history *out_history;
      30                 :            : 
      31                 :            :         /* Recorded next entry index in record */
      32                 :            :         uint64_t rec_next_entry;
      33                 :            : 
      34                 :            :         /* Record tsc for report */
      35                 :            :         uint64_t first_entry_tsc;
      36                 :            :         uint64_t last_entry_tsc;
      37                 :            : 
      38                 :            :         /* Total number of entries in lcore trace file */
      39                 :            :         uint64_t num_entries;
      40                 :            : };
      41                 :            : 
      42                 :            : struct aggr_trace_record_ctx {
      43                 :            :         const char *out_file;
      44                 :            :         int out_fd;
      45                 :            :         int shm_fd;
      46                 :            :         struct lcore_trace_record_ctx lcore_ports[SPDK_TRACE_MAX_LCORE];
      47                 :            :         struct spdk_trace_file *trace_file;
      48                 :            : };
      49                 :            : 
      50                 :            : static int
      51                 :          2 : input_trace_file_mmap(struct aggr_trace_record_ctx *ctx, const char *shm_name)
      52                 :            : {
      53                 :            :         void *history_ptr;
      54                 :            :         int i;
      55                 :            : 
      56                 :          2 :         ctx->shm_fd = shm_open(shm_name, O_RDONLY, 0);
      57         [ -  + ]:          2 :         if (ctx->shm_fd < 0) {
      58   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Could not open %s.\n", shm_name);
      59                 :          0 :                 return -1;
      60                 :            :         }
      61                 :            : 
      62                 :            :         /* Map the header of trace file */
      63                 :          2 :         history_ptr = mmap(NULL, sizeof(struct spdk_trace_file), PROT_READ, MAP_SHARED, ctx->shm_fd,
      64                 :            :                            0);
      65         [ -  + ]:          2 :         if (history_ptr == MAP_FAILED) {
      66   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Could not mmap shm %s.\n", shm_name);
      67                 :          0 :                 close(ctx->shm_fd);
      68                 :          0 :                 return -1;
      69                 :            :         }
      70                 :            : 
      71                 :          2 :         ctx->trace_file = (struct spdk_trace_file *)history_ptr;
      72                 :            : 
      73                 :          2 :         g_tsc_rate = ctx->trace_file->tsc_rate;
      74                 :          2 :         g_utsc_rate = g_tsc_rate / 1000;
      75         [ -  + ]:          2 :         if (g_tsc_rate == 0) {
      76   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Invalid tsc_rate %ju\n", g_tsc_rate);
      77                 :          0 :                 munmap(history_ptr, sizeof(struct spdk_trace_file));
      78                 :          0 :                 close(ctx->shm_fd);
      79                 :          0 :                 return -1;
      80                 :            :         }
      81                 :            : 
      82         [ -  + ]:          2 :         if (g_verbose) {
      83         [ #  # ]:          0 :                 printf("TSC Rate: %ju\n", g_tsc_rate);
      84                 :            :         }
      85                 :            : 
      86                 :            :         /* Remap the entire trace file */
      87                 :          2 :         g_file_size = spdk_get_trace_file_size(ctx->trace_file);
      88                 :          2 :         munmap(history_ptr, sizeof(struct spdk_trace_file));
      89                 :          2 :         history_ptr = mmap(NULL, g_file_size, PROT_READ, MAP_SHARED, ctx->shm_fd, 0);
      90         [ -  + ]:          2 :         if (history_ptr == MAP_FAILED) {
      91   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Could not remmap shm %s.\n", shm_name);
      92                 :          0 :                 close(ctx->shm_fd);
      93                 :          0 :                 return -1;
      94                 :            :         }
      95                 :            : 
      96                 :          2 :         ctx->trace_file = (struct spdk_trace_file *)history_ptr;
      97         [ +  + ]:       2050 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
      98                 :            :                 struct spdk_trace_history *history;
      99                 :            : 
     100                 :       2048 :                 history = spdk_get_per_lcore_history(ctx->trace_file, i);
     101                 :       2048 :                 ctx->lcore_ports[i].in_history = history;
     102                 :       2048 :                 ctx->lcore_ports[i].valid = (history != NULL);
     103                 :            : 
     104   [ -  +  -  - ]:       2048 :                 if (g_verbose && history) {
     105         [ #  # ]:          0 :                         printf("Number of trace entries for lcore (%d): %ju\n", i,
     106                 :            :                                history->num_entries);
     107                 :            :                 }
     108                 :            :         }
     109                 :            : 
     110                 :          2 :         return 0;
     111                 :            : }
     112                 :            : 
     113                 :            : static int
     114                 :          2 : output_trace_files_prepare(struct aggr_trace_record_ctx *ctx, const char *aggr_path)
     115                 :            : {
     116                 :          2 :         int flags = O_CREAT | O_EXCL | O_RDWR;
     117                 :            :         struct lcore_trace_record_ctx *port_ctx;
     118                 :            :         int name_len;
     119                 :            :         int i, rc;
     120                 :            : 
     121                 :            :         /* Assign file names for related trace files */
     122                 :          2 :         ctx->out_file = aggr_path;
     123         [ +  + ]:       2050 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     124                 :       2048 :                 port_ctx = &ctx->lcore_ports[i];
     125                 :            : 
     126                 :            :                 /* Get the length of trace file name for each lcore with format "%s-%d" */
     127         [ -  + ]:       2048 :                 name_len = snprintf(port_ctx->lcore_file, TRACE_PATH_MAX, "%s-%d", ctx->out_file, i);
     128         [ -  + ]:       2048 :                 if (name_len >= TRACE_PATH_MAX) {
     129   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Length of file path (%s) exceeds limitation for lcore file.\n",
     130                 :            :                                 aggr_path);
     131                 :          0 :                         goto err;
     132                 :            :                 }
     133                 :            :         }
     134                 :            : 
     135                 :            :         /* If output trace file already exists, try to unlink it together with its temporary files */
     136   [ -  +  -  + ]:          2 :         if (access(ctx->out_file, F_OK) == 0) {
     137         [ #  # ]:          0 :                 rc = unlink(ctx->out_file);
     138         [ #  # ]:          0 :                 if (rc) {
     139                 :          0 :                         goto err;
     140                 :            :                 }
     141                 :            : 
     142         [ #  # ]:          0 :                 for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     143                 :          0 :                         port_ctx = &ctx->lcore_ports[i];
     144   [ #  #  #  # ]:          0 :                         if (access(port_ctx->lcore_file, F_OK) == 0) {
     145         [ #  # ]:          0 :                                 rc = unlink(port_ctx->lcore_file);
     146         [ #  # ]:          0 :                                 if (rc) {
     147                 :          0 :                                         goto err;
     148                 :            :                                 }
     149                 :            :                         }
     150                 :            :                 }
     151                 :            : 
     152                 :            :         }
     153                 :            : 
     154         [ +  + ]:       2050 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     155                 :       2048 :                 port_ctx = &ctx->lcore_ports[i];
     156                 :            : 
     157   [ -  +  +  + ]:       2048 :                 if (!port_ctx->valid) {
     158                 :       2040 :                         continue;
     159                 :            :                 }
     160                 :            : 
     161         [ -  + ]:          8 :                 port_ctx->fd = open(port_ctx->lcore_file, flags, 0600);
     162         [ -  + ]:          8 :                 if (port_ctx->fd < 0) {
     163   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Could not open lcore file %s.\n", port_ctx->lcore_file);
     164                 :          0 :                         goto err;
     165                 :            :                 }
     166                 :            : 
     167         [ -  + ]:          8 :                 if (g_verbose) {
     168         [ #  # ]:          0 :                         printf("Create tmp lcore trace file %s for lcore %d\n", port_ctx->lcore_file, i);
     169                 :            :                 }
     170                 :            : 
     171                 :          8 :                 port_ctx->out_history = calloc(1, sizeof(struct spdk_trace_history));
     172         [ -  + ]:          8 :                 if (port_ctx->out_history == NULL) {
     173   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Failed to allocate memory for out_history.\n");
     174                 :          0 :                         goto err;
     175                 :            :                 }
     176                 :            :         }
     177                 :            : 
     178                 :          2 :         return 0;
     179                 :            : 
     180                 :          0 : err:
     181         [ #  # ]:          0 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     182                 :          0 :                 port_ctx = &ctx->lcore_ports[i];
     183                 :          0 :                 free(port_ctx->out_history);
     184                 :            : 
     185         [ #  # ]:          0 :                 if (port_ctx->fd > 0) {
     186                 :          0 :                         close(port_ctx->fd);
     187                 :            :                 }
     188                 :            :         }
     189                 :            : 
     190                 :          0 :         return -1;
     191                 :            : }
     192                 :            : 
     193                 :            : static void
     194                 :          2 : output_trace_files_finish(struct aggr_trace_record_ctx *ctx)
     195                 :            : {
     196                 :            :         struct lcore_trace_record_ctx *port_ctx;
     197                 :            :         int i;
     198                 :            : 
     199         [ +  + ]:       2050 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     200                 :       2048 :                 port_ctx = &ctx->lcore_ports[i];
     201                 :            : 
     202                 :       2048 :                 free(port_ctx->out_history);
     203                 :       2048 :                 close(port_ctx->fd);
     204         [ -  + ]:       2048 :                 unlink(port_ctx->lcore_file);
     205                 :            : 
     206         [ -  + ]:       2048 :                 if (g_verbose) {
     207         [ #  # ]:          0 :                         printf("Remove tmp lcore trace file %s for lcore %d\n", port_ctx->lcore_file, i);
     208                 :            :                 }
     209                 :            :         }
     210                 :          2 : }
     211                 :            : 
     212                 :            : static int
     213                 :     217069 : cont_write(int fildes, const void *buf, size_t nbyte)
     214                 :            : {
     215                 :            :         int rc;
     216                 :     217069 :         int _nbyte = nbyte;
     217                 :            : 
     218         [ +  + ]:     434138 :         while (_nbyte) {
     219                 :     217069 :                 rc = write(fildes, buf, _nbyte);
     220         [ -  + ]:     217069 :                 if (rc < 0) {
     221         [ #  # ]:          0 :                         if (errno != EINTR) {
     222                 :          0 :                                 return -1;
     223                 :            :                         }
     224                 :            : 
     225                 :          0 :                         continue;
     226                 :            :                 }
     227                 :            : 
     228                 :     217069 :                 _nbyte -= rc;
     229                 :            :         }
     230                 :            : 
     231                 :     217069 :         return nbyte;
     232                 :            : }
     233                 :            : 
     234                 :            : static int
     235                 :       1152 : cont_read(int fildes, void *buf, size_t nbyte)
     236                 :            : {
     237                 :            :         int rc;
     238                 :       1152 :         int _nbyte = nbyte;
     239                 :            : 
     240         [ +  + ]:       2296 :         while (_nbyte) {
     241                 :       1160 :                 rc = read(fildes, buf, _nbyte);
     242         [ +  + ]:       1160 :                 if (rc == 0) {
     243                 :         16 :                         return nbyte - _nbyte;
     244         [ -  + ]:       1144 :                 } else if (rc < 0) {
     245         [ #  # ]:          0 :                         if (errno != EINTR) {
     246                 :          0 :                                 return -1;
     247                 :            :                         }
     248                 :            : 
     249                 :          0 :                         continue;
     250                 :            :                 }
     251                 :            : 
     252                 :       1144 :                 _nbyte -= rc;
     253                 :            :         }
     254                 :            : 
     255                 :       1136 :         return nbyte;
     256                 :            : }
     257                 :            : 
     258                 :            : static int
     259                 :     215679 : lcore_trace_last_entry_idx(struct spdk_trace_history *in_history, int cir_next_idx)
     260                 :            : {
     261                 :            :         int last_idx;
     262                 :            : 
     263         [ +  + ]:     215679 :         if (cir_next_idx == 0) {
     264                 :         53 :                 last_idx = in_history->num_entries - 1;
     265                 :            :         } else {
     266                 :     215626 :                 last_idx = cir_next_idx - 1;
     267                 :            :         }
     268                 :            : 
     269                 :     215679 :         return last_idx;
     270                 :            : }
     271                 :            : 
     272                 :            : static int
     273                 :     215398 : circular_buffer_padding_backward(int fd, struct spdk_trace_history *in_history,
     274                 :            :                                  int cir_start, int cir_end)
     275                 :            : {
     276                 :            :         int rc;
     277                 :            : 
     278         [ -  + ]:     215398 :         if (cir_end <= cir_start) {
     279   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Wrong using of circular_buffer_padding_back\n");
     280                 :          0 :                 return -1;
     281                 :            :         }
     282                 :            : 
     283                 :     215398 :         rc = cont_write(fd, &in_history->entries[cir_start],
     284                 :     215398 :                         sizeof(struct spdk_trace_entry) * (cir_end - cir_start));
     285         [ -  + ]:     215398 :         if (rc < 0) {
     286   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to append entries into lcore file\n");
     287                 :          0 :                 return rc;
     288                 :            :         }
     289                 :            : 
     290                 :     215398 :         return 0;
     291                 :            : }
     292                 :            : 
     293                 :            : static int
     294                 :        281 : circular_buffer_padding_across(int fd, struct spdk_trace_history *in_history,
     295                 :            :                                int cir_start, int cir_end)
     296                 :            : {
     297                 :            :         int rc;
     298                 :        281 :         int num_entries = in_history->num_entries;
     299                 :            : 
     300         [ -  + ]:        281 :         if (cir_end > cir_start) {
     301   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Wrong using of circular_buffer_padding_across\n");
     302                 :          0 :                 return -1;
     303                 :            :         }
     304                 :            : 
     305                 :        281 :         rc = cont_write(fd, &in_history->entries[cir_start],
     306                 :        281 :                         sizeof(struct spdk_trace_entry) * (num_entries - cir_start));
     307         [ -  + ]:        281 :         if (rc < 0) {
     308   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to append entries into lcore file backward\n");
     309                 :          0 :                 return rc;
     310                 :            :         }
     311                 :            : 
     312         [ +  + ]:        281 :         if (cir_end == 0) {
     313                 :         53 :                 return 0;
     314                 :            :         }
     315                 :            : 
     316                 :        228 :         rc = cont_write(fd, &in_history->entries[0], sizeof(struct spdk_trace_entry) * cir_end);
     317         [ -  + ]:        228 :         if (rc < 0) {
     318   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to append entries into lcore file forward\n");
     319                 :          0 :                 return rc;
     320                 :            :         }
     321                 :            : 
     322                 :        228 :         return 0;
     323                 :            : }
     324                 :            : 
     325                 :            : static int
     326                 :          0 : circular_buffer_padding_all(int fd, struct spdk_trace_history *in_history,
     327                 :            :                             int cir_end)
     328                 :            : {
     329                 :          0 :         return circular_buffer_padding_across(fd, in_history, cir_end, cir_end);
     330                 :            : }
     331                 :            : 
     332                 :            : static int
     333                 :    1804416 : lcore_trace_record(struct lcore_trace_record_ctx *lcore_port)
     334                 :            : {
     335                 :    1804416 :         struct spdk_trace_history       *in_history = lcore_port->in_history;
     336                 :    1804416 :         uint64_t                        rec_next_entry = lcore_port->rec_next_entry;
     337                 :    1804416 :         uint64_t                        rec_num_entries = lcore_port->num_entries;
     338                 :    1804416 :         int                             fd = lcore_port->fd;
     339                 :            :         uint64_t                        shm_next_entry;
     340                 :            :         uint64_t                        num_cir_entries;
     341                 :            :         uint64_t                        shm_cir_next;
     342                 :            :         uint64_t                        rec_cir_next;
     343                 :            :         int                             rc;
     344                 :            :         int                             last_idx;
     345                 :            : 
     346                 :    1804416 :         shm_next_entry = in_history->next_entry;
     347                 :            : 
     348                 :            :         /* Ensure all entries of spdk_trace_history are latest to next_entry */
     349                 :    1804416 :         spdk_smp_rmb();
     350                 :            : 
     351         [ +  + ]:    1804416 :         if (shm_next_entry == rec_next_entry) {
     352                 :            :                 /* There is no update */
     353                 :    1588737 :                 return 0;
     354         [ -  + ]:     215679 :         } else if (shm_next_entry < rec_next_entry) {
     355                 :            :                 /* Error branch */
     356   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Trace porting error in lcore %d, trace rollback occurs.\n", in_history->lcore);
     357   [ #  #  #  # ]:          0 :                 fprintf(stderr, "shm_next_entry is %ju, record_next_entry is %ju.\n", shm_next_entry,
     358                 :            :                         rec_next_entry);
     359                 :          0 :                 return -1;
     360                 :            :         }
     361                 :            : 
     362                 :     215679 :         num_cir_entries = in_history->num_entries;
     363                 :     215679 :         shm_cir_next = shm_next_entry & (num_cir_entries - 1);
     364                 :            : 
     365                 :            :         /* Record first entry's tsc and corresponding entries when recording first time. */
     366         [ +  + ]:     215679 :         if (lcore_port->first_entry_tsc == 0) {
     367         [ +  - ]:          8 :                 if (shm_next_entry < num_cir_entries) {
     368                 :            :                         /* Updates haven't been across circular buffer yet.
     369                 :            :                          * The first entry in shared memory is the eldest one.
     370                 :            :                          */
     371                 :          8 :                         lcore_port->first_entry_tsc = in_history->entries[0].tsc;
     372                 :            : 
     373                 :          8 :                         lcore_port->num_entries += shm_cir_next;
     374                 :          8 :                         rc = circular_buffer_padding_backward(fd, in_history, 0, shm_cir_next);
     375                 :            :                 } else {
     376                 :            :                         /* Updates have already been across circular buffer.
     377                 :            :                          * The eldest entry in shared memory is pointed by shm_cir_next.
     378                 :            :                          */
     379                 :          0 :                         lcore_port->first_entry_tsc = in_history->entries[shm_cir_next].tsc;
     380                 :            : 
     381                 :          0 :                         lcore_port->num_entries += num_cir_entries;
     382                 :          0 :                         rc = circular_buffer_padding_all(fd, in_history, shm_cir_next);
     383                 :            :                 }
     384                 :            : 
     385                 :          8 :                 goto out;
     386                 :            :         }
     387                 :            : 
     388         [ -  + ]:     215671 :         if (shm_next_entry - rec_next_entry > num_cir_entries) {
     389                 :            :                 /* There must be missed updates */
     390         [ #  # ]:          0 :                 fprintf(stderr, "Trace-record missed %ju trace entries\n",
     391         [ #  # ]:          0 :                         shm_next_entry - rec_next_entry - num_cir_entries);
     392                 :            : 
     393                 :          0 :                 lcore_port->num_entries += num_cir_entries;
     394                 :          0 :                 rc = circular_buffer_padding_all(fd, in_history, shm_cir_next);
     395         [ -  + ]:     215671 :         } else if (shm_next_entry - rec_next_entry == num_cir_entries) {
     396                 :            :                 /* All circular buffer is updated */
     397                 :          0 :                 lcore_port->num_entries += num_cir_entries;
     398                 :          0 :                 rc = circular_buffer_padding_all(fd, in_history, shm_cir_next);
     399                 :            :         } else {
     400                 :            :                 /* Part of circular buffer is updated */
     401                 :     215671 :                 rec_cir_next = rec_next_entry & (num_cir_entries - 1);
     402                 :            : 
     403         [ +  + ]:     215671 :                 if (shm_cir_next > rec_cir_next) {
     404                 :            :                         /* Updates are not across circular buffer */
     405                 :     215390 :                         lcore_port->num_entries += shm_cir_next - rec_cir_next;
     406                 :     215390 :                         rc = circular_buffer_padding_backward(fd, in_history, rec_cir_next, shm_cir_next);
     407                 :            :                 } else {
     408                 :            :                         /* Updates are across circular buffer */
     409                 :        281 :                         lcore_port->num_entries += num_cir_entries - rec_cir_next + shm_cir_next;
     410                 :        281 :                         rc = circular_buffer_padding_across(fd, in_history, rec_cir_next, shm_cir_next);
     411                 :            :                 }
     412                 :            :         }
     413                 :            : 
     414                 :     215679 : out:
     415         [ -  + ]:     215679 :         if (rc) {
     416                 :          0 :                 return rc;
     417                 :            :         }
     418                 :            : 
     419         [ -  + ]:     215679 :         if (g_verbose) {
     420         [ #  # ]:          0 :                 printf("Append %ju trace_entry for lcore %d\n", lcore_port->num_entries - rec_num_entries,
     421                 :            :                        in_history->lcore);
     422                 :            :         }
     423                 :            : 
     424                 :            :         /* Update tpoint_count info */
     425   [ -  +  -  + ]:     215679 :         memcpy(lcore_port->out_history, lcore_port->in_history, sizeof(struct spdk_trace_history));
     426                 :            : 
     427                 :            :         /* Update last_entry_tsc to align with appended entries */
     428                 :     215679 :         last_idx = lcore_trace_last_entry_idx(in_history, shm_cir_next);
     429                 :     215679 :         lcore_port->last_entry_tsc = in_history->entries[last_idx].tsc;
     430                 :     215679 :         lcore_port->rec_next_entry = shm_next_entry;
     431                 :            : 
     432                 :     215679 :         return rc;
     433                 :            : }
     434                 :            : 
     435                 :            : static int
     436                 :          2 : trace_files_aggregate(struct aggr_trace_record_ctx *ctx)
     437                 :            : {
     438                 :          2 :         int flags = O_CREAT | O_EXCL | O_RDWR;
     439                 :            :         struct lcore_trace_record_ctx *lcore_port;
     440                 :          0 :         char copy_buff[TRACE_FILE_COPY_SIZE];
     441                 :          0 :         uint64_t lcore_offsets[SPDK_TRACE_MAX_LCORE];
     442                 :            :         int rc, i;
     443                 :          2 :         ssize_t len = 0;
     444                 :          0 :         uint64_t current_offset;
     445                 :          0 :         uint64_t owner_offset, owner_size;
     446                 :            :         uint64_t len_sum;
     447                 :            :         uint8_t *owner_buf;
     448                 :            : 
     449         [ -  + ]:          2 :         ctx->out_fd = open(ctx->out_file, flags, 0600);
     450         [ -  + ]:          2 :         if (ctx->out_fd < 0) {
     451   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Could not open aggregation file %s.\n", ctx->out_file);
     452                 :          0 :                 return -1;
     453                 :            :         }
     454                 :            : 
     455         [ -  + ]:          2 :         if (g_verbose) {
     456         [ #  # ]:          0 :                 printf("Create trace file %s for output\n", ctx->out_file);
     457                 :            :         }
     458                 :            : 
     459                 :            :         /* Calculate lcore offsets for converged trace file */
     460                 :          2 :         current_offset = sizeof(struct spdk_trace_file);
     461         [ +  + ]:       2050 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     462                 :       2048 :                 lcore_port = &ctx->lcore_ports[i];
     463   [ -  +  +  + ]:       2048 :                 if (lcore_port->valid) {
     464                 :          8 :                         lcore_offsets[i] = current_offset;
     465                 :          8 :                         current_offset += spdk_get_trace_history_size(lcore_port->num_entries);
     466                 :            :                 } else {
     467                 :       2040 :                         lcore_offsets[i] = 0;
     468                 :            :                 }
     469                 :            :         }
     470                 :          2 :         owner_size = (uint64_t)ctx->trace_file->num_owners *
     471                 :          2 :                      (sizeof(struct spdk_trace_owner) + ctx->trace_file->owner_description_size);
     472                 :          2 :         owner_offset = current_offset;
     473                 :          2 :         current_offset += owner_size;
     474                 :            : 
     475                 :            :         /* Write size of converged trace file */
     476                 :          2 :         rc = cont_write(ctx->out_fd, &current_offset, sizeof(ctx->trace_file->file_size));
     477         [ -  + ]:          2 :         if (rc < 0) {
     478   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to write file size into trace file\n");
     479                 :          0 :                 goto out;
     480                 :            :         }
     481                 :            : 
     482                 :            :         /* Write rest of metadata (spdk_trace_file) of converged trace file */
     483                 :          2 :         rc = cont_write(ctx->out_fd, &ctx->trace_file->tsc_rate,
     484                 :            :                         sizeof(struct spdk_trace_file) - sizeof(lcore_offsets) -
     485                 :            :                         sizeof(owner_offset) - sizeof(ctx->trace_file->file_size));
     486         [ -  + ]:          2 :         if (rc < 0) {
     487   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to write metadata into trace file\n");
     488                 :          0 :                 goto out;
     489                 :            :         }
     490                 :            : 
     491                 :            :         /* Write lcore offsets of converged trace file */
     492                 :          2 :         rc = cont_write(ctx->out_fd, lcore_offsets, sizeof(lcore_offsets));
     493         [ -  + ]:          2 :         if (rc < 0) {
     494   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to write lcore offsets into trace file\n");
     495                 :          0 :                 goto out;
     496                 :            :         }
     497                 :            : 
     498                 :            :         /* Write owner_offset of converged trace file */
     499                 :          2 :         rc = cont_write(ctx->out_fd, &owner_offset, sizeof(owner_offset));
     500         [ -  + ]:          2 :         if (rc < 0) {
     501   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to write owner_description_size into trace file\n");
     502                 :          0 :                 goto out;
     503                 :            :         }
     504                 :            : 
     505                 :            :         /* Append each lcore trace file into converged trace file */
     506         [ +  + ]:       2050 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     507                 :       2048 :                 lcore_port = &ctx->lcore_ports[i];
     508                 :            : 
     509   [ -  +  +  + ]:       2048 :                 if (!lcore_port->valid) {
     510                 :       2040 :                         continue;
     511                 :            :                 }
     512                 :            : 
     513                 :          8 :                 lcore_port->out_history->num_entries = lcore_port->num_entries;
     514                 :          8 :                 rc = cont_write(ctx->out_fd, lcore_port->out_history, sizeof(struct spdk_trace_history));
     515         [ -  + ]:          8 :                 if (rc < 0) {
     516   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Failed to write lcore trace header into trace file\n");
     517                 :          0 :                         goto out;
     518                 :            :                 }
     519                 :            : 
     520                 :            :                 /* Move file offset to the start of trace_entries */
     521                 :          8 :                 rc = lseek(lcore_port->fd, 0, SEEK_SET);
     522         [ -  + ]:          8 :                 if (rc != 0) {
     523   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Failed to lseek lcore trace file\n");
     524                 :          0 :                         goto out;
     525                 :            :                 }
     526                 :            : 
     527                 :          8 :                 len_sum = 0;
     528         [ +  + ]:       1152 :                 while ((len = cont_read(lcore_port->fd, copy_buff, TRACE_FILE_COPY_SIZE)) > 0) {
     529                 :       1144 :                         len_sum += len;
     530                 :       1144 :                         rc = cont_write(ctx->out_fd, copy_buff, len);
     531         [ -  + ]:       1144 :                         if (rc != len) {
     532   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "Failed to write lcore trace entries into trace file\n");
     533                 :          0 :                                 goto out;
     534                 :            :                         }
     535                 :            :                 }
     536                 :            : 
     537         [ -  + ]:          8 :                 if (len_sum != lcore_port->num_entries * sizeof(struct spdk_trace_entry)) {
     538   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Len of lcore trace file doesn't match number of entries for lcore\n");
     539                 :            :                 }
     540                 :            :         }
     541                 :            : 
     542                 :            :         /* Append owner data into converged trace file */
     543                 :          2 :         owner_buf = (uint8_t *)ctx->trace_file + ctx->trace_file->owner_offset;
     544                 :          2 :         rc = cont_write(ctx->out_fd, owner_buf, owner_size);
     545         [ -  + ]:          2 :         if (rc < 0) {
     546   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to write owner_data into trace file\n");
     547                 :          0 :                 goto out;
     548                 :            :         }
     549                 :            : 
     550         [ -  + ]:          2 :         printf("All lcores trace entries are aggregated into trace file %s\n", ctx->out_file);
     551                 :          2 :         return 0;
     552                 :            : 
     553                 :          0 : out:
     554                 :          0 :         close(ctx->out_fd);
     555                 :            : 
     556                 :          0 :         return rc;
     557                 :            : }
     558                 :            : 
     559                 :            : static void
     560                 :          2 : __shutdown_signal(int signo)
     561                 :            : {
     562                 :          2 :         g_shutdown = true;
     563                 :          2 : }
     564                 :            : 
     565                 :            : static int
     566                 :          2 : setup_exit_signal_handler(void)
     567                 :            : {
     568                 :          0 :         struct sigaction        sigact;
     569                 :            :         int                     rc;
     570                 :            : 
     571         [ -  + ]:          2 :         memset(&sigact, 0, sizeof(sigact));
     572         [ -  + ]:          2 :         sigemptyset(&sigact.sa_mask);
     573                 :            :         /* Install the same handler for SIGINT and SIGTERM */
     574                 :          2 :         sigact.sa_handler = __shutdown_signal;
     575                 :            : 
     576                 :          2 :         rc = sigaction(SIGINT, &sigact, NULL);
     577         [ -  + ]:          2 :         if (rc < 0) {
     578   [ #  #  #  # ]:          0 :                 fprintf(stderr, "sigaction(SIGINT) failed\n");
     579                 :            : 
     580                 :          0 :                 return rc;
     581                 :            :         }
     582                 :            : 
     583                 :          2 :         rc = sigaction(SIGTERM, &sigact, NULL);
     584         [ -  + ]:          2 :         if (rc < 0) {
     585   [ #  #  #  # ]:          0 :                 fprintf(stderr, "sigaction(SIGTERM) failed\n");
     586                 :            :         }
     587                 :            : 
     588                 :          2 :         return rc;
     589                 :            : }
     590                 :            : 
     591                 :            : static void
     592                 :          0 : usage(void)
     593                 :            : {
     594         [ #  # ]:          0 :         printf("\n%s is used to record all SPDK generated trace entries\n", g_exe_name);
     595         [ #  # ]:          0 :         printf("from SPDK trace shared-memory to specified file.\n\n");
     596         [ #  # ]:          0 :         printf("usage:\n");
     597         [ #  # ]:          0 :         printf("   %s <option>\n", g_exe_name);
     598         [ #  # ]:          0 :         printf("        option = '-q' to disable verbose mode\n");
     599         [ #  # ]:          0 :         printf("                 '-s' to specify spdk_trace shm name for a\n");
     600         [ #  # ]:          0 :         printf("                      currently running process\n");
     601         [ #  # ]:          0 :         printf("                 '-i' to specify the shared memory ID\n");
     602         [ #  # ]:          0 :         printf("                 '-p' to specify the trace PID\n");
     603         [ #  # ]:          0 :         printf("                      (one of -i or -p must be specified)\n");
     604         [ #  # ]:          0 :         printf("                 '-f' to specify output trace file name\n");
     605         [ #  # ]:          0 :         printf("                 '-h' to print usage information\n");
     606                 :          0 : }
     607                 :            : 
     608                 :            : int
     609                 :          2 : main(int argc, char **argv)
     610                 :            : {
     611                 :          2 :         const char                      *app_name = NULL;
     612                 :          2 :         const char                      *file_name = NULL;
     613                 :            :         int                             op;
     614                 :          0 :         char                            shm_name[64];
     615                 :          2 :         int                             shm_id = -1, shm_pid = -1;
     616                 :          2 :         int                             rc = 0;
     617                 :            :         int                             i;
     618                 :          2 :         struct aggr_trace_record_ctx    ctx = {};
     619                 :            :         struct lcore_trace_record_ctx   *lcore_port;
     620                 :            : 
     621                 :          2 :         g_exe_name = argv[0];
     622   [ -  +  -  +  :         10 :         while ((op = getopt(argc, argv, "f:i:p:qs:h")) != -1) {
                   +  + ]
     623   [ -  +  +  +  :          8 :                 switch (op) {
                +  -  - ]
     624                 :          0 :                 case 'i':
     625                 :          0 :                         shm_id = spdk_strtol(optarg, 10);
     626                 :          0 :                         break;
     627                 :          2 :                 case 'p':
     628                 :          2 :                         shm_pid = spdk_strtol(optarg, 10);
     629                 :          2 :                         break;
     630                 :          2 :                 case 'q':
     631                 :          2 :                         g_verbose = 0;
     632                 :          2 :                         break;
     633                 :          2 :                 case 's':
     634                 :          2 :                         app_name = optarg;
     635                 :          2 :                         break;
     636                 :          2 :                 case 'f':
     637                 :          2 :                         file_name = optarg;
     638                 :          2 :                         break;
     639                 :          0 :                 case 'h':
     640                 :          0 :                         usage();
     641                 :          0 :                         exit(EXIT_SUCCESS);
     642                 :          0 :                 default:
     643                 :          0 :                         usage();
     644                 :          0 :                         exit(1);
     645                 :            :                 }
     646                 :            :         }
     647                 :            : 
     648         [ -  + ]:          2 :         if (file_name == NULL) {
     649   [ #  #  #  # ]:          0 :                 fprintf(stderr, "-f must be specified\n");
     650                 :          0 :                 usage();
     651                 :          0 :                 exit(1);
     652                 :            :         }
     653                 :            : 
     654         [ -  + ]:          2 :         if (app_name == NULL) {
     655   [ #  #  #  # ]:          0 :                 fprintf(stderr, "-s must be specified\n");
     656                 :          0 :                 usage();
     657                 :          0 :                 exit(1);
     658                 :            :         }
     659                 :            : 
     660   [ +  -  -  + ]:          2 :         if (shm_id == -1 && shm_pid == -1) {
     661   [ #  #  #  # ]:          0 :                 fprintf(stderr, "-i or -p must be specified\n");
     662                 :          0 :                 usage();
     663                 :          0 :                 exit(1);
     664                 :            :         }
     665                 :            : 
     666         [ -  + ]:          2 :         if (shm_id >= 0) {
     667         [ #  # ]:          0 :                 snprintf(shm_name, sizeof(shm_name), "/%s_trace.%d", app_name, shm_id);
     668                 :            :         } else {
     669         [ -  + ]:          2 :                 snprintf(shm_name, sizeof(shm_name), "/%s_trace.pid%d", app_name, shm_pid);
     670                 :            :         }
     671                 :            : 
     672                 :          2 :         rc = setup_exit_signal_handler();
     673         [ -  + ]:          2 :         if (rc) {
     674                 :          0 :                 exit(1);
     675                 :            :         }
     676                 :            : 
     677                 :          2 :         rc = input_trace_file_mmap(&ctx, shm_name);
     678         [ -  + ]:          2 :         if (rc) {
     679                 :          0 :                 exit(1);
     680                 :            :         }
     681                 :            : 
     682                 :          2 :         rc = output_trace_files_prepare(&ctx, file_name);
     683         [ -  + ]:          2 :         if (rc) {
     684                 :          0 :                 exit(1);
     685                 :            :         }
     686                 :            : 
     687         [ -  + ]:          2 :         printf("Start to poll trace shm file %s\n", shm_name);
     688   [ -  +  +  +  :     451108 :         while (!g_shutdown && rc == 0) {
                   +  - ]
     689         [ +  + ]:  462381600 :                 for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     690                 :  461930496 :                         lcore_port = &ctx.lcore_ports[i];
     691                 :            : 
     692   [ -  +  +  + ]:  461930496 :                         if (!lcore_port->valid) {
     693                 :  460126080 :                                 continue;
     694                 :            :                         }
     695                 :    1804416 :                         rc = lcore_trace_record(lcore_port);
     696         [ -  + ]:    1804416 :                         if (rc) {
     697                 :          0 :                                 break;
     698                 :            :                         }
     699                 :            :                 }
     700                 :            :         }
     701                 :            : 
     702         [ -  + ]:          2 :         if (rc) {
     703                 :          0 :                 exit(1);
     704                 :            :         }
     705                 :            : 
     706         [ -  + ]:          2 :         printf("Start to aggregate lcore trace files\n");
     707                 :          2 :         rc = trace_files_aggregate(&ctx);
     708         [ -  + ]:          2 :         if (rc) {
     709                 :          0 :                 exit(1);
     710                 :            :         }
     711                 :            : 
     712                 :            :         /* Summary report */
     713         [ -  + ]:          2 :         printf("TSC Rate: %ju\n", g_tsc_rate);
     714         [ +  + ]:       2050 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     715                 :       2048 :                 lcore_port = &ctx.lcore_ports[i];
     716                 :            : 
     717         [ +  + ]:       2048 :                 if (lcore_port->num_entries == 0) {
     718                 :       2040 :                         continue;
     719                 :            :                 }
     720                 :            : 
     721         [ -  + ]:          8 :                 printf("Port %ju trace entries for lcore (%d) in %ju usec\n",
     722                 :            :                        lcore_port->num_entries, i,
     723         [ -  + ]:          8 :                        (lcore_port->last_entry_tsc - lcore_port->first_entry_tsc) / g_utsc_rate);
     724                 :            : 
     725                 :            :         }
     726                 :            : 
     727                 :          2 :         munmap(ctx.trace_file, g_file_size);
     728                 :          2 :         close(ctx.shm_fd);
     729                 :            : 
     730                 :          2 :         output_trace_files_finish(&ctx);
     731                 :            : 
     732                 :          2 :         return 0;
     733                 :            : }

Generated by: LCOV version 1.14