LCOV - code coverage report
Current view: top level - spdk/app/trace_record - trace_record.c (source / functions) Hit Total Coverage
Test: Combined Lines: 224 354 63.3 %
Date: 2024-07-12 22:14:58 Functions: 13 15 86.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 122 365 33.4 %

           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_histories_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_histories *trace_histories;
      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_histories), 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_histories = (struct spdk_trace_histories *)history_ptr;
      72                 :            : 
      73                 :          2 :         g_tsc_rate = ctx->trace_histories->flags.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_histories));
      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_histories_size = spdk_get_trace_histories_size(ctx->trace_histories);
      88                 :          2 :         munmap(history_ptr, sizeof(struct spdk_trace_histories));
      89                 :          2 :         history_ptr = mmap(NULL, g_histories_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_histories = (struct spdk_trace_histories *)history_ptr;
      97         [ +  + ]:        258 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
      98                 :            :                 struct spdk_trace_history *history;
      99                 :            : 
     100                 :        256 :                 history = spdk_get_per_lcore_history(ctx->trace_histories, i);
     101                 :        256 :                 ctx->lcore_ports[i].in_history = history;
     102                 :        256 :                 ctx->lcore_ports[i].valid = (history != NULL);
     103                 :            : 
     104   [ -  +  -  - ]:        256 :                 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         [ +  + ]:        258 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     124                 :        256 :                 port_ctx = &ctx->lcore_ports[i];
     125                 :            : 
     126                 :            :                 /* Get the length of trace file name for each lcore with format "%s-%d" */
     127         [ -  + ]:        256 :                 name_len = snprintf(port_ctx->lcore_file, TRACE_PATH_MAX, "%s-%d", ctx->out_file, i);
     128         [ -  + ]:        256 :                 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         [ +  + ]:        258 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     155                 :        256 :                 port_ctx = &ctx->lcore_ports[i];
     156                 :            : 
     157   [ -  +  +  + ]:        256 :                 if (!port_ctx->valid) {
     158                 :        248 :                         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         [ +  + ]:        258 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     200                 :        256 :                 port_ctx = &ctx->lcore_ports[i];
     201                 :            : 
     202                 :        256 :                 free(port_ctx->out_history);
     203                 :        256 :                 close(port_ctx->fd);
     204         [ -  + ]:        256 :                 unlink(port_ctx->lcore_file);
     205                 :            : 
     206         [ -  + ]:        256 :                 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                 :     509773 : cont_write(int fildes, const void *buf, size_t nbyte)
     214                 :            : {
     215                 :            :         int rc;
     216                 :     509773 :         int _nbyte = nbyte;
     217                 :            : 
     218         [ +  + ]:    1019546 :         while (_nbyte) {
     219                 :     509773 :                 rc = write(fildes, buf, _nbyte);
     220         [ -  + ]:     509773 :                 if (rc < 0) {
     221         [ #  # ]:          0 :                         if (errno != EINTR) {
     222                 :          0 :                                 return -1;
     223                 :            :                         }
     224                 :            : 
     225                 :          0 :                         continue;
     226                 :            :                 }
     227                 :            : 
     228                 :     509773 :                 _nbyte -= rc;
     229                 :            :         }
     230                 :            : 
     231                 :     509773 :         return nbyte;
     232                 :            : }
     233                 :            : 
     234                 :            : static int
     235                 :       1179 : cont_read(int fildes, void *buf, size_t nbyte)
     236                 :            : {
     237                 :            :         int rc;
     238                 :       1179 :         int _nbyte = nbyte;
     239                 :            : 
     240         [ +  + ]:       2350 :         while (_nbyte) {
     241                 :       1187 :                 rc = read(fildes, buf, _nbyte);
     242         [ +  + ]:       1187 :                 if (rc == 0) {
     243                 :         16 :                         return nbyte - _nbyte;
     244         [ -  + ]:       1171 :                 } else if (rc < 0) {
     245         [ #  # ]:          0 :                         if (errno != EINTR) {
     246                 :          0 :                                 return -1;
     247                 :            :                         }
     248                 :            : 
     249                 :          0 :                         continue;
     250                 :            :                 }
     251                 :            : 
     252                 :       1171 :                 _nbyte -= rc;
     253                 :            :         }
     254                 :            : 
     255                 :       1163 :         return nbyte;
     256                 :            : }
     257                 :            : 
     258                 :            : static int
     259                 :     508423 : lcore_trace_last_entry_idx(struct spdk_trace_history *in_history, int cir_next_idx)
     260                 :            : {
     261                 :            :         int last_idx;
     262                 :            : 
     263         [ +  + ]:     508423 :         if (cir_next_idx == 0) {
     264                 :        122 :                 last_idx = in_history->num_entries - 1;
     265                 :            :         } else {
     266                 :     508301 :                 last_idx = cir_next_idx - 1;
     267                 :            :         }
     268                 :            : 
     269                 :     508423 :         return last_idx;
     270                 :            : }
     271                 :            : 
     272                 :            : static int
     273                 :     508134 : 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         [ -  + ]:     508134 :         if (cir_end <= cir_start) {
     279   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Wrong using of circular_buffer_padding_back\n");
     280                 :          0 :                 return -1;
     281                 :            :         }
     282                 :            : 
     283                 :     508134 :         rc = cont_write(fd, &in_history->entries[cir_start],
     284                 :     508134 :                         sizeof(struct spdk_trace_entry) * (cir_end - cir_start));
     285         [ -  + ]:     508134 :         if (rc < 0) {
     286   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to append entries into lcore file\n");
     287                 :          0 :                 return rc;
     288                 :            :         }
     289                 :            : 
     290                 :     508134 :         return 0;
     291                 :            : }
     292                 :            : 
     293                 :            : static int
     294                 :        289 : circular_buffer_padding_across(int fd, struct spdk_trace_history *in_history,
     295                 :            :                                int cir_start, int cir_end)
     296                 :            : {
     297                 :            :         int rc;
     298                 :        289 :         int num_entries = in_history->num_entries;
     299                 :            : 
     300         [ -  + ]:        289 :         if (cir_end > cir_start) {
     301   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Wrong using of circular_buffer_padding_across\n");
     302                 :          0 :                 return -1;
     303                 :            :         }
     304                 :            : 
     305                 :        289 :         rc = cont_write(fd, &in_history->entries[cir_start],
     306                 :        289 :                         sizeof(struct spdk_trace_entry) * (num_entries - cir_start));
     307         [ -  + ]:        289 :         if (rc < 0) {
     308   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to append entries into lcore file backward\n");
     309                 :          0 :                 return rc;
     310                 :            :         }
     311                 :            : 
     312         [ +  + ]:        289 :         if (cir_end == 0) {
     313                 :        122 :                 return 0;
     314                 :            :         }
     315                 :            : 
     316                 :        167 :         rc = cont_write(fd, &in_history->entries[0], sizeof(struct spdk_trace_entry) * cir_end);
     317         [ -  + ]:        167 :         if (rc < 0) {
     318   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to append entries into lcore file forward\n");
     319                 :          0 :                 return rc;
     320                 :            :         }
     321                 :            : 
     322                 :        167 :         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                 :   13294780 : lcore_trace_record(struct lcore_trace_record_ctx *lcore_port)
     334                 :            : {
     335                 :   13294780 :         struct spdk_trace_history       *in_history = lcore_port->in_history;
     336                 :   13294780 :         uint64_t                        rec_next_entry = lcore_port->rec_next_entry;
     337                 :   13294780 :         uint64_t                        rec_num_entries = lcore_port->num_entries;
     338                 :   13294780 :         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                 :   13294780 :         shm_next_entry = in_history->next_entry;
     347                 :            : 
     348                 :            :         /* Ensure all entries of spdk_trace_history are latest to next_entry */
     349                 :   13294780 :         spdk_smp_rmb();
     350                 :            : 
     351         [ +  + ]:   13294780 :         if (shm_next_entry == rec_next_entry) {
     352                 :            :                 /* There is no update */
     353                 :   12786357 :                 return 0;
     354         [ -  + ]:     508423 :         } 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                 :     508423 :         num_cir_entries = in_history->num_entries;
     363                 :     508423 :         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         [ +  + ]:     508423 :         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         [ -  + ]:     508415 :         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         [ -  + ]:     508415 :         } 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                 :     508415 :                 rec_cir_next = rec_next_entry & (num_cir_entries - 1);
     402                 :            : 
     403         [ +  + ]:     508415 :                 if (shm_cir_next > rec_cir_next) {
     404                 :            :                         /* Updates are not across circular buffer */
     405                 :     508126 :                         lcore_port->num_entries += shm_cir_next - rec_cir_next;
     406                 :     508126 :                         rc = circular_buffer_padding_backward(fd, in_history, rec_cir_next, shm_cir_next);
     407                 :            :                 } else {
     408                 :            :                         /* Updates are across circular buffer */
     409                 :        289 :                         lcore_port->num_entries += num_cir_entries - rec_cir_next + shm_cir_next;
     410                 :        289 :                         rc = circular_buffer_padding_across(fd, in_history, rec_cir_next, shm_cir_next);
     411                 :            :                 }
     412                 :            :         }
     413                 :            : 
     414                 :     508423 : out:
     415         [ -  + ]:     508423 :         if (rc) {
     416                 :          0 :                 return rc;
     417                 :            :         }
     418                 :            : 
     419         [ -  + ]:     508423 :         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   [ -  +  -  + ]:     508423 :         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                 :     508423 :         last_idx = lcore_trace_last_entry_idx(in_history, shm_cir_next);
     429                 :     508423 :         lcore_port->last_entry_tsc = in_history->entries[last_idx].tsc;
     430                 :     508423 :         lcore_port->rec_next_entry = shm_next_entry;
     431                 :            : 
     432                 :     508423 :         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 + 1];
     442                 :            :         int rc, i;
     443                 :          2 :         ssize_t len = 0;
     444                 :            :         uint64_t current_offset;
     445                 :            :         uint64_t len_sum;
     446                 :            : 
     447         [ -  + ]:          2 :         ctx->out_fd = open(ctx->out_file, flags, 0600);
     448         [ -  + ]:          2 :         if (ctx->out_fd < 0) {
     449   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Could not open aggregation file %s.\n", ctx->out_file);
     450                 :          0 :                 return -1;
     451                 :            :         }
     452                 :            : 
     453         [ -  + ]:          2 :         if (g_verbose) {
     454         [ #  # ]:          0 :                 printf("Create trace file %s for output\n", ctx->out_file);
     455                 :            :         }
     456                 :            : 
     457                 :            :         /* Write flags of histories into head of converged trace file, except num_entriess */
     458                 :          2 :         rc = cont_write(ctx->out_fd, ctx->trace_histories,
     459                 :            :                         sizeof(struct spdk_trace_histories) - sizeof(lcore_offsets));
     460         [ -  + ]:          2 :         if (rc < 0) {
     461   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to write trace header into trace file\n");
     462                 :          0 :                 goto out;
     463                 :            :         }
     464                 :            : 
     465                 :            :         /* Update and append lcore offsets converged trace file */
     466                 :          2 :         current_offset = sizeof(struct spdk_trace_flags);
     467         [ +  + ]:        258 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     468                 :        256 :                 lcore_port = &ctx->lcore_ports[i];
     469   [ -  +  +  + ]:        256 :                 if (lcore_port->valid) {
     470                 :          8 :                         lcore_offsets[i] = current_offset;
     471                 :          8 :                         current_offset += spdk_get_trace_history_size(lcore_port->num_entries);
     472                 :            :                 } else {
     473                 :        248 :                         lcore_offsets[i] = 0;
     474                 :            :                 }
     475                 :            :         }
     476                 :          2 :         lcore_offsets[SPDK_TRACE_MAX_LCORE] = current_offset;
     477                 :            : 
     478                 :          2 :         rc = cont_write(ctx->out_fd, lcore_offsets, sizeof(lcore_offsets));
     479         [ -  + ]:          2 :         if (rc < 0) {
     480   [ #  #  #  # ]:          0 :                 fprintf(stderr, "Failed to write lcore offsets into trace file\n");
     481                 :          0 :                 goto out;
     482                 :            :         }
     483                 :            : 
     484                 :            :         /* Append each lcore trace file into converged trace file */
     485         [ +  + ]:        258 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     486                 :        256 :                 lcore_port = &ctx->lcore_ports[i];
     487                 :            : 
     488   [ -  +  +  + ]:        256 :                 if (!lcore_port->valid) {
     489                 :        248 :                         continue;
     490                 :            :                 }
     491                 :            : 
     492                 :          8 :                 lcore_port->out_history->num_entries = lcore_port->num_entries;
     493                 :          8 :                 rc = cont_write(ctx->out_fd, lcore_port->out_history, sizeof(struct spdk_trace_history));
     494         [ -  + ]:          8 :                 if (rc < 0) {
     495   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Failed to write lcore trace header into trace file\n");
     496                 :          0 :                         goto out;
     497                 :            :                 }
     498                 :            : 
     499                 :            :                 /* Move file offset to the start of trace_entries */
     500                 :          8 :                 rc = lseek(lcore_port->fd, 0, SEEK_SET);
     501         [ -  + ]:          8 :                 if (rc != 0) {
     502   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Failed to lseek lcore trace file\n");
     503                 :          0 :                         goto out;
     504                 :            :                 }
     505                 :            : 
     506                 :          8 :                 len_sum = 0;
     507         [ +  + ]:       1179 :                 while ((len = cont_read(lcore_port->fd, copy_buff, TRACE_FILE_COPY_SIZE)) > 0) {
     508                 :       1171 :                         len_sum += len;
     509                 :       1171 :                         rc = cont_write(ctx->out_fd, copy_buff, len);
     510         [ -  + ]:       1171 :                         if (rc != len) {
     511   [ #  #  #  # ]:          0 :                                 fprintf(stderr, "Failed to write lcore trace entries into trace file\n");
     512                 :          0 :                                 goto out;
     513                 :            :                         }
     514                 :            :                 }
     515                 :            : 
     516                 :            :                 /* Clear rc so that the last cont_write() doesn't get interpreted as a failure. */
     517                 :          8 :                 rc = 0;
     518                 :            : 
     519         [ -  + ]:          8 :                 if (len_sum != lcore_port->num_entries * sizeof(struct spdk_trace_entry)) {
     520   [ #  #  #  # ]:          0 :                         fprintf(stderr, "Len of lcore trace file doesn't match number of entries for lcore\n");
     521                 :            :                 }
     522                 :            :         }
     523                 :            : 
     524         [ -  + ]:          2 :         printf("All lcores trace entries are aggregated into trace file %s\n", ctx->out_file);
     525                 :            : 
     526                 :          2 : out:
     527                 :          2 :         close(ctx->out_fd);
     528                 :            : 
     529                 :          2 :         return rc;
     530                 :            : }
     531                 :            : 
     532                 :            : static void
     533                 :          2 : __shutdown_signal(int signo)
     534                 :            : {
     535                 :          2 :         g_shutdown = true;
     536                 :          2 : }
     537                 :            : 
     538                 :            : static int
     539                 :          2 : setup_exit_signal_handler(void)
     540                 :            : {
     541                 :          0 :         struct sigaction        sigact;
     542                 :            :         int                     rc;
     543                 :            : 
     544         [ -  + ]:          2 :         memset(&sigact, 0, sizeof(sigact));
     545         [ -  + ]:          2 :         sigemptyset(&sigact.sa_mask);
     546                 :            :         /* Install the same handler for SIGINT and SIGTERM */
     547                 :          2 :         sigact.sa_handler = __shutdown_signal;
     548                 :            : 
     549                 :          2 :         rc = sigaction(SIGINT, &sigact, NULL);
     550         [ -  + ]:          2 :         if (rc < 0) {
     551   [ #  #  #  # ]:          0 :                 fprintf(stderr, "sigaction(SIGINT) failed\n");
     552                 :            : 
     553                 :          0 :                 return rc;
     554                 :            :         }
     555                 :            : 
     556                 :          2 :         rc = sigaction(SIGTERM, &sigact, NULL);
     557         [ -  + ]:          2 :         if (rc < 0) {
     558   [ #  #  #  # ]:          0 :                 fprintf(stderr, "sigaction(SIGTERM) failed\n");
     559                 :            :         }
     560                 :            : 
     561                 :          2 :         return rc;
     562                 :            : }
     563                 :            : 
     564                 :            : static void
     565                 :          0 : usage(void)
     566                 :            : {
     567         [ #  # ]:          0 :         printf("\n%s is used to record all SPDK generated trace entries\n", g_exe_name);
     568         [ #  # ]:          0 :         printf("from SPDK trace shared-memory to specified file.\n\n");
     569         [ #  # ]:          0 :         printf("usage:\n");
     570         [ #  # ]:          0 :         printf("   %s <option>\n", g_exe_name);
     571         [ #  # ]:          0 :         printf("        option = '-q' to disable verbose mode\n");
     572         [ #  # ]:          0 :         printf("                 '-s' to specify spdk_trace shm name for a\n");
     573         [ #  # ]:          0 :         printf("                      currently running process\n");
     574         [ #  # ]:          0 :         printf("                 '-i' to specify the shared memory ID\n");
     575         [ #  # ]:          0 :         printf("                 '-p' to specify the trace PID\n");
     576         [ #  # ]:          0 :         printf("                      (one of -i or -p must be specified)\n");
     577         [ #  # ]:          0 :         printf("                 '-f' to specify output trace file name\n");
     578         [ #  # ]:          0 :         printf("                 '-h' to print usage information\n");
     579                 :          0 : }
     580                 :            : 
     581                 :            : int
     582                 :          2 : main(int argc, char **argv)
     583                 :            : {
     584                 :          2 :         const char                      *app_name = NULL;
     585                 :          2 :         const char                      *file_name = NULL;
     586                 :            :         int                             op;
     587                 :          0 :         char                            shm_name[64];
     588                 :          2 :         int                             shm_id = -1, shm_pid = -1;
     589                 :          2 :         int                             rc = 0;
     590                 :            :         int                             i;
     591                 :          2 :         struct aggr_trace_record_ctx    ctx = {};
     592                 :            :         struct lcore_trace_record_ctx   *lcore_port;
     593                 :            : 
     594                 :          2 :         g_exe_name = argv[0];
     595   [ -  +  -  +  :         10 :         while ((op = getopt(argc, argv, "f:i:p:qs:h")) != -1) {
                   +  + ]
     596   [ -  +  +  +  :          8 :                 switch (op) {
                +  -  - ]
     597                 :          0 :                 case 'i':
     598                 :          0 :                         shm_id = spdk_strtol(optarg, 10);
     599                 :          0 :                         break;
     600                 :          2 :                 case 'p':
     601                 :          2 :                         shm_pid = spdk_strtol(optarg, 10);
     602                 :          2 :                         break;
     603                 :          2 :                 case 'q':
     604                 :          2 :                         g_verbose = 0;
     605                 :          2 :                         break;
     606                 :          2 :                 case 's':
     607                 :          2 :                         app_name = optarg;
     608                 :          2 :                         break;
     609                 :          2 :                 case 'f':
     610                 :          2 :                         file_name = optarg;
     611                 :          2 :                         break;
     612                 :          0 :                 case 'h':
     613                 :          0 :                         usage();
     614                 :          0 :                         exit(EXIT_SUCCESS);
     615                 :          0 :                 default:
     616                 :          0 :                         usage();
     617                 :          0 :                         exit(1);
     618                 :            :                 }
     619                 :            :         }
     620                 :            : 
     621         [ -  + ]:          2 :         if (file_name == NULL) {
     622   [ #  #  #  # ]:          0 :                 fprintf(stderr, "-f must be specified\n");
     623                 :          0 :                 usage();
     624                 :          0 :                 exit(1);
     625                 :            :         }
     626                 :            : 
     627         [ -  + ]:          2 :         if (app_name == NULL) {
     628   [ #  #  #  # ]:          0 :                 fprintf(stderr, "-s must be specified\n");
     629                 :          0 :                 usage();
     630                 :          0 :                 exit(1);
     631                 :            :         }
     632                 :            : 
     633   [ +  -  -  + ]:          2 :         if (shm_id == -1 && shm_pid == -1) {
     634   [ #  #  #  # ]:          0 :                 fprintf(stderr, "-i or -p must be specified\n");
     635                 :          0 :                 usage();
     636                 :          0 :                 exit(1);
     637                 :            :         }
     638                 :            : 
     639         [ -  + ]:          2 :         if (shm_id >= 0) {
     640         [ #  # ]:          0 :                 snprintf(shm_name, sizeof(shm_name), "/%s_trace.%d", app_name, shm_id);
     641                 :            :         } else {
     642         [ -  + ]:          2 :                 snprintf(shm_name, sizeof(shm_name), "/%s_trace.pid%d", app_name, shm_pid);
     643                 :            :         }
     644                 :            : 
     645                 :          2 :         rc = setup_exit_signal_handler();
     646         [ -  + ]:          2 :         if (rc) {
     647                 :          0 :                 exit(1);
     648                 :            :         }
     649                 :            : 
     650                 :          2 :         rc = input_trace_file_mmap(&ctx, shm_name);
     651         [ -  + ]:          2 :         if (rc) {
     652                 :          0 :                 exit(1);
     653                 :            :         }
     654                 :            : 
     655                 :          2 :         rc = output_trace_files_prepare(&ctx, file_name);
     656         [ -  + ]:          2 :         if (rc) {
     657                 :          0 :                 exit(1);
     658                 :            :         }
     659                 :            : 
     660         [ -  + ]:          2 :         printf("Start to poll trace shm file %s\n", shm_name);
     661   [ -  +  +  +  :    3323699 :         while (!g_shutdown && rc == 0) {
                   +  - ]
     662         [ +  + ]:  428756655 :                 for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     663                 :  425432960 :                         lcore_port = &ctx.lcore_ports[i];
     664                 :            : 
     665   [ -  +  +  + ]:  425432960 :                         if (!lcore_port->valid) {
     666                 :  412138180 :                                 continue;
     667                 :            :                         }
     668                 :   13294780 :                         rc = lcore_trace_record(lcore_port);
     669         [ -  + ]:   13294780 :                         if (rc) {
     670                 :          0 :                                 break;
     671                 :            :                         }
     672                 :            :                 }
     673                 :            :         }
     674                 :            : 
     675         [ -  + ]:          2 :         if (rc) {
     676                 :          0 :                 exit(1);
     677                 :            :         }
     678                 :            : 
     679         [ -  + ]:          2 :         printf("Start to aggregate lcore trace files\n");
     680                 :          2 :         rc = trace_files_aggregate(&ctx);
     681         [ -  + ]:          2 :         if (rc) {
     682                 :          0 :                 exit(1);
     683                 :            :         }
     684                 :            : 
     685                 :            :         /* Summary report */
     686         [ -  + ]:          2 :         printf("TSC Rate: %ju\n", g_tsc_rate);
     687         [ +  + ]:        258 :         for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) {
     688                 :        256 :                 lcore_port = &ctx.lcore_ports[i];
     689                 :            : 
     690         [ +  + ]:        256 :                 if (lcore_port->num_entries == 0) {
     691                 :        248 :                         continue;
     692                 :            :                 }
     693                 :            : 
     694         [ -  + ]:          8 :                 printf("Port %ju trace entries for lcore (%d) in %ju usec\n",
     695                 :            :                        lcore_port->num_entries, i,
     696         [ -  + ]:          8 :                        (lcore_port->last_entry_tsc - lcore_port->first_entry_tsc) / g_utsc_rate);
     697                 :            : 
     698                 :            :         }
     699                 :            : 
     700                 :          2 :         munmap(ctx.trace_histories, g_histories_size);
     701                 :          2 :         close(ctx.shm_fd);
     702                 :            : 
     703                 :          2 :         output_trace_files_finish(&ctx);
     704                 :            : 
     705                 :          2 :         return 0;
     706                 :            : }

Generated by: LCOV version 1.14