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