/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1994, by Sun Microsytems, Inc. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include #include #include #include #include "state.h" #define STREQ(s1, s2, n) (strncmp(s1, s2, n) == 0) #define IS_64BIT(kind) ((1 << kind) & \ ((1 << TNF_K_UINT64) | (1 << TNF_K_INT64))) #define PROBE_TYPE "tnf_probe_type" static void print_event (entry_t *ent); static void insert_event (tnf_datum_t, tnf_datum_t); static void describe_c_brief (tnf_datum_t); static void describe_target (tnf_datum_t); static void describe_c_struct (tnf_datum_t); static void describe_probe_type (tnf_datum_t); static void describe_event (tnf_datum_t, tnf_datum_t, hrtime_t); static hrtime_t base_time = 0; void print_c_header(void) { (void) printf("%16s %16s %5s %5s %10s %3s %-25s %s\n", "----------------", "----------------", "-----", "-----", "----------", "---", "-------------------------", "------------------------"); (void) printf("%16s %16s %5s %5s %10s %3s %-25s %s\n", "Elapsed (ms)", "Delta (ms)", "PID", "LWPID", " TID ", "CPU", "Probe Name", "Data / Description . . ."); (void) printf("%16s %16s %5s %5s %10s %3s %-25s %s\n", "----------------", "----------------", "-----", "-----", "----------", "---", "-------------------------", "------------------------"); } static void print_event(entry_t *ent) { tnf_datum_t evt, sched; hrtime_t normalized_time; evt = ent->record; sched = tnf_get_tag_arg(evt); if (sched == TNF_DATUM_NULL) { /* * should never happen because it had a schedule * record earlier */ fail(0, gettext("event without a schedule record")); } normalized_time = ent->time - base_time; describe_event(evt, sched, normalized_time); } void print_sorted_events(void) { entry_t *ent; table_sort(); ent = table_get_entry_indexed(0); if (ent) { base_time = ent->time; } table_print(&print_event); } void describe_c_record(tnf_datum_t datum) { char *name_str; tnf_datum_t schedule_rec; switch (tnf_get_kind(datum)) { case TNF_K_STRUCT: /* print only event records */ schedule_rec = tnf_get_tag_arg(datum); if (schedule_rec != TNF_DATUM_NULL) { /* event record */ insert_event(datum, schedule_rec); } break; case TNF_K_STRING: case TNF_K_ARRAY: /* Skip arrays at top level */ break; case TNF_K_TYPE: name_str = tnf_get_type_name(datum); /* REMIND: filter based on property */ if (STREQ(name_str, PROBE_TYPE, strlen(name_str))) describe_probe_type(datum); break; default: fail(0, gettext("illegal record at %x (%d)"), tnf_get_raw(datum), tnf_get_kind(datum)); break; } } static void describe_probe_type(tnf_datum_t datum) { unsigned n, i; char *slotname; size_t slot_len; n = tnf_get_slot_count(datum); #if 0 /* print the OUTPUT PAD */ (void) printf("%16s %14s %5s %5s %8s %3s %-25s", "-", "-", "-", "-", "-", "-", "-"); #endif (void) printf("probe\t"); for (i = 0; i < n; i++) { slotname = tnf_get_slot_name(datum, i); slot_len = strlen(slotname); /* print all fields except ... */ if ((!STREQ(slotname, TNF_N_TAG, slot_len)) && (!STREQ(slotname, TNF_N_PROPERTIES, slot_len)) && (!STREQ(slotname, TNF_N_SLOT_TYPES, slot_len)) && (!STREQ(slotname, TNF_N_TYPE_SIZE, slot_len)) && (!STREQ(slotname, TNF_N_SLOT_NAMES, slot_len))) { (void) printf(" "); (void) printf("%s: ", slotname); describe_c_brief(tnf_get_slot_indexed(datum, i)); } } (void) printf("\n"); } static void insert_event(tnf_datum_t datum, tnf_datum_t schedule_rec) { tnf_datum_t temp; hrtime_t evt_time; unsigned time_delta = 0; entry_t element; temp = tnf_get_slot_named(schedule_rec, TNF_N_TIME_BASE); evt_time = tnf_get_int64(temp); temp = tnf_get_slot_named(datum, TNF_N_TIME_DELTA); time_delta = (unsigned) tnf_get_int32(temp); evt_time = evt_time + time_delta; element.time = evt_time; element.record = datum; table_insert(&element); } #define K_TID "tnf_kthread_id" #define CPUID "cpuid" static void describe_event(tnf_datum_t datum, tnf_datum_t schedule_rec, hrtime_t evt_time) { unsigned n, i; char *slotname, *eventname, *tidtype; tnf_datum_t temp; int lwpid = 0, pid = 0; int start_slots = 0; static hrtime_t last_time = 0; unsigned long long tid = 0; temp = tnf_get_slot_named(schedule_rec, TNF_N_TID); if (IS_64BIT(tnf_get_kind(temp))) { tid = tnf_get_int64(temp); } else { tid = (unsigned int)tnf_get_int32(temp); } tidtype = tnf_get_type_name(temp); temp = tnf_get_slot_named(schedule_rec, TNF_N_LWPID); lwpid = tnf_get_int32(temp); temp = tnf_get_slot_named(schedule_rec, TNF_N_PID); pid = tnf_get_int32(temp); /* XXX should use TNF_N_KERNEL_SCHEDULE, TNF_N_USER_SCHEDULE */ if (strcmp(tidtype, K_TID) == 0) { int cpuid; /* XXX Assumes cpuid always exists in kernel schedule */ cpuid = tnf_get_int32(tnf_get_slot_named(schedule_rec, CPUID)); /* print the OUTPUT schedule record for Kernel case */ (void) printf("%16.6f %16.6f %5u %5u 0x%-8llx %3d", evt_time / 1000000.0, (evt_time - last_time)/1000000.0, pid, lwpid, tid, cpuid); } else { /* print the OUTPUT schedule record */ (void) printf("%16.6f %16.6f %5u %5u %10llu %3s", evt_time / 1000000.0, (evt_time - last_time)/1000000.0, pid, lwpid, tid, "-"); } /* print the tag */ eventname = tnf_type_get_name(tnf_get_slot_named(datum, TNF_N_TAG)); (void) printf(" %-25s", eventname); /* heuristic - start of data is after TIME_DELTA field */ start_slots = tnf_get_slot_index(datum, TNF_N_TIME_DELTA); start_slots++; n = tnf_get_slot_count(datum); /* print the rest of the fields */ for (i = start_slots; i < n; i++) { (void) printf(" "); slotname = tnf_get_slot_name(datum, i); (void) printf("%s: ", slotname); describe_target(tnf_get_slot_indexed(datum, i)); } (void) printf("\n"); last_time = evt_time; } static void describe_c_struct(tnf_datum_t datum) { unsigned n, i, tag_index; char *slotname; n = tnf_get_slot_count(datum); /* print the tag */ (void) printf(" "); (void) printf("%s: ", "type"); describe_c_brief(tnf_get_slot_named(datum, TNF_N_TAG)); tag_index = tnf_get_slot_index(datum, TNF_N_TAG); for (i = 0; i < n; i++) { /* print the rest of the members */ if (i != tag_index) { (void) printf(" "); slotname = tnf_get_slot_name(datum, i); (void) printf("%s: ", slotname); describe_target(tnf_get_slot_indexed(datum, i)); } } } static void describe_c_brief(tnf_datum_t datum) { if (datum == TNF_DATUM_NULL) /* allowed */ (void) printf("0x%-8x ", 0); else if (tnf_is_scalar(datum)) describe_scalar(datum); else if (tnf_is_record(datum)) { switch (tnf_get_kind(datum)) { case TNF_K_TYPE: (void) printf("%s", tnf_type_get_name(datum)); break; case TNF_K_STRING: (void) printf("\"%s\"", tnf_get_chars(datum)); break; default: (void) printf("<%s>", tnf_get_type_name(datum)); } } else fail(0, gettext("inline aggregate slots/elements unhandled")); } static void describe_target(tnf_datum_t datum) { if (datum == TNF_DATUM_NULL) /* allowed */ (void) printf("0x%-8x ", 0); else if (tnf_is_scalar(datum)) describe_scalar(datum); else if (tnf_is_record(datum)) { switch (tnf_get_kind(datum)) { case TNF_K_STRUCT: (void) printf("{"); describe_c_struct(datum); (void) printf(" }"); break; case TNF_K_TYPE: (void) printf("%s", tnf_type_get_name(datum)); break; case TNF_K_STRING: (void) printf("\"%s\"", tnf_get_chars(datum)); break; default: (void) printf("<%s>", tnf_get_type_name(datum)); } } else fail(0, gettext("inline aggregate slots/elements unhandled")); }