1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 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 16 * distribution. 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. 20 * 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. 32 */ 33 34 #include "spdk/env.h" 35 #include "spdk/trace.h" 36 37 #include <assert.h> 38 #include <stdint.h> 39 #include <string.h> 40 #include <fcntl.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <unistd.h> 44 #include <sys/types.h> 45 #include <sys/stat.h> 46 #include <sys/mman.h> 47 #include <errno.h> 48 49 #include <rte_config.h> 50 #include <rte_lcore.h> 51 52 static char g_shm_name[64]; 53 54 static struct spdk_trace_histories *g_trace_histories; 55 static struct spdk_trace_register_fn *g_reg_fn_head = NULL; 56 57 void 58 spdk_trace_record(uint16_t tpoint_id, uint16_t poller_id, uint32_t size, 59 uint64_t object_id, uint64_t arg1) 60 { 61 struct spdk_trace_history *lcore_history; 62 struct spdk_trace_entry *next_entry; 63 uint64_t tsc; 64 unsigned lcore; 65 66 /* 67 * Tracepoint group ID is encoded in the tpoint_id. Lower 6 bits determine the tracepoint 68 * within the group, the remaining upper bits determine the tracepoint group. Each 69 * tracepoint group has its own tracepoint mask. 70 */ 71 if (g_trace_histories == NULL || 72 !((1ULL << (tpoint_id & 0x3F)) & g_trace_histories->tpoint_mask[tpoint_id >> 6])) { 73 return; 74 } 75 76 lcore = rte_lcore_id(); 77 if (lcore >= SPDK_TRACE_MAX_LCORE) { 78 return; 79 } 80 81 lcore_history = &g_trace_histories->per_lcore_history[lcore]; 82 tsc = spdk_get_ticks(); 83 84 lcore_history->tpoint_count[tpoint_id]++; 85 86 next_entry = &lcore_history->entries[lcore_history->next_entry]; 87 next_entry->tsc = tsc; 88 next_entry->tpoint_id = tpoint_id; 89 next_entry->poller_id = poller_id; 90 next_entry->size = size; 91 next_entry->object_id = object_id; 92 next_entry->arg1 = arg1; 93 94 lcore_history->next_entry++; 95 if (lcore_history->next_entry == SPDK_TRACE_SIZE) 96 lcore_history->next_entry = 0; 97 } 98 99 uint64_t 100 spdk_trace_get_tpoint_mask(uint32_t group_id) 101 { 102 if (group_id >= SPDK_TRACE_MAX_GROUP_ID) { 103 fprintf(stderr, "%s: invalid group ID %d\n", __func__, group_id); 104 return 0ULL; 105 } 106 107 return g_trace_histories->tpoint_mask[group_id]; 108 } 109 110 void 111 spdk_trace_set_tpoints(uint32_t group_id, uint64_t tpoint_mask) 112 { 113 if (group_id >= SPDK_TRACE_MAX_GROUP_ID) { 114 fprintf(stderr, "%s: invalid group ID %d\n", __func__, group_id); 115 return; 116 } 117 118 g_trace_histories->tpoint_mask[group_id] |= tpoint_mask; 119 } 120 121 void 122 spdk_trace_clear_tpoints(uint32_t group_id, uint64_t tpoint_mask) 123 { 124 if (group_id >= SPDK_TRACE_MAX_GROUP_ID) { 125 fprintf(stderr, "%s: invalid group ID %d\n", __func__, group_id); 126 return; 127 } 128 129 g_trace_histories->tpoint_mask[group_id] &= ~tpoint_mask; 130 } 131 132 uint64_t 133 spdk_trace_get_tpoint_group_mask(void) 134 { 135 uint64_t mask = 0x0; 136 int i; 137 138 for (i = 0; i < 64; i++) { 139 if (spdk_trace_get_tpoint_mask(i) != 0) { 140 mask |= (1ULL << i); 141 } 142 } 143 144 return mask; 145 } 146 147 void 148 spdk_trace_set_tpoint_group_mask(uint64_t tpoint_group_mask) 149 { 150 int i; 151 152 for (i = 0; i < 64; i++) { 153 if (tpoint_group_mask & (1ULL << i)) { 154 spdk_trace_set_tpoints(i, -1ULL); 155 } 156 } 157 } 158 159 void 160 spdk_trace_init(const char *shm_name) 161 { 162 struct spdk_trace_register_fn *reg_fn; 163 int trace_fd; 164 int i = 0; 165 166 strncpy(g_shm_name, shm_name, sizeof(g_shm_name)); 167 168 trace_fd = shm_open(shm_name, O_RDWR | O_CREAT, 0600); 169 if (trace_fd == -1) { 170 fprintf(stderr, "could not shm_open spdk_trace\n"); 171 fprintf(stderr, "errno=%d %s\n", errno, strerror(errno)); 172 exit(EXIT_FAILURE); 173 } 174 175 if (ftruncate(trace_fd, sizeof(*g_trace_histories)) != 0) { 176 fprintf(stderr, "could not truncate shm\n"); 177 exit(EXIT_FAILURE); 178 } 179 180 g_trace_histories = mmap(NULL, sizeof(*g_trace_histories), PROT_READ | PROT_WRITE, 181 MAP_SHARED, trace_fd, 0); 182 if (g_trace_histories == NULL) { 183 fprintf(stderr, "could not mmap shm\n"); 184 exit(EXIT_FAILURE); 185 } 186 187 memset(g_trace_histories, 0, sizeof(*g_trace_histories)); 188 189 g_trace_histories->tsc_rate = spdk_get_ticks_hz(); 190 191 for (i = 0; i < SPDK_TRACE_MAX_LCORE; i++) { 192 g_trace_histories->per_lcore_history[i].lcore = i; 193 } 194 195 reg_fn = g_reg_fn_head; 196 while (reg_fn) { 197 reg_fn->reg_fn(); 198 reg_fn = reg_fn->next; 199 } 200 } 201 202 void 203 spdk_trace_cleanup(void) 204 { 205 munmap(g_trace_histories, sizeof(struct spdk_trace_histories)); 206 shm_unlink(g_shm_name); 207 } 208 209 void 210 spdk_trace_register_owner(uint8_t type, char id_prefix) 211 { 212 struct spdk_trace_owner *owner; 213 214 assert(type != OWNER_NONE); 215 216 /* 'owner' has 256 entries and since 'type' is a uint8_t, it 217 * can't overrun the array. 218 */ 219 owner = &g_trace_histories->owner[type]; 220 assert(owner->type == 0); 221 222 owner->type = type; 223 owner->id_prefix = id_prefix; 224 } 225 226 void 227 spdk_trace_register_object(uint8_t type, char id_prefix) 228 { 229 struct spdk_trace_object *object; 230 231 assert(type != OBJECT_NONE); 232 233 /* 'object' has 256 entries and since 'type' is a uint8_t, it 234 * can't overrun the array. 235 */ 236 object = &g_trace_histories->object[type]; 237 assert(object->type == 0); 238 239 object->type = type; 240 object->id_prefix = id_prefix; 241 } 242 243 void 244 spdk_trace_register_description(const char *name, const char *short_name, 245 uint16_t tpoint_id, uint8_t owner_type, 246 uint8_t object_type, uint8_t new_object, 247 uint8_t arg1_is_ptr, uint8_t arg1_is_alias, 248 const char *arg1_name) 249 { 250 struct spdk_trace_tpoint *tpoint; 251 252 assert(tpoint_id != 0); 253 assert(tpoint_id < SPDK_TRACE_MAX_TPOINT_ID); 254 255 tpoint = &g_trace_histories->tpoint[tpoint_id]; 256 assert(tpoint->tpoint_id == 0); 257 258 strncpy(tpoint->name, name, sizeof(tpoint->name)); 259 strncpy(tpoint->short_name, short_name, sizeof(tpoint->short_name)); 260 tpoint->tpoint_id = tpoint_id; 261 tpoint->object_type = object_type; 262 tpoint->owner_type = owner_type; 263 tpoint->new_object = new_object; 264 tpoint->arg1_is_ptr = arg1_is_ptr; 265 tpoint->arg1_is_alias = arg1_is_alias; 266 strncpy(tpoint->arg1_name, arg1_name, sizeof(tpoint->arg1_name)); 267 } 268 269 void 270 spdk_trace_add_register_fn(struct spdk_trace_register_fn *reg_fn) 271 { 272 reg_fn->next = g_reg_fn_head; 273 g_reg_fn_head = reg_fn; 274 } 275