]>
git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/app/trace/trace.cpp
4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/types.h>
52 #include "spdk/trace.h"
55 static struct spdk_trace_histories
*g_histories
;
57 static void usage(void);
60 entry_key(uint16_t _lcore
, uint64_t _tsc
) : lcore(_lcore
), tsc(_tsc
) {}
65 class compare_entry_key
68 bool operator()(const entry_key
&first
, const entry_key
&second
) const
70 if (first
.tsc
== second
.tsc
) {
71 return first
.lcore
< second
.lcore
;
73 return first
.tsc
< second
.tsc
;
78 typedef std::map
<entry_key
, spdk_trace_entry
*, compare_entry_key
> entry_map
;
80 entry_map g_entry_map
;
84 std::map
<uint64_t, uint64_t> start
;
85 std::map
<uint64_t, uint64_t> index
;
86 std::map
<uint64_t, uint64_t> size
;
87 std::map
<uint64_t, uint64_t> tpoint_id
;
90 object_stats() : start(), index(), size(), tpoint_id(), counter(0) {}
93 struct object_stats g_stats
[SPDK_TRACE_MAX_OBJECT
];
95 static char *exe_name
;
96 static int verbose
= 1;
97 static int g_fudge_factor
= 20;
99 static uint64_t tsc_rate
;
100 static uint64_t first_tsc
= 0x0;
101 static uint64_t last_tsc
= -1ULL;
104 get_us_from_tsc(uint64_t tsc
, uint64_t tsc_rate
)
106 return ((float)tsc
) * 1000 * 1000 / tsc_rate
;
110 print_ptr(const char *arg_string
, uint64_t arg
)
112 printf("%-7.7s0x%-14jx ", arg_string
, arg
);
116 print_uint64(const char *arg_string
, uint64_t arg
)
119 * Print arg as signed, since -1 is a common value especially
120 * for FLUSH WRITEBUF when writev() returns -1 due to full
123 printf("%-7.7s%-16jd ", arg_string
, arg
);
127 print_size(uint32_t size
)
130 printf("size: %6u ", size
);
137 print_object_id(uint8_t type
, uint64_t id
)
139 printf("id: %c%-15jd ", g_histories
->object
[type
].id_prefix
, id
);
143 print_float(const char *arg_string
, float arg
)
145 printf("%-7s%-16.3f ", arg_string
, arg
);
149 print_arg(bool arg_is_ptr
, const char *arg_string
, uint64_t arg
)
151 if (arg_string
[0] == 0)
155 print_ptr(arg_string
, arg
);
157 print_uint64(arg_string
, arg
);
161 print_event(struct spdk_trace_entry
*e
, uint64_t tsc_rate
,
162 uint64_t tsc_offset
, uint16_t lcore
)
164 struct spdk_trace_tpoint
*d
;
165 struct object_stats
*stats
;
168 d
= &g_histories
->tpoint
[e
->tpoint_id
];
169 stats
= &g_stats
[d
->object_type
];
172 stats
->index
[e
->object_id
] = stats
->counter
++;
173 stats
->tpoint_id
[e
->object_id
] = e
->tpoint_id
;
174 stats
->start
[e
->object_id
] = e
->tsc
;
175 stats
->size
[e
->object_id
] = e
->size
;
178 if (d
->arg1_is_alias
) {
179 stats
->index
[e
->arg1
] = stats
->index
[e
->object_id
];
180 stats
->start
[e
->arg1
] = stats
->start
[e
->object_id
];
181 stats
->size
[e
->arg1
] = stats
->size
[e
->object_id
];
184 us
= get_us_from_tsc(e
->tsc
- tsc_offset
, tsc_rate
);
186 printf("%2d: %10.3f (%9ju) ", lcore
, us
, e
->tsc
- tsc_offset
);
187 if (g_histories
->owner
[d
->owner_type
].id_prefix
) {
188 printf("%c%02d ", g_histories
->owner
[d
->owner_type
].id_prefix
, e
->poller_id
);
193 printf("%-*s ", (int)sizeof(d
->name
), d
->name
);
197 print_arg(d
->arg1_is_ptr
, d
->arg1_name
, e
->arg1
);
198 print_object_id(d
->object_type
, stats
->index
[e
->object_id
]);
199 } else if (d
->object_type
!= OBJECT_NONE
) {
200 if (stats
->start
.find(e
->object_id
) != stats
->start
.end()) {
201 struct spdk_trace_tpoint
*start_description
;
203 us
= get_us_from_tsc(e
->tsc
- stats
->start
[e
->object_id
],
205 print_object_id(d
->object_type
, stats
->index
[e
->object_id
]);
206 print_float("time:", us
);
207 start_description
= &g_histories
->tpoint
[stats
->tpoint_id
[e
->object_id
]];
208 if (start_description
->short_name
[0] != 0) {
209 printf(" (%.4s)", start_description
->short_name
);
215 print_arg(d
->arg1_is_ptr
, d
->arg1_name
, e
->arg1
);
221 process_event(struct spdk_trace_entry
*e
, uint64_t tsc_rate
,
222 uint64_t tsc_offset
, uint16_t lcore
)
225 print_event(e
, tsc_rate
, tsc_offset
, lcore
);
230 populate_events(struct spdk_trace_history
*history
)
232 int i
, entry_size
, history_size
, num_entries
, num_entries_filled
;
233 struct spdk_trace_entry
*e
;
234 int first
, last
, lcore
;
236 lcore
= history
->lcore
;
238 entry_size
= sizeof(history
->entries
[0]);
239 history_size
= sizeof(history
->entries
);
240 num_entries
= history_size
/ entry_size
;
242 e
= history
->entries
;
244 num_entries_filled
= num_entries
;
245 while (e
[num_entries_filled
- 1].tsc
== 0) {
246 num_entries_filled
--;
249 if (num_entries
== num_entries_filled
) {
251 for (i
= 1; i
< num_entries
; i
++) {
252 if (e
[i
].tsc
< e
[first
].tsc
)
254 if (e
[i
].tsc
> e
[last
].tsc
)
258 first
+= g_fudge_factor
;
259 if (first
>= num_entries
)
260 first
-= num_entries
;
262 last
-= g_fudge_factor
;
267 last
= num_entries_filled
- 1;
271 * We keep track of the highest first TSC out of all reactors and
272 * the lowest last TSC out of all reactors. We will ignore any
273 * events outside the range of these two TSC values. This will
274 * ensure we only print data for the subset of time where we have
275 * data across all reactors.
277 if (e
[first
].tsc
> first_tsc
) {
278 first_tsc
= e
[first
].tsc
;
280 if (e
[last
].tsc
< last_tsc
) {
281 last_tsc
= e
[last
].tsc
;
286 g_entry_map
[entry_key(lcore
, e
[i
].tsc
)] = &e
[i
];
291 if (i
== num_entries_filled
) {
299 static void usage(void)
301 fprintf(stderr
, "usage:\n");
302 fprintf(stderr
, " %s <option> <lcore#>\n", exe_name
);
303 fprintf(stderr
, " option = '-q' to disable verbose mode\n");
304 fprintf(stderr
, " '-s' to specify spdk_trace shm name\n");
305 fprintf(stderr
, " '-c' to display single lcore history\n");
306 fprintf(stderr
, " '-f' to specify number of events to ignore at\n");
307 fprintf(stderr
, " beginning and end of trace (default: 20)\n");
308 fprintf(stderr
, " '-i' to specify the shared memory ID\n");
309 fprintf(stderr
, " '-p' to specify the trace PID\n");
310 fprintf(stderr
, " (One of -i or -p must be specified)\n");
313 int main(int argc
, char **argv
)
316 struct spdk_trace_history
*history_entries
, *history
;
318 int lcore
= SPDK_TRACE_MAX_LCORE
;
320 const char *app_name
= "ids";
323 int shm_id
= -1, shm_pid
= -1;
326 while ((op
= getopt(argc
, argv
, "c:f:i:p:qs:")) != -1) {
329 lcore
= atoi(optarg
);
330 if (lcore
> SPDK_TRACE_MAX_LCORE
) {
331 fprintf(stderr
, "Selected lcore: %d "
332 "exceeds maximum %d\n", lcore
,
333 SPDK_TRACE_MAX_LCORE
);
338 g_fudge_factor
= atoi(optarg
);
341 shm_id
= atoi(optarg
);
344 shm_pid
= atoi(optarg
);
359 snprintf(shm_name
, sizeof(shm_name
), "/%s_trace.%d", app_name
, shm_id
);
361 snprintf(shm_name
, sizeof(shm_name
), "/%s_trace.pid%d", app_name
, shm_pid
);
364 fd
= shm_open(shm_name
, O_RDONLY
, 0600);
366 fprintf(stderr
, "Could not open shm %s.\n", shm_name
);
371 history_ptr
= mmap(NULL
, sizeof(*g_histories
), PROT_READ
, MAP_SHARED
, fd
, 0);
372 if (history_ptr
== MAP_FAILED
) {
373 fprintf(stderr
, "Could not mmap shm %s.\n", shm_name
);
378 g_histories
= (struct spdk_trace_histories
*)history_ptr
;
380 tsc_rate
= g_histories
->tsc_rate
;
382 fprintf(stderr
, "Invalid tsc_rate %ju\n", tsc_rate
);
388 printf("TSC Rate: %ju\n", tsc_rate
);
391 history_entries
= (struct spdk_trace_history
*)malloc(sizeof(g_histories
->per_lcore_history
));
392 if (history_entries
== NULL
) {
395 memcpy(history_entries
, g_histories
->per_lcore_history
,
396 sizeof(g_histories
->per_lcore_history
));
398 if (lcore
== SPDK_TRACE_MAX_LCORE
) {
399 for (i
= 0; i
< SPDK_TRACE_MAX_LCORE
; i
++) {
400 history
= &history_entries
[i
];
401 if (history
->entries
[0].tsc
== 0) {
404 populate_events(history
);
407 history
= &history_entries
[lcore
];
408 if (history
->entries
[0].tsc
!= 0) {
409 populate_events(history
);
413 tsc_offset
= first_tsc
;
414 for (entry_map::iterator it
= g_entry_map
.begin(); it
!= g_entry_map
.end(); it
++) {
415 if (it
->first
.tsc
< first_tsc
|| it
->first
.tsc
> last_tsc
) {
418 process_event(it
->second
, tsc_rate
, tsc_offset
, it
->first
.lcore
);
421 free(history_entries
);
424 munmap(history_ptr
, sizeof(*g_histories
));