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
print_c_header(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
print_event(entry_t * ent)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
print_sorted_events(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
describe_c_record(tnf_datum_t datum)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
describe_probe_type(tnf_datum_t datum)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
insert_event(tnf_datum_t datum,tnf_datum_t schedule_rec)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
describe_event(tnf_datum_t datum,tnf_datum_t schedule_rec,hrtime_t evt_time)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
describe_c_struct(tnf_datum_t datum)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
describe_c_brief(tnf_datum_t datum)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
describe_target(tnf_datum_t datum)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