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