1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1994, by Sun Microsytems, Inc. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <unistd.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <fcntl.h> 32 #include <sys/mman.h> 33 #include <stdio.h> 34 #include <stdarg.h> 35 #include <string.h> 36 #include <unistd.h> 37 #include <tnf/tnf.h> 38 #include <errno.h> 39 #include <libintl.h> 40 41 #include "state.h" 42 43 #define STREQ(s1, s2, n) (strncmp(s1, s2, n) == 0) 44 45 #define IS_64BIT(kind) ((1 << kind) & \ 46 ((1 << TNF_K_UINT64) | (1 << TNF_K_INT64))) 47 48 #define PROBE_TYPE "tnf_probe_type" 49 50 static void print_event (entry_t *ent); 51 static void insert_event (tnf_datum_t, tnf_datum_t); 52 static void describe_c_brief (tnf_datum_t); 53 static void describe_target (tnf_datum_t); 54 static void describe_c_struct (tnf_datum_t); 55 static void describe_probe_type (tnf_datum_t); 56 static void describe_event (tnf_datum_t, tnf_datum_t, hrtime_t); 57 58 static hrtime_t base_time = 0; 59 60 void 61 print_c_header(void) 62 { 63 (void) printf("%16s %16s %5s %5s %10s %3s %-25s %s\n", 64 "----------------", "----------------", "-----", "-----", 65 "----------", "---", "-------------------------", 66 "------------------------"); 67 (void) printf("%16s %16s %5s %5s %10s %3s %-25s %s\n", 68 "Elapsed (ms)", "Delta (ms)", "PID", "LWPID", 69 " TID ", "CPU", "Probe Name", "Data / Description . . ."); 70 (void) printf("%16s %16s %5s %5s %10s %3s %-25s %s\n", 71 "----------------", "----------------", "-----", "-----", 72 "----------", "---", "-------------------------", 73 "------------------------"); 74 } 75 76 static void 77 print_event(entry_t *ent) 78 { 79 tnf_datum_t evt, sched; 80 hrtime_t normalized_time; 81 82 evt = ent->record; 83 sched = tnf_get_tag_arg(evt); 84 if (sched == TNF_DATUM_NULL) { 85 /* 86 * should never happen because it had a schedule 87 * record earlier 88 */ 89 fail(0, gettext("event without a schedule record")); 90 } 91 normalized_time = ent->time - base_time; 92 describe_event(evt, sched, normalized_time); 93 } 94 95 void 96 print_sorted_events(void) 97 { 98 entry_t *ent; 99 100 table_sort(); 101 ent = table_get_entry_indexed(0); 102 if (ent) { 103 base_time = ent->time; 104 } 105 table_print(&print_event); 106 } 107 108 void 109 describe_c_record(tnf_datum_t datum) 110 { 111 char *name_str; 112 tnf_datum_t schedule_rec; 113 114 switch (tnf_get_kind(datum)) { 115 116 case TNF_K_STRUCT: 117 /* print only event records */ 118 schedule_rec = tnf_get_tag_arg(datum); 119 if (schedule_rec != TNF_DATUM_NULL) { 120 /* event record */ 121 insert_event(datum, schedule_rec); 122 } 123 break; 124 case TNF_K_STRING: 125 case TNF_K_ARRAY: 126 /* Skip arrays at top level */ 127 break; 128 case TNF_K_TYPE: 129 name_str = tnf_get_type_name(datum); 130 /* REMIND: filter based on property */ 131 if (STREQ(name_str, PROBE_TYPE, strlen(name_str))) 132 describe_probe_type(datum); 133 break; 134 default: 135 fail(0, gettext("illegal record at %x (%d)"), 136 tnf_get_raw(datum), tnf_get_kind(datum)); 137 break; 138 } 139 140 } 141 142 static void 143 describe_probe_type(tnf_datum_t datum) 144 { 145 unsigned n, i; 146 char *slotname; 147 size_t slot_len; 148 149 n = tnf_get_slot_count(datum); 150 #if 0 151 /* print the OUTPUT PAD */ 152 (void) printf("%16s %14s %5s %5s %8s %3s %-25s", 153 "-", "-", "-", "-", "-", "-", "-"); 154 #endif 155 (void) printf("probe\t"); 156 for (i = 0; i < n; i++) { 157 slotname = tnf_get_slot_name(datum, i); 158 slot_len = strlen(slotname); 159 160 /* print all fields except ... */ 161 if ((!STREQ(slotname, TNF_N_TAG, slot_len)) && 162 (!STREQ(slotname, TNF_N_PROPERTIES, slot_len)) && 163 (!STREQ(slotname, TNF_N_SLOT_TYPES, slot_len)) && 164 (!STREQ(slotname, TNF_N_TYPE_SIZE, slot_len)) && 165 (!STREQ(slotname, TNF_N_SLOT_NAMES, slot_len))) { 166 (void) printf(" "); 167 (void) printf("%s: ", slotname); 168 describe_c_brief(tnf_get_slot_indexed(datum, 169 i)); 170 } 171 } 172 (void) printf("\n"); 173 } 174 175 static void 176 insert_event(tnf_datum_t datum, tnf_datum_t schedule_rec) 177 { 178 tnf_datum_t temp; 179 hrtime_t evt_time; 180 unsigned time_delta = 0; 181 entry_t element; 182 183 temp = tnf_get_slot_named(schedule_rec, TNF_N_TIME_BASE); 184 evt_time = tnf_get_int64(temp); 185 temp = tnf_get_slot_named(datum, TNF_N_TIME_DELTA); 186 time_delta = (unsigned) tnf_get_int32(temp); 187 evt_time = evt_time + time_delta; 188 189 element.time = evt_time; 190 element.record = datum; 191 table_insert(&element); 192 } 193 194 #define K_TID "tnf_kthread_id" 195 #define CPUID "cpuid" 196 197 static void 198 describe_event(tnf_datum_t datum, tnf_datum_t schedule_rec, hrtime_t evt_time) 199 { 200 unsigned n, i; 201 char *slotname, *eventname, *tidtype; 202 tnf_datum_t temp; 203 int lwpid = 0, pid = 0; 204 int start_slots = 0; 205 static hrtime_t last_time = 0; 206 unsigned long long tid = 0; 207 208 temp = tnf_get_slot_named(schedule_rec, TNF_N_TID); 209 if (IS_64BIT(tnf_get_kind(temp))) { 210 tid = tnf_get_int64(temp); 211 } else { 212 tid = (unsigned int)tnf_get_int32(temp); 213 } 214 tidtype = tnf_get_type_name(temp); 215 216 temp = tnf_get_slot_named(schedule_rec, TNF_N_LWPID); 217 lwpid = tnf_get_int32(temp); 218 temp = tnf_get_slot_named(schedule_rec, TNF_N_PID); 219 pid = tnf_get_int32(temp); 220 221 /* XXX should use TNF_N_KERNEL_SCHEDULE, TNF_N_USER_SCHEDULE */ 222 if (strcmp(tidtype, K_TID) == 0) { 223 int cpuid; 224 /* XXX Assumes cpuid always exists in kernel schedule */ 225 cpuid = tnf_get_int32(tnf_get_slot_named(schedule_rec, CPUID)); 226 /* print the OUTPUT schedule record for Kernel case */ 227 (void) printf("%16.6f %16.6f %5u %5u 0x%-8llx %3d", 228 evt_time / 1000000.0, 229 (evt_time - last_time)/1000000.0, 230 pid, lwpid, tid, cpuid); 231 } else { 232 /* print the OUTPUT schedule record */ 233 (void) printf("%16.6f %16.6f %5u %5u %10llu %3s", 234 evt_time / 1000000.0, 235 (evt_time - last_time)/1000000.0, 236 pid, lwpid, tid, "-"); 237 } 238 /* print the tag */ 239 eventname = tnf_type_get_name(tnf_get_slot_named(datum, TNF_N_TAG)); 240 (void) printf(" %-25s", eventname); 241 242 /* heuristic - start of data is after TIME_DELTA field */ 243 start_slots = tnf_get_slot_index(datum, TNF_N_TIME_DELTA); 244 start_slots++; 245 246 n = tnf_get_slot_count(datum); 247 248 /* print the rest of the fields */ 249 for (i = start_slots; i < n; i++) { 250 (void) printf(" "); 251 slotname = tnf_get_slot_name(datum, i); 252 (void) printf("%s: ", slotname); 253 describe_target(tnf_get_slot_indexed(datum, i)); 254 } 255 (void) printf("\n"); 256 last_time = evt_time; 257 } 258 259 static void 260 describe_c_struct(tnf_datum_t datum) 261 { 262 unsigned n, i, tag_index; 263 char *slotname; 264 265 n = tnf_get_slot_count(datum); 266 267 /* print the tag */ 268 (void) printf(" "); 269 (void) printf("%s: ", "type"); 270 describe_c_brief(tnf_get_slot_named(datum, TNF_N_TAG)); 271 tag_index = tnf_get_slot_index(datum, TNF_N_TAG); 272 273 for (i = 0; i < n; i++) { 274 /* print the rest of the members */ 275 if (i != tag_index) { 276 (void) printf(" "); 277 slotname = tnf_get_slot_name(datum, i); 278 (void) printf("%s: ", slotname); 279 describe_target(tnf_get_slot_indexed(datum, i)); 280 } 281 } 282 } 283 284 static void 285 describe_c_brief(tnf_datum_t datum) 286 { 287 if (datum == TNF_DATUM_NULL) /* allowed */ 288 (void) printf("0x%-8x <NULL>", 0); 289 290 else if (tnf_is_scalar(datum)) 291 describe_scalar(datum); 292 293 else if (tnf_is_record(datum)) { 294 295 switch (tnf_get_kind(datum)) { 296 case TNF_K_TYPE: 297 (void) printf("%s", tnf_type_get_name(datum)); 298 break; 299 case TNF_K_STRING: 300 (void) printf("\"%s\"", tnf_get_chars(datum)); 301 break; 302 default: 303 (void) printf("<%s>", tnf_get_type_name(datum)); 304 } 305 } else 306 fail(0, gettext("inline aggregate slots/elements unhandled")); 307 } 308 309 static void 310 describe_target(tnf_datum_t datum) 311 { 312 if (datum == TNF_DATUM_NULL) /* allowed */ 313 (void) printf("0x%-8x <NULL>", 0); 314 315 else if (tnf_is_scalar(datum)) 316 describe_scalar(datum); 317 318 else if (tnf_is_record(datum)) { 319 320 switch (tnf_get_kind(datum)) { 321 case TNF_K_STRUCT: 322 (void) printf("{"); 323 describe_c_struct(datum); 324 (void) printf(" }"); 325 break; 326 case TNF_K_TYPE: 327 (void) printf("%s", tnf_type_get_name(datum)); 328 break; 329 case TNF_K_STRING: 330 (void) printf("\"%s\"", tnf_get_chars(datum)); 331 break; 332 default: 333 (void) printf("<%s>", tnf_get_type_name(datum)); 334 } 335 } else 336 fail(0, gettext("inline aggregate slots/elements unhandled")); 337 } 338