Mercurial > illumos > illumos-gate
changeset 10126:a4bccc1bc929
backout 6825817: needs more work
author | jmcp <James.McPherson@Sun.COM> |
---|---|
date | Sat, 18 Jul 2009 04:34:57 -0700 |
parents | c531901f60d1 |
children | 671556d7f85d |
files | usr/src/Makefile.lint usr/src/cmd/Makefile usr/src/cmd/latencytop/Makefile usr/src/cmd/latencytop/Makefile.com usr/src/cmd/latencytop/amd64/Makefile usr/src/cmd/latencytop/common/display.c usr/src/cmd/latencytop/common/dwrapper.c usr/src/cmd/latencytop/common/klog.c usr/src/cmd/latencytop/common/latencytop.c usr/src/cmd/latencytop/common/latencytop.d usr/src/cmd/latencytop/common/latencytop.h usr/src/cmd/latencytop/common/latencytop.trans usr/src/cmd/latencytop/common/stat.c usr/src/cmd/latencytop/common/table.c usr/src/cmd/latencytop/common/util.c usr/src/cmd/latencytop/i386/Makefile usr/src/cmd/latencytop/sparcv9/Makefile usr/src/pkgdefs/Makefile usr/src/pkgdefs/SUNWlatencytop/Makefile usr/src/pkgdefs/SUNWlatencytop/depend usr/src/pkgdefs/SUNWlatencytop/pkginfo.tmpl usr/src/pkgdefs/SUNWlatencytop/prototype_com usr/src/pkgdefs/SUNWlatencytop/prototype_i386 usr/src/pkgdefs/SUNWlatencytop/prototype_sparc |
diffstat | 24 files changed, 0 insertions(+), 5499 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/Makefile.lint Sat Jul 18 02:19:44 2009 -0700 +++ b/usr/src/Makefile.lint Sat Jul 18 04:34:57 2009 -0700 @@ -231,7 +231,6 @@ cmd/pools \ cmd/power \ cmd/powertop \ - cmd/latencytop \ cmd/ppgsz \ cmd/praudit \ cmd/prctl \
--- a/usr/src/cmd/Makefile Sat Jul 18 02:19:44 2009 -0700 +++ b/usr/src/cmd/Makefile Sat Jul 18 04:34:57 2009 -0700 @@ -227,7 +227,6 @@ kstat \ last \ lastcomm \ - latencytop \ ldap \ ldapcachemgr \ lgrpinfo \
--- a/usr/src/cmd/latencytop/Makefile Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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) 2008-2009, Intel Corporation. -# All Rights Reserved. -# - -PROG = latencytop - -include ../Makefile.cmd - -$(64ONLY)SUBDIRS= $(MACH) -$(BUILD64)SUBDIRS += $(MACH64) - -all := TARGET = all -install := TARGET = install -clean := TARGET = clean -clobber := TARGET = clobber -lint := TARGET = lint - -.KEEP_STATE: - -all install clean clobber lint: $(SUBDIRS) - -$(SUBDIRS): FRC - @cd $@; pwd; $(MAKE) $(TARGET) - -FRC: - -include ../Makefile.targ
--- a/usr/src/cmd/latencytop/Makefile.com Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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) 2008-2009, Intel Corporation. -# All Rights Reserved. -# - -PROG = latencytop -OBJS = latencytop.o display.o dwrapper.o klog.o stat.o table.o util.o conststr.o -SRCS = $(OBJS:%.o=../common/%.c) - -include ../../Makefile.cmd - -CFLAGS += $(CCVERBOSE) -CFLAGS64 += $(CCVERBOSE) - -CPPFLAGS += -DEMBED_CONFIGS -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -C99MODE = $(C99_ENABLE) -LDLIBS += -lcurses -ldtrace -all install := LDLIBS += -lglib-2.0 - -LINTFLAGS += -erroff=E_NAME_USED_NOT_DEF2 - -LINTFLAGS64 += -erroff=E_NAME_USED_NOT_DEF2 - -FILEMODE = 0555 -GROUP = bin - -CLEANFILES += $(OBJS) - -.KEEP_STATE: - -all: dumpcfg $(PROG) - -install: dumpcfg $(SUBDIRS) - -$(RM) $(ROOTPROG) - -$(LN) $(ISAEXEC) $(ROOTPROG) - -$(PROG): $(OBJS) - $(LINK.c) -o $@ $(OBJS) $(LDLIBS) - $(POST_PROCESS) - -dumpcfg: - cd ../common; xxd -i latencytop.d >./conststr.c; xxd -i latencytop.trans >>./conststr.c; cd .. - -rmcfg: - rm -f ../common/conststr.c - -clean: rmcfg - $(RM) $(CLEANFILES) - -lint: dumpcfg lint_SRCS - -%.o: ../common/%.c - $(COMPILE.c) $< - -include ../../Makefile.targ
--- a/usr/src/cmd/latencytop/amd64/Makefile Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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) 2008-2009, Intel Corporation. -# All Rights Reserved. -# - -include ../Makefile.com -include ../../Makefile.cmd.64 - -install: all $(ROOTPROG64)
--- a/usr/src/cmd/latencytop/common/display.c Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,998 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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) 2008-2009, Intel Corporation. - * All Rights Reserved. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <sys/types.h> -#include <sys/time.h> -#include <dirent.h> -#include <curses.h> -#include <time.h> -#include <wchar.h> -#include <ctype.h> -#include <stdarg.h> - -#include "latencytop.h" - -#define LT_WINDOW_X 80 -#define LT_WINDOW_Y 24 - -#define LT_COLOR_DEFAULT 1 -#define LT_COLOR_HEADER 2 - -/* Windows created by libcurses */ -static WINDOW *titlebar = NULL; -static WINDOW *captionbar = NULL; -static WINDOW *sysglobal_window = NULL; -static WINDOW *taskbar = NULL; -static WINDOW *process_window = NULL; -static WINDOW *hintbar = NULL; -/* Screen dimention */ -static int screen_width = 1, screen_height = 1; -/* Is display initialized, i.e. window pointers set up. */ -static int display_initialized = FALSE; -/* Is initscr() called */ -static int curses_inited = FALSE; - -/* Changed by user key press */ -static pid_t selected_pid = INVALID_PID; -static id_t selected_tid = INVALID_TID; -static lt_sort_t sort_type = LT_SORT_TOTAL; -static int thread_mode = FALSE; -/* what kind of list are we showing now */ -static int current_list_type = LT_LIST_CAUSE; -static int show_help = FALSE; - -/* Help functions that append/prepend blank to the string */ -#define fill_space_right(a, b, c) fill_space((a), (b), (c), TRUE) -#define fill_space_left(a, b, c) fill_space((a), (b), (c), FALSE) - -static void -fill_space(char *buffer, int len, int buffer_limit, int is_right) -{ - int i = 0; - int tofill; - - if (len >= buffer_limit) { - len = buffer_limit - 1; - } - - i = strlen(buffer); - if (i >= len) { - return; - } - - tofill = len - i; - - if (is_right) { - (void) memset(&buffer[i], ' ', tofill); - buffer[len] = 0; - } else { - (void) memmove(&buffer[tofill], buffer, i+1); - (void) memset(buffer, ' ', tofill); - } -} - -/* Formats a human readable string out of nanosecond value */ -static const char * -get_time_string(double nanoseconds, char *buffer, int len, int fill_width) -{ - const double ONE_USEC = 1000.0; - const double ONE_MSEC = 1000000.0; - const double ONE_SEC = 1000000000.0; - - if (nanoseconds < (ONE_USEC - .5)) { - (void) snprintf(buffer, len, "%3.1f nsec", nanoseconds); - } else if (nanoseconds < (ONE_MSEC - .5 * ONE_USEC)) { - (void) snprintf(buffer, len, - "%3.1f usec", nanoseconds / ONE_USEC); - } else if (nanoseconds < (ONE_SEC - .5 * ONE_MSEC)) { - (void) snprintf(buffer, len, - "%3.1f msec", nanoseconds / ONE_MSEC); - } else if (nanoseconds < 999.5 * ONE_SEC) { - (void) snprintf(buffer, len, - "%3.1f sec", nanoseconds / ONE_SEC); - } else { - (void) snprintf(buffer, len, - "%.0e sec", nanoseconds / ONE_SEC); - } - fill_space_left(buffer, fill_width, len); - return (buffer); -} - -/* - * Print statistics in a window. - * IN: window - the global or process statistics window. - * begin_line - where to start printing. - * count - how many lines should we print. - * list - a stat_list. - */ -#define WIDTH_REASON_STRING 36 -#define WIDTH_COUNT 12 -#define WIDTH_SUM 12 -#define WIDTH_MAX 12 -#define WIDTH_PCT 8 -#define BEGIN_COUNT WIDTH_REASON_STRING -#define BEGIN_SUM (BEGIN_COUNT + WIDTH_COUNT) -#define BEGIN_MAX (BEGIN_SUM + WIDTH_SUM) -#define BEGIN_PCT (BEGIN_MAX + WIDTH_MAX) - -static void -print_statistics(WINDOW * window, int begin_line, int count, void *list) -{ - uint64_t total; - int i = 0; - - if (!display_initialized) { - return; - } - - total = lt_stat_list_get_gtotal(list); - if (total == 0) { - return; - } - - while (i < count && lt_stat_list_has_item(list, i)) { - /* - * We intentionally make tmp[] hold one character less - * than WIDTH_REASON_STRING, so it will look nice on the - * screen. - */ - char tmp[WIDTH_REASON_STRING]; - const char *reason = lt_stat_list_get_reason(list, i); - uint64_t count = lt_stat_list_get_count(list, i); - - if (count == 0) { - continue; - } - - (void) snprintf(tmp, sizeof (tmp), "%s", reason); - (void) mvwprintw(window, i + begin_line, 0, "%s", tmp); - (void) snprintf(tmp, sizeof (tmp), "%d", - lt_stat_list_get_count(list, i)); - fill_space_left(tmp, WIDTH_COUNT, sizeof (tmp)); - (void) mvwprintw(window, i + begin_line, BEGIN_COUNT, - "%s", tmp); - (void) mvwprintw(window, i + begin_line, BEGIN_SUM, - "%s", get_time_string( - (double)lt_stat_list_get_sum(list, i) / count, - tmp, sizeof (tmp), WIDTH_SUM)); - (void) mvwprintw(window, i + begin_line, BEGIN_MAX, - "%s", get_time_string( - (double)lt_stat_list_get_max(list, i), - tmp, sizeof (tmp), WIDTH_MAX)); - if (LT_LIST_SPECIALS != current_list_type) { - (void) snprintf(tmp, sizeof (tmp), "%.1f %%", - (double)lt_stat_list_get_sum(list, i) - / total * 100.0); - } else { - (void) snprintf(tmp, sizeof (tmp), "--- "); - } - fill_space_left(tmp, WIDTH_PCT, sizeof (tmp)); - - (void) mvwprintw(window, i + begin_line, BEGIN_PCT, - "%s", tmp); - i++; - } -} - -/* - * Print global statistics. Calls print_statistics(). - */ -static void -print_sysglobal(void) -{ - void *list; - char header[256]; - - if (!display_initialized) { - return; - } - - (void) werase(sysglobal_window); - - (void) wattron(sysglobal_window, A_REVERSE); - (void) snprintf(header, sizeof (header), - "%s", lt_text("System wide latencies")); - fill_space_right(header, screen_width, sizeof (header)); - (void) mvwprintw(sysglobal_window, 0, 0, "%s", header); - (void) wattroff(sysglobal_window, A_REVERSE); - - list = lt_stat_list_create(current_list_type, - LT_LEVEL_GLOBAL, 0, 0, 10, sort_type); - print_statistics(sysglobal_window, 1, 10, list); - lt_stat_list_free(list); - - (void) wrefresh(sysglobal_window); -} - -/* - * Prints current operation mode: process/thread, window 1/2/3. - */ -static void -print_current_mode() -{ - char type; - - if (!display_initialized) { - return; - } - - switch (current_list_type) { - case LT_LIST_CAUSE: - type = 'C'; - break; - case LT_LIST_SPECIALS: - type = 'S'; - break; - case LT_LIST_SOBJ: - type = 'L'; - break; - default: - type = '?'; - break; - } - - (void) mvwprintw(process_window, 0, screen_width - 2, "%c%c", - type, thread_mode ? 'T' : 'P'); -} - -/* - * Print per-process statistics. Calls print_statistics(). - * This one is used in per-process mode. - */ -static void -print_process(unsigned int pid) -{ - void *list; - char header[256]; - char tmp[30]; - - if (!display_initialized) { - return; - } - - list = lt_stat_list_create(current_list_type, LT_LEVEL_PROCESS, - pid, 0, 8, sort_type); - - (void) werase(process_window); - (void) wattron(process_window, A_REVERSE); - - (void) snprintf(header, sizeof (header), "Process %s (%i) ", - lt_stat_proc_get_name(pid), pid); - fill_space_right(header, screen_width, sizeof (header)); - (void) mvwprintw(process_window, 0, 0, "%s", header); - - if (current_list_type != LT_LIST_SPECIALS) { - (void) mvwprintw(process_window, 0, 40, - lt_text("Total: %s from %d threads"), - get_time_string((double)lt_stat_list_get_gtotal(list), - tmp, sizeof (tmp), 12), - lt_stat_proc_get_nthreads(pid)); - } - print_current_mode(); - - (void) wattroff(process_window, A_REVERSE); - - print_statistics(process_window, 1, 8, list); - lt_stat_list_free(list); - - (void) wrefresh(process_window); -} - -/* - * List all processes in task bar. - * This one is used in per-process mode. - */ -static void -print_taskbar_process(pid_t *pidlist, int pidlist_len, int pidlist_index) -{ - const int ITEM_WIDTH = 8; - - int number_item; - int i; - int xpos = 0; - - if (!display_initialized) { - return; - } - - number_item = (screen_width / ITEM_WIDTH) - 1; - i = pidlist_index - (pidlist_index % number_item); - - (void) werase(taskbar); - if (i != 0) { - (void) mvwprintw(taskbar, 0, xpos, "<-"); - } - xpos = ITEM_WIDTH / 2; - - while (xpos + ITEM_WIDTH <= screen_width && i < pidlist_len) { - char str[ITEM_WIDTH+1]; - int slen; - const char *pname = lt_stat_proc_get_name(pidlist[i]); - - if (pname && pname[0]) { - (void) snprintf(str, sizeof (str) - 1, "%s", pname); - } else { - (void) snprintf(str, sizeof (str) - 1, - "<%d>", pidlist[i]); - } - - slen = strlen(str); - if (slen < ITEM_WIDTH) { - (void) memset(&str[slen], ' ', ITEM_WIDTH - slen); - } - - str[sizeof (str) - 1] = 0; - - if (i == pidlist_index) { - (void) wattron(taskbar, A_REVERSE); - } - (void) mvwprintw(taskbar, 0, xpos, "%s", str); - if (i == pidlist_index) { - (void) wattroff(taskbar, A_REVERSE); - } - - xpos += ITEM_WIDTH; - i++; - } - - if (i != pidlist_len) { - (void) mvwprintw(taskbar, 0, screen_width - 2, "->"); - } - (void) wrefresh(taskbar); -} - -/* - * List all processes in task bar. - * This one is used in per-thread mode. - */ -static void -print_taskbar_thread(pid_t *pidlist, id_t *tidlist, int list_len, - int list_index) -{ - const int ITEM_WIDTH = 12; - - int number_item; - int i; - int xpos = 0; - const char *pname = NULL; - pid_t last_pid = INVALID_PID; - - - if (!display_initialized) { - return; - } - - number_item = (screen_width - 8) / ITEM_WIDTH; - i = list_index - (list_index % number_item); - - (void) werase(taskbar); - if (i != 0) { - (void) mvwprintw(taskbar, 0, xpos, "<-"); - } - xpos = 4; - - while (xpos + ITEM_WIDTH <= screen_width && i < list_len) { - char str[ITEM_WIDTH+1]; - int slen, tlen; - - if (pidlist[i] != last_pid) { - pname = lt_stat_proc_get_name(pidlist[i]); - last_pid = pidlist[i]; - } - /* - * Calculate thread id length, leave enough space by print - * shorter process name. - */ - tlen = snprintf(NULL, 0, "_%d", tidlist[i]); - - if (pname && pname[0]) { - (void) snprintf(str, sizeof (str) - tlen - 1, - "%s", pname); - } else { - (void) snprintf(str, sizeof (str) - tlen - 1, - "<%d>", pidlist[i]); - } - slen = strlen(str); - - (void) snprintf(&str[slen], sizeof (str) - slen, - "_%d", tidlist[i]); - - slen += tlen; - - if (slen < ITEM_WIDTH) { - (void) memset(&str[slen], ' ', ITEM_WIDTH - slen); - } - str[sizeof (str) - 1] = 0; - - if (i == list_index) { - (void) wattron(taskbar, A_REVERSE); - } - (void) mvwprintw(taskbar, 0, xpos, "%s", str); - if (i == list_index) { - (void) wattroff(taskbar, A_REVERSE); - } - - xpos += ITEM_WIDTH; - i++; - } - - if (i != list_len) { - (void) mvwprintw(taskbar, 0, screen_width - 2, "->"); - } - (void) wrefresh(taskbar); -} - -/* - * Print statistics. Calls print_statistics(). - * This one is used in per-thread mode. - */ -static void -print_thread(pid_t pid, id_t tid) -{ - void *list; - char header[256]; - char tmp[30]; - - if (!display_initialized) { - return; - } - - list = lt_stat_list_create(current_list_type, LT_LEVEL_THREAD, - pid, tid, 8, sort_type); - - (void) werase(process_window); - (void) wattron(process_window, A_REVERSE); - - (void) snprintf(header, sizeof (header), - "Process %s (%i), LWP %d", - lt_stat_proc_get_name(pid), pid, tid); - fill_space_right(header, screen_width, sizeof (header)); - (void) mvwprintw(process_window, 0, 0, "%s", header); - - if (current_list_type != LT_LIST_SPECIALS) { - (void) mvwprintw(process_window, 0, 40, lt_text("Total: %s"), - get_time_string( - (double)lt_stat_list_get_gtotal(list), - tmp, sizeof (tmp), 12)); - } - print_current_mode(); - - (void) wattroff(process_window, A_REVERSE); - - print_statistics(process_window, 1, 8, list); - lt_stat_list_free(list); - - (void) wrefresh(process_window); -} - -/* - * Update hint string at the bottom line. The message to print is stored in - * hint. If hint is NULL, the function will pick a message from useful tips - * and display it. - */ -static void -print_hint(const char *hint) -{ - const char *HINTS[] = { - "Press '<' or '>' to switch between processes.", - "Press 'q' to exit.", - "Press 'r' to refresh immediately.", - "Press 't' to toggle Process/Thread display mode.", - "Press 'h' for help.", - "Use 'c', 'a', 'm', 'p' to change sort criteria." - "Use '1', '2', '3' to switch between windows." - }; - const uint64_t update_interval = 5000; /* 5 seconds */ - - static int index = 0; - static uint64_t next_hint = 0; - uint64_t now = lt_millisecond(); - - if (!display_initialized) { - return; - } - - if (hint == NULL) { - if (now < next_hint) { - return; - } - hint = HINTS[index]; - index = (index + 1) % (sizeof (HINTS) / sizeof (HINTS[0])); - next_hint = now + update_interval; - } else { - /* - * To ensure important message - * show at least 2 cycles. - */ - next_hint = now + update_interval * 2; - } - - (void) werase(hintbar); - (void) mvwprintw(hintbar, 0, (screen_width - strlen(hint)) / 2, - "%s", lt_text(hint)); - (void) wrefresh(hintbar); -} - -/* - * Get information from existing statistics, and create a PID list - * or PID/TID list based on current display mode. - */ -static void -get_plist(pid_t **plist, id_t **tlist, int *list_len, int *list_index) -{ - if (!thread_mode) { - /* Per-process mode */ - *list_len = lt_stat_proc_list_create(plist, NULL); - - /* Search for previous selected PID */ - for (*list_index = 0; *list_index < *list_len && - (*plist)[*list_index] != selected_pid; - ++*list_index) { - } - - if (*list_index >= *list_len) { - /* - * The old selected pid is gone. - * Select the first one - */ - *list_index = 0; - } - } else { - /* Per-thread mode */ - *list_len = lt_stat_proc_list_create(plist, tlist); - - /* Search for previous selected PID & TID */ - for (*list_index = 0; *list_index < *list_len; - ++*list_index) { - if ((*plist)[*list_index] == selected_pid && - (*tlist)[*list_index] == selected_tid) { - break; - } - } - - if (*list_index >= *list_len) { - /* - * The old selected pid/tid is gone. - * Select the first one in the pid - */ - for (*list_index = 0; - *list_index < *list_len && - (*plist)[*list_index] != selected_pid; - ++*list_index) { - } - } - if (*list_index >= *list_len) { - /* - * The old selected pid is gone. - * Select the first one - */ - *list_index = 0; - } - } -} - -static void -print_help(void) -{ - const char *HELP[] = { - TITLE, - COPYRIGHT, - "", - "These single-character commands are available:", - "< - Move to previous process/thread.", - "> - Move to next process/thread.", - "q - Exit.", - "r - Refresh.", - "t - Toggle process/thread mode.", - "c - Sort by count.", - "a - Sort by average.", - "m - Sort by maximum.", - "p - Sort by percent.", - "1 - Show list by causes.", - "2 - Show list of special entries.", - "3 - Show list by synchronization objects.", - "h - Show this help.", - "", - "Press any key to continue..." - }; - int i; - - if (!display_initialized) { - return; - } - - for (i = 0; i < sizeof (HELP) / sizeof (HELP[0]); ++i) { - (void) mvwprintw(stdscr, i, 0, "%s", HELP[i]); - } - (void) refresh(); -} - -/* - * Print title on screen - */ -static void -print_title(void) -{ - if (!display_initialized) { - return; - } - - (void) wattrset(titlebar, COLOR_PAIR(LT_COLOR_HEADER)); - (void) wbkgd(titlebar, COLOR_PAIR(LT_COLOR_HEADER)); - (void) werase(titlebar); - - (void) mvwprintw(titlebar, 0, (screen_width - strlen(TITLE)) / 2, - "%s", TITLE); - (void) wrefresh(titlebar); - - (void) werase(captionbar); - (void) mvwprintw(captionbar, 0, 0, "%s", lt_text( - " Cause " - "Count Average Maximum Percent")); - (void) wrefresh(captionbar); - - (void) wattrset(hintbar, COLOR_PAIR(LT_COLOR_HEADER)); - (void) wbkgd(hintbar, COLOR_PAIR(LT_COLOR_HEADER)); -} - -/* - * Signal handler on terminal resize - */ -/* ARGSUSED */ -static void -on_resize(int sig) -{ - lt_gpipe_break("r"); -} - -/* - * Initialize display part. Screen will be cleared when this function returns. - */ -void -lt_display_init(void) -{ - if (display_initialized) { - return; - } - - /* Window resize signal */ - (void) signal(SIGWINCH, on_resize); - - /* Initialize curses lib. */ - (void) initscr(); - (void) start_color(); - (void) keypad(stdscr, TRUE); - (void) nonl(); - (void) cbreak(); - (void) noecho(); - (void) curs_set(0); - - /* Set up color pairs */ - (void) init_pair(LT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK); - (void) init_pair(LT_COLOR_HEADER, COLOR_BLACK, COLOR_WHITE); - - curses_inited = TRUE; - - getmaxyx(stdscr, screen_height, screen_width); - if (screen_width < LT_WINDOW_X || screen_height < LT_WINDOW_Y) { - (void) mvwprintw(stdscr, 0, 0, "Terminal size is too small."); - (void) mvwprintw(stdscr, 1, 0, - "Please resize it to 80x24 or larger."); - (void) mvwprintw(stdscr, 2, 0, "Press q to quit."); - (void) refresh(); - return; - } - - /* Setup all windows on screen. */ - titlebar = subwin(stdscr, 1, screen_width, 0, 0); - captionbar = subwin(stdscr, 1, screen_width, 1, 0); - sysglobal_window = subwin(stdscr, screen_height / 2 - 1, - screen_width, 2, 0); - process_window = subwin(stdscr, screen_height / 2 - 3, - screen_width, screen_height / 2 + 1, 0); - taskbar = subwin(stdscr, 1, screen_width, screen_height - 2, 0); - hintbar = subwin(stdscr, 1, screen_width, screen_height - 1, 0); - (void) werase(stdscr); - (void) refresh(); - - display_initialized = TRUE; - - print_title(); -} - -/* - * The event loop. Display data on screen and handles key press. Will return - * after "duration" seconds, unless exit or refresh hotkey is pressed. - * Return 0 means main() should exit. 1 means to loop again. - */ -int -lt_display_loop(int duration) -{ - uint64_t start; - int remaining; - struct timeval timeout; - fd_set read_fd; - int need_refresh = TRUE; - pid_t *plist = NULL; - id_t *tlist = NULL; - int list_len = 0; - int list_index = 0; - int retval = 1; - int next_snap; - int gpipe; - - start = lt_millisecond(); - gpipe = lt_gpipe_readfd(); - - if (!show_help) { - print_hint(NULL); - print_sysglobal(); - } - get_plist(&plist, &tlist, &list_len, &list_index); - - for (;;) { - if (list_len != 0 && need_refresh && !show_help) { - if (!thread_mode) { - print_taskbar_process(plist, list_len, - list_index); - print_process(plist[list_index]); - } else { - print_taskbar_thread(plist, tlist, - list_len, list_index); - print_thread(plist[list_index], - tlist[list_index]); - } - } - need_refresh = TRUE; /* Usually we need refresh. */ - - remaining = duration - (int)(lt_millisecond() - start); - if (remaining <= 0) { - break; - } - /* Embedded dtrace snap action here. */ - next_snap = lt_dtrace_work(0); - if (next_snap == 0) { - /* - * Just did a snap, check again to get time for - * next shot. - */ - next_snap = lt_dtrace_work(0); - } - if (next_snap > 0 && remaining > next_snap) { - remaining = next_snap; - } - - timeout.tv_sec = remaining / 1000; - timeout.tv_usec = (remaining % 1000) * 1000; - FD_ZERO(&read_fd); - FD_SET(0, &read_fd); - FD_SET(gpipe, &read_fd); - - /* Wait for keyboard input, or signal from gpipe */ - if (select(gpipe + 1, &read_fd, NULL, NULL, &timeout) > 0) { - int k = 0; - - if (FD_ISSET(gpipe, &read_fd)) { - /* data from pipe has priority */ - char ch; /* Need this for big-endian */ - (void) read(gpipe, &ch, 1); - k = ch; - } else { - k = getch(); - } - - /* - * We check if we need to update hint line whenever we - * get chance. - * NOTE: current implementation depends on - * g_config.snap_interval, but it's OK because it - * doesn't have to be precise. - */ - print_hint(NULL); - /* - * If help is on, and a key press happens, - * we need to clear the help and go on. - */ - if (show_help) { - (void) werase(stdscr); - (void) refresh(); - print_title(); - print_sysglobal(); - show_help = FALSE; - /* Drop this key and continue */ - continue; - } - - switch (k) { - case 'Q': - case 'q': - retval = 0; - goto quit; - case 'R': - case 'r': - lt_display_deinit(); - lt_display_init(); - goto quit; - case 'H': - case 'h': - show_help = TRUE; - (void) werase(stdscr); - (void) refresh(); - print_help(); - break; - case ',': - case '<': - case KEY_LEFT: - --list_index; - if (list_index < 0) { - list_index = 0; - } - break; - case '.': - case '>': - case KEY_RIGHT: - ++list_index; - if (list_index >= list_len) { - list_index = list_len - 1; - } - break; - case 'a': - case 'A': - sort_type = LT_SORT_AVG; - print_sysglobal(); - break; - case 'p': - case 'P': - sort_type = LT_SORT_TOTAL; - print_sysglobal(); - break; - case 'm': - case 'M': - sort_type = LT_SORT_MAX; - print_sysglobal(); - break; - case 'c': - case 'C': - sort_type = LT_SORT_COUNT; - print_sysglobal(); - break; - case 't': - case 'T': - if (plist != NULL) { - selected_pid = plist[list_index]; - } - selected_tid = INVALID_TID; - thread_mode = !thread_mode; - get_plist(&plist, &tlist, - &list_len, &list_index); - break; - case '1': - case '!': - current_list_type = LT_LIST_CAUSE; - print_sysglobal(); - break; - case '2': - case '@': - if (g_config.low_overhead_mode) { - lt_display_error("Switching mode is " - "not available for '-f low'."); - } else { - current_list_type = LT_LIST_SPECIALS; - print_sysglobal(); - } - break; - case '3': - case '#': - if (g_config.trace_syncobj) { - current_list_type = LT_LIST_SOBJ; - print_sysglobal(); - } else if (g_config.low_overhead_mode) { - lt_display_error("Switching mode is " - "not available for '-f low'."); - } else { - lt_display_error("Tracing " - "synchronization objects is " - "disabled."); - } - break; - default: - /* Wake up for nothing, no need to refresh */ - need_refresh = FALSE; - break; - } - } else { - need_refresh = FALSE; - } - } - -quit: - if (plist != NULL) { - selected_pid = plist[list_index]; - } - if (tlist != NULL) { - selected_tid = tlist[list_index]; - } - lt_stat_proc_list_free(plist, tlist); - - return (retval); -} - -/* - * Close display part. - */ -void -lt_display_deinit(void) -{ - if (curses_inited) { - (void) clear(); - (void) refresh(); - (void) endwin(); - } - - titlebar = NULL; - captionbar = NULL; - sysglobal_window = NULL; - taskbar = NULL; - process_window = NULL; - hintbar = NULL; - screen_width = 1; - screen_height = 1; - - display_initialized = FALSE; - curses_inited = FALSE; -} - -/* - * Print error message. - */ -/* ARGSUSED */ -void -lt_display_error(const char *fmt, ...) -{ - va_list vl; - char tmp[81]; - int l; - - va_start(vl, fmt); - (void) vsnprintf(tmp, sizeof (tmp), fmt, vl); - va_end(vl); - - l = strlen(tmp); - while (l > 0 && (tmp[l - 1] == '\n' || tmp[l - 1] == '\r')) { - tmp[l - 1] = 0; - --l; - } - - if (!display_initialized) { - (void) printf("%s\n", tmp); - } else if (!show_help) { - print_hint(tmp); - } - -}
--- a/usr/src/cmd/latencytop/common/dwrapper.c Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,548 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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) 2008-2009, Intel Corporation. - * All Rights Reserved. - */ - -#include <unistd.h> -#include <stdio.h> -#include <dtrace.h> -#include <string.h> -#include <stdlib.h> -#include <memory.h> -#include <limits.h> - -#include "latencytop.h" - -static dtrace_hdl_t *g_dtp = NULL; /* The dtrace handle */ -static pid_t pid_self = -1; /* PID of our own process */ - -/* - * Checks if the process is latencytop itself or sched (if we are not tracing - * sched), we should ignore them. - */ -#define SHOULD_IGNORE(pid) \ - ((!g_config.trace_sched && 0 == (pid)) || pid_self == (pid)) - -/* - * Get an integer value from dtrace record. - */ -static uint64_t -rec_get_value(void *a, size_t b) -{ - uint64_t ret = 0; - - switch (b) { - case sizeof (uint64_t): - ret = *((uint64_t *)(a)); - break; - case sizeof (uint32_t): - ret = *((uint32_t *)(a)); - break; - case sizeof (uint16_t): - ret = *((uint16_t *)(a)); - break; - case sizeof (uint8_t): - ret = *((uint8_t *)(a)); - break; - default: - break; - } - - return (ret); -} - -/* - * Callback to process each aggregation in the snapshot. - * This one processes lt_call_*, which contains on/off cpu activites. - */ -static int -aggwalk_call(const dtrace_aggdata_t *data, lt_stat_type_t stat_type) -{ - const int REC_PID = 1; - const int REC_TID = 2; - const int REC_STACK = 3; - const int REC_AGG = 4; - const int NREC = 5; - - dtrace_aggdesc_t *aggdesc = data->dtada_desc; - dtrace_syminfo_t dts; - GElf_Sym sym; - caddr_t addr; - pid_t pid; - id_t tid; - unsigned int stack_depth; - unsigned int pc_size; - uint64_t pc; - uint64_t agg_value; - char *ptr = NULL; - char *buffer = NULL; - int ptrsize; - unsigned int buffersize; - - if (aggdesc->dtagd_nrecs < NREC) { - /* Not enough records */ - goto err; - } - - if (aggdesc->dtagd_rec[REC_PID].dtrd_action != DTRACEACT_DIFEXPR) { - /* Record is not PID, this is an error. */ - goto err; - } - pid = rec_get_value( - data->dtada_data + aggdesc->dtagd_rec[REC_PID].dtrd_offset, - aggdesc->dtagd_rec[REC_PID].dtrd_size); - if (SHOULD_IGNORE(pid)) { - goto done; - } - - if (aggdesc->dtagd_rec[REC_TID].dtrd_action != DTRACEACT_DIFEXPR) { - /* Record is not TID, this is an error. */ - goto err; - } - tid = rec_get_value( - data->dtada_data + aggdesc->dtagd_rec[REC_TID].dtrd_offset, - aggdesc->dtagd_rec[REC_TID].dtrd_size); - - if (aggdesc->dtagd_rec[REC_STACK].dtrd_action != DTRACEACT_STACK) { - /* Record is not stack(), this is an error. */ - goto err; - } - - /* Parse stack array from dtagd_rec */ - stack_depth = aggdesc->dtagd_rec[REC_STACK].dtrd_arg; - pc_size = aggdesc->dtagd_rec[REC_STACK].dtrd_size / stack_depth; - addr = data->dtada_data + aggdesc->dtagd_rec[REC_STACK].dtrd_offset; - buffersize = (stack_depth * (2 * PATH_MAX + 2) + 1) * sizeof (char); - buffer = (char *)lt_malloc(buffersize); - ptr = buffer; - ptrsize = buffersize; - - /* Print the stack */ - while (stack_depth > 0) { - pc = rec_get_value(addr, pc_size); - if (pc == 0) { - break; - } - addr += pc_size; - if (dtrace_lookup_by_addr(g_dtp, pc, &sym, &dts) == 0) { - int len; - len = snprintf(ptr, ptrsize, - "%s`%s ", dts.dts_object, dts.dts_name); - ptrsize -= len; - if (ptrsize <= 0) { - /* - * Snprintf returns "desired" length, so - * reaching here means our buffer is full. - * Move ptr to last byte in the buffer and - * break early. - */ - ptr = &buffer[buffersize-1]; - break; - } else { - ptr += len; - } - } - } - - if (ptr != buffer) { - /* - * We have printed something, - * so it is safe to remove last ' '. - */ - *(ptr-1) = 0; - } - - /* Parsing aggregation data */ - if (!DTRACEACT_ISAGG(aggdesc->dtagd_rec[REC_AGG].dtrd_action)) { - /* Record is not aggregation, this is an error. */ - goto err; - } - agg_value = rec_get_value( - data->dtada_data + aggdesc->dtagd_rec[REC_AGG].dtrd_offset, - aggdesc->dtagd_rec[REC_AGG].dtrd_size); - - lt_stat_update(pid, tid, buffer, stat_type, agg_value); - -done: - if (buffer != NULL) { - free(buffer); - } - return (0); - -err: - if (buffer != NULL) { - free(buffer); - } - return (-1); -} - -/* - * Callback to process each aggregation in the snapshot. - * This one processes lt_named_*, which contains data such as lock spinning. - */ -static int -aggwalk_named(const dtrace_aggdata_t *data, lt_stat_type_t stat_type) -{ - const int REC_PID = 1; - const int REC_TID = 2; - const int REC_TYPE = 3; - const int REC_AGG = 4; - const int NREC = 5; - - dtrace_aggdesc_t *aggdesc = data->dtada_desc; - pid_t pid; - id_t tid; - uint64_t agg_value; - int cause_id; - char *type = NULL; - - if (aggdesc->dtagd_nrecs < NREC) { - /* Not enough records */ - return (-1); - } - - if (aggdesc->dtagd_rec[REC_PID].dtrd_action != DTRACEACT_DIFEXPR) { - /* Record is not PID, this is an error. */ - return (-1); - } - pid = rec_get_value( - data->dtada_data + aggdesc->dtagd_rec[REC_PID].dtrd_offset, - aggdesc->dtagd_rec[REC_PID].dtrd_size); - if (SHOULD_IGNORE(pid)) { - return (0); - } - if (aggdesc->dtagd_rec[REC_TID].dtrd_action != DTRACEACT_DIFEXPR) { - /* Record is not TID, this is an error. */ - return (-1); - } - tid = rec_get_value( - data->dtada_data + aggdesc->dtagd_rec[REC_TID].dtrd_offset, - aggdesc->dtagd_rec[REC_TID].dtrd_size); - - if (aggdesc->dtagd_rec[REC_TYPE].dtrd_action != DTRACEACT_DIFEXPR) { - /* Record is not type, this is an error. */ - return (-1); - } - type = (char *)data->dtada_data - + aggdesc->dtagd_rec[REC_TYPE].dtrd_offset; - cause_id = lt_table_lookup_named_cause(type, 1); - - /* Parsing aggregation data */ - if (!DTRACEACT_ISAGG(aggdesc->dtagd_rec[REC_AGG].dtrd_action)) { - /* Record is not aggregation, this is an error. */ - return (-1); - } - agg_value = rec_get_value( - data->dtada_data + aggdesc->dtagd_rec[REC_AGG].dtrd_offset, - aggdesc->dtagd_rec[REC_AGG].dtrd_size); - - lt_stat_update_cause(pid, tid, cause_id, stat_type, agg_value); - - return (0); - -} - -/* - * Callback to process each aggregation in the snapshot. - * This one processes lt_sync_*, which traces synchronization objects. - */ -static int -aggwalk_sync(const dtrace_aggdata_t *data, lt_stat_type_t stat_type) -{ - const int REC_PID = 1; - const int REC_TID = 2; - const int REC_STYPE = 3; - const int REC_WCHAN = 4; - const int REC_AGG = 5; - const int NREC = 6; - - dtrace_aggdesc_t *aggdesc = data->dtada_desc; - pid_t pid; - id_t tid; - uint64_t agg_value; - int stype; - unsigned long long wchan; - - if (aggdesc->dtagd_nrecs < NREC) { - /* Not enough records */ - return (-1); - } - - if (aggdesc->dtagd_rec[REC_PID].dtrd_action != DTRACEACT_DIFEXPR) { - /* Record is not PID, this is an error. */ - return (-1); - } - pid = rec_get_value( - data->dtada_data + aggdesc->dtagd_rec[REC_PID].dtrd_offset, - aggdesc->dtagd_rec[REC_PID].dtrd_size); - if (SHOULD_IGNORE(pid)) { - return (0); - } - - if (aggdesc->dtagd_rec[REC_TID].dtrd_action != DTRACEACT_DIFEXPR) { - /* Record is not TID, this is an error. */ - return (-1); - } - tid = rec_get_value( - data->dtada_data + aggdesc->dtagd_rec[REC_TID].dtrd_offset, - aggdesc->dtagd_rec[REC_TID].dtrd_size); - - if (aggdesc->dtagd_rec[REC_STYPE].dtrd_action != DTRACEACT_DIFEXPR) { - /* Record is not stype, this is an error. */ - return (-1); - } - stype = rec_get_value( - data->dtada_data + aggdesc->dtagd_rec[REC_STYPE].dtrd_offset, - aggdesc->dtagd_rec[REC_STYPE].dtrd_size); - - if (aggdesc->dtagd_rec[REC_WCHAN].dtrd_action != DTRACEACT_DIFEXPR) { - /* Record is not wchan, this is an error. */ - return (-1); - } - wchan = rec_get_value( - data->dtada_data + aggdesc->dtagd_rec[REC_WCHAN].dtrd_offset, - aggdesc->dtagd_rec[REC_WCHAN].dtrd_size); - - /* Parsing aggregation data */ - if (!DTRACEACT_ISAGG(aggdesc->dtagd_rec[REC_AGG].dtrd_action)) { - /* Record is not aggregation, this is an error. */ - return (-1); - } - agg_value = rec_get_value( - data->dtada_data + aggdesc->dtagd_rec[REC_AGG].dtrd_offset, - aggdesc->dtagd_rec[REC_AGG].dtrd_size); - - lt_stat_update_sobj(pid, tid, stype, wchan, stat_type, agg_value); - - return (0); -} - -/* - * Callback to process each aggregation in the snapshot. - * This one dispatches to different aggwalk_*(). - */ -/* ARGSUSED */ -static int -aggwalk(const dtrace_aggdata_t *data, void *arg) -{ - char *tmp; - char buffer[32]; - lt_stat_type_t stat_type = LT_STAT_COUNT; - int (*func)(const dtrace_aggdata_t *, lt_stat_type_t); - - (void) strncpy(buffer, data->dtada_desc->dtagd_name, sizeof (buffer)); - buffer[sizeof (buffer) - 1] = 0; - - tmp = strtok(buffer, "_"); - if (strcmp(tmp, "lt") != 0) { - goto done; - } - - tmp = strtok(NULL, "_"); - if (strcmp(tmp, "call") == 0) { - func = aggwalk_call; - } else if (strcmp(tmp, "named") == 0) { - func = aggwalk_named; - } else if (strcmp(tmp, "sync") == 0) { - func = aggwalk_sync; - } else { - goto done; - } - - tmp = strtok(NULL, "_"); - if (strcmp(tmp, "count") == 0) { - stat_type = LT_STAT_COUNT; - } else if (strcmp(tmp, "sum") == 0) { - stat_type = LT_STAT_SUM; - } else if (strcmp(tmp, "max") == 0) { - stat_type = LT_STAT_MAX; - } else { - goto done; - } - - (void) func(data, stat_type); - -done: - /* We have our data, remove it from DTrace. */ - return (DTRACE_AGGWALK_REMOVE); -} - -/* - * Callback to handle DTrace drop data events. - */ -/*ARGSUSED*/ -static int -drop_handler(const dtrace_dropdata_t *data, void *user) -{ - lt_display_error("Drop: %s\n", data->dtdda_msg); - /* - * Pretend nothing happened. So our program can continue. - */ - return (DTRACE_HANDLE_OK); -} - -/* - * DTrace initialization. The D script is running when this function returns. - */ -int -lt_dtrace_init(void) -{ - dtrace_prog_t *prog; - dtrace_proginfo_t info; - int err; - FILE *fp_script = NULL; - - pid_self = getpid(); - /* Open dtrace, set up handler */ - g_dtp = dtrace_open(DTRACE_VERSION, 0, &err); - if (g_dtp == NULL) { - lt_display_error("Cannot open dtrace library: %s\n", - dtrace_errmsg(NULL, err)); - return (-1); - } - - if (dtrace_handle_drop(g_dtp, &drop_handler, NULL) == -1) { - lt_display_error("Cannot install DTrace handle: %s\n", - dtrace_errmsg(NULL, err)); - return (-1); - } - - /* Load D script, set up macro and compile */ -#ifdef EMBED_CONFIGS - /* Create a temp file because libdtrace use cpp(1) on files only. */ - fp_script = tmpfile(); - if (fp_script == NULL) { - lt_display_error("Cannot create tmp file\n"); - return (-1); - } - (void) fwrite(latencytop_d, latencytop_d_len, 1, fp_script); - (void) fseek(fp_script, 0, SEEK_SET); -#else - fp_script = fopen(DEFAULT_D_SCRIPT_NAME, "r"); - if (fp_script == NULL) { - lt_display_error("Cannot open script file %s\n", - DEFAULT_D_SCRIPT_NAME); - return (-1); - } -#endif /* EMBED_CONFIGS */ - - if (g_config.enable_filter) { - (void) dtrace_setopt(g_dtp, "define", "ENABLE_FILTER"); - } - if (g_config.trace_syncobj) { - (void) dtrace_setopt(g_dtp, "define", "ENABLE_SYNCOBJ"); - } - if (g_config.trace_sched) { - (void) dtrace_setopt(g_dtp, "define", "ENABLE_SCHED"); - } - if (g_config.low_overhead_mode) { - (void) dtrace_setopt(g_dtp, "define", "ENABLE_LOW_OVERHEAD"); - } - - prog = dtrace_program_fcompile(g_dtp, fp_script, - DTRACE_C_CPP, 0, NULL); - (void) fclose(fp_script); - if (prog == NULL) { - lt_display_error("Failed to compile D script.\n"); - return (dtrace_errno(g_dtp)); - } - - /* Execute the D script */ - if (dtrace_program_exec(g_dtp, prog, &info) == -1) { - lt_display_error("Failed to enable probes.\n"); - return (dtrace_errno(g_dtp)); - } - if (dtrace_go(g_dtp) != 0) { - lt_display_error("Failed to run D script.\n"); - return (dtrace_errno(g_dtp)); - } - return (0); -} - -/* - * Worker function to move aggregator data to user space. - * Needs to be called periodically to prevent running out of kernel memory. - */ -int -lt_dtrace_work(int force) -{ - static uint64_t last_snap = 0; - uint64_t now = lt_millisecond(); - - if (!force && now - last_snap < g_config.snap_interval) { - return (last_snap + g_config.snap_interval - now); - } - - if (dtrace_status(g_dtp) == -1) { - lt_display_error("Failed when getting status: %s\n", - dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); - return (-1); - } - - if (dtrace_aggregate_snap(g_dtp) != 0) { - lt_display_error("Failed to snap aggregate: %s\n", - dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); - return (-1); - } - - last_snap = now; - return (0); -} - -/* - * Walk through aggregator and collect data to LatencyTOP. - * Different from lt_dtrace_work, this one moves data from libdtrace - * to latencytop. - * This needs to be called immediately before update UI. - */ -int -lt_dtrace_collect(void) -{ - if (lt_dtrace_work(1) != 0) { - return (-1); - } - - if (dtrace_aggregate_walk(g_dtp, aggwalk, NULL) != 0) { - lt_display_error("Failed to sort aggregate: %s\n", - dtrace_errmsg(g_dtp, dtrace_errno(g_dtp))); - return (-1); - } - - /* - * Probably no need to clear again, because we removed everything. - * Paranoid. - */ - dtrace_aggregate_clear(g_dtp); - - return (0); -} - -/* - * Clean up and close DTrace. - */ -void -lt_dtrace_deinit(void) -{ - (void) dtrace_stop(g_dtp); - dtrace_close(g_dtp); -}
--- a/usr/src/cmd/latencytop/common/klog.c Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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) 2008-2009, Intel Corporation. - * All Rights Reserved. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <memory.h> -#include <string.h> -#include <procfs.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <limits.h> -#include <unistd.h> - -#include "latencytop.h" - -static GHashTable *proc_table = NULL; /* pid -> char * */ -static GHashTable *klog_table = NULL; /* char * -> uint64_t total */ -static char klog_filename[PATH_MAX] = DEFAULT_KLOG_FILE; -static int klog_level = LT_KLOG_LEVEL_NONE; - -static void -print_proc(void *key, const char *args, FILE *fp) -{ - pid_t pid = LT_POINTER_TO_INT(key); - char tmp[16]; - - (void) snprintf(tmp, sizeof (tmp), "%ld,", (long)pid); - (void) fprintf(fp, "%-8s \"%s\"\n", tmp, args); -} - -static void -print_stat(const char *key, lt_stat_data_t *log, FILE *fp) -{ - (void) fprintf(fp, "%lld, %lld, %lld, %s\n", - (long long)log->total, - (long long)log->count, - (long long)log->max, - key); -} - -/* - * Initialize kernel stack logging. - */ -void -lt_klog_init(void) -{ - if (klog_table != NULL || proc_table != NULL) { - return; - } - - klog_table = g_hash_table_new_full(g_str_hash, g_str_equal, - (GDestroyNotify)free, (GDestroyNotify)free); - lt_check_null(klog_table); - - proc_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify)free); - lt_check_null(proc_table); -} - -/* - * Set log file path. - */ -int -lt_klog_set_log_file(const char *filename) -{ - FILE *fp; - int file_exist; - - if (strlen(filename) >= sizeof (klog_filename)) { - return (-1); - } - - file_exist = lt_file_exist(filename); - /* Test if we can write to the file */ - fp = fopen(filename, "a"); - if (fp == NULL) { - return (-2); - } - (void) fclose(fp); - /* Don't leave empty file behind */ - if (!file_exist) { - (void) unlink(filename); - } - - (void) strncpy(klog_filename, filename, - sizeof (klog_filename)); - - return (0); -} - -/* - * Set log level. - */ -int -lt_klog_set_log_level(int level) -{ - if (level < 0 || level > (int)LT_KLOG_LEVEL_ALL) { - return (-1); - } - - klog_level = level; - - return (0); -} - -/* - * Write the log to file. - */ -void -lt_klog_write(void) -{ - FILE *fp; - char buffer[32]; - - if (klog_level == LT_KLOG_LEVEL_NONE) { - return; - } - - g_assert(klog_table != NULL && proc_table != NULL); - - fp = fopen(klog_filename, "a"); - if (fp == NULL) { - return; - } - - lt_time_str(buffer, sizeof (buffer)); - - (void) fprintf(fp, "# Log generated %s by %s\n", buffer, TITLE); - (void) fprintf(fp, "# List of processes\n"); - (void) fprintf(fp, "PID, CMD\n"); - g_hash_table_foreach(proc_table, - (GHFunc)print_proc, fp); - - (void) fprintf(fp, "# Statistics\n"); - (void) fprintf(fp, "TOTAL, COUNT, MAX, PID, KSTACK\n"); - g_hash_table_foreach(klog_table, - (GHFunc)print_stat, fp); - - (void) fclose(fp); -} - -/* - * Clean up function. This will cause all log in memory be written to the - * log file. - */ -void -lt_klog_deinit(void) -{ - if (klog_table != NULL) { - g_hash_table_destroy(klog_table); - klog_table = NULL; - } - - if (proc_table != NULL) { - g_hash_table_destroy(proc_table); - proc_table = NULL; - } -} - -/* - * Log a stack and its statistics. Only "total" will be logged, others are - * internally discarded. - */ -/* ARGSUSED */ -void -lt_klog_log(int level, pid_t pid, char *stack, - lt_stat_type_t type, uint64_t value) -{ - lt_stat_data_t *entry = NULL; - char *psargs; - char *str; - int str_len; - - if ((level & klog_level) == 0) { - return; - } - g_assert(klog_table != NULL && proc_table != NULL); - - psargs = (char *)g_hash_table_lookup(proc_table, - LT_INT_TO_POINTER(pid)); - if (psargs == NULL) { - psargs = lt_get_proc_field(pid, LT_FIELD_PSARGS); - if (psargs == NULL) { - psargs = lt_get_proc_field(pid, LT_FIELD_FNAME); - } - - if (psargs == NULL) { - return; - } - - g_hash_table_insert(proc_table, - LT_INT_TO_POINTER(pid), psargs); - } - - str_len = strlen(stack) + 20; - str = lt_malloc(str_len); - (void) snprintf(str, str_len, "%ld, \"%s\"", pid, stack); - - entry = (lt_stat_data_t *)g_hash_table_lookup(klog_table, str); - if (entry == NULL) { - entry = (lt_stat_data_t *)lt_zalloc(sizeof (lt_stat_data_t)); - g_hash_table_insert(klog_table, str, entry); - } else { - free(str); - } - - lt_update_stat_value(entry, type, value); -}
--- a/usr/src/cmd/latencytop/common/latencytop.c Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,362 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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) 2008-2009, Intel Corporation. - * All Rights Reserved. - */ - -#include <unistd.h> -#include <getopt.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <limits.h> -#include <libgen.h> -#include <signal.h> -#include "latencytop.h" - -#define CMPOPT(a, b) strncmp((a), (b), sizeof (b)) - -lt_config_t g_config; - -/* - * Prints help for command line parameters. - */ -static void -print_usage(const char *execname) -{ - char buffer[PATH_MAX]; - (void) snprintf(buffer, sizeof (buffer), "%s", execname); - (void) fprintf(stderr, "\nUsage: %s [option(s)]\n", basename(buffer)); - (void) fprintf(stderr, "Options:\n" - " -h, --help\n" - " Print this help.\n" - " -t, --interval TIME\n" - " Set refresh interval to TIME. " - "Valid range [1...60] seconds, default = 5\n" - /* - * Keep this option private, until we have chance to properly document - * the format of translation rules. - */ -#if 0 - " -c, --config FILE\n" - " Use translation rules defined in FILE.\n" -#endif - " -o, --output-log-file FILE\n" - " Output kernel log to FILE. Default = " - DEFAULT_KLOG_FILE "\n" - " -k, --kernel-log-level LEVEL\n" - " Set kernel log level to LEVEL.\n" - " 0(default) = None, 1 = Unmapped, 2 = Mapped, 3 = All.\n" - " -f, --feature [no]feature1,[no]feature2,...\n" - " Enable/disable features in LatencyTOP.\n" - " [no]filter:\n" - " Filter large interruptible latencies, e.g. sleep.\n" - " [no]sched:\n" - " Monitors sched (PID=0).\n" - " [no]sobj:\n" - " Monitors synchronization objects.\n" - " [no]low:\n" - " Lower overhead by sampling small latencies.\n" - " -l, --log-period TIME\n" - " Write and restart log every TIME seconds, TIME > 60s\n"); -} - -/* - * Properly shut down when latencytop receives SIGINT or SIGTERM. - */ -/* ARGSUSED */ -static void -signal_handler(int sig) -{ - lt_gpipe_break("q"); -} - -/* - * Convert string to integer, return error if extra characters are found. - */ -static int -to_int(const char *str, int *result) -{ - char *tail = NULL; - long ret; - - if (str == NULL || result == NULL) { - return (-1); - } - - ret = strtol(str, &tail, 10); - - if (tail != NULL && *tail != '\0') { - return (-1); - } - - *result = (int)ret; - - return (0); -} - -/* - * The main function. - */ -int -main(int argc, char *argv[]) -{ - const char *opt_string = "t:o:k:hf:l:c:"; - struct option const longopts[] = - { - {"interval", required_argument, NULL, 't'}, - {"output-log-file", required_argument, NULL, 'o'}, - {"kernel-log-level", required_argument, NULL, 'k'}, - {"help", no_argument, NULL, 'h'}, - {"feature", required_argument, NULL, 'f'}, - {"log-period", required_argument, NULL, 'l'}, - {"config", required_argument, NULL, 'c'}, - {NULL, 0, NULL, 0} - }; - - int optc; - int longind = 0; - int running = 1; - int unknown_option = FALSE; - int refresh_interval = 5; - int klog_level = 0; - int log_interval = 0; - long long last_logged = 0; - char *token = NULL; - int retval = 0; - int gpipe; - int err; - uint64_t collect_end; - uint64_t current_time; - uint64_t delta_time; - - lt_gpipe_init(); - (void) signal(SIGINT, signal_handler); - (void) signal(SIGTERM, signal_handler); - - (void) printf("%s\n%s\n", TITLE, COPYRIGHT); - - /* Default global settings */ - g_config.enable_filter = 0; - g_config.trace_sched = 0; - g_config.trace_syncobj = 1; - g_config.low_overhead_mode = 0; - g_config.snap_interval = 1000; /* DTrace snapshot every 1 sec */ -#ifdef EMBED_CONFIGS - g_config.config_name = NULL; -#else - g_config.config_name = lt_strdup(DEFAULT_CONFIG_NAME); -#endif - - /* Parse command line arguments. */ - while ((optc = getopt_long(argc, argv, opt_string, - longopts, &longind)) != -1) { - switch (optc) { - case 'h': - print_usage(argv[0]); - goto end_none; - case 't': - if (to_int(optarg, &refresh_interval) != 0 || - refresh_interval < 1 || refresh_interval > 60) { - lt_display_error( - "Invalid refresh interval: %s\n", optarg); - unknown_option = TRUE; - } - break; - case 'k': - if (to_int(optarg, &klog_level) != 0 || - lt_klog_set_log_level(klog_level) != 0) { - lt_display_error( - "Invalid log level: %s\n", optarg); - unknown_option = TRUE; - } - break; - case 'o': - err = lt_klog_set_log_file(optarg); - if (err == 0) { - (void) printf("Writing to log file %s.\n", - optarg); - } else if (err == -1) { - lt_display_error( - "Log file name is too long: %s\n", - optarg); - unknown_option = TRUE; - } else if (err == -2) { - lt_display_error( - "Cannot write to log file: %s\n", - optarg); - unknown_option = TRUE; - } - break; - case 'f': - for (token = strtok(optarg, ","); token != NULL; - token = strtok(NULL, ",")) { - int v = TRUE; - if (strncmp(token, "no", 2) == 0) { - v = FALSE; - token = &token[2]; - } - if (CMPOPT(token, "filter") == 0) { - g_config.enable_filter = v; - } else if (CMPOPT(token, "sched") == 0) { - g_config.trace_sched = v; - } else if (CMPOPT(token, "sobj") == 0) { - g_config.trace_syncobj = v; - } else if (CMPOPT(token, "low") == 0) { - g_config.low_overhead_mode = v; - } else { - lt_display_error( - "Unknown feature: %s\n", token); - unknown_option = TRUE; - } - } - break; - case 'l': - if (to_int(optarg, &log_interval) != 0 || - log_interval < 60) { - lt_display_error( - "Invalid refresh interval: %s\n", optarg); - unknown_option = TRUE; - } - break; - case 'c': - if (strlen(optarg) > PATH_MAX) { - lt_display_error( - "Configuration name is too long.\n"); - unknown_option = TRUE; - } else { - g_config.config_name = lt_strdup(optarg); - } - break; - default: - unknown_option = TRUE; - break; - } - } - - /* Throw error for commands like: "latencytop 12345678" */ - if (optind < argc) { - int tmpind = optind; - (void) printf("Unknown option(s): "); - while (tmpind < argc) { - (void) printf("%s ", argv[tmpind++]); - } - (void) printf("\n"); - unknown_option = TRUE; - } - - if (unknown_option) { - print_usage(argv[0]); - retval = 1; - goto end_none; - } - - /* Initialization */ - lt_klog_init(); - if (lt_table_init() != 0) { - lt_display_error("Unable to load configuration table.\n"); - retval = 1; - goto end_notable; - } - if (lt_dtrace_init() != 0) { - lt_display_error("Unable to initialize dtrace.\n"); - retval = 1; - goto end_nodtrace; - } - - last_logged = lt_millisecond(); - - (void) printf("Collecting data for %d seconds...\n", - refresh_interval); - - gpipe = lt_gpipe_readfd(); - collect_end = last_logged + refresh_interval * 1000; - for (;;) { - fd_set read_fd; - struct timeval timeout; - int tsleep = collect_end - lt_millisecond(); - - if (tsleep <= 0) { - break; - } - - if (tsleep > g_config.snap_interval * 1000) { - tsleep = g_config.snap_interval * 1000; - } - - timeout.tv_sec = tsleep / 1000; - timeout.tv_usec = (tsleep % 1000) * 1000; - - FD_ZERO(&read_fd); - FD_SET(gpipe, &read_fd); - if (select(gpipe + 1, &read_fd, NULL, NULL, &timeout) > 0) { - goto end_ubreak; - } - - (void) lt_dtrace_work(0); - } - - lt_display_init(); - - do { - current_time = lt_millisecond(); - - lt_stat_clear_all(); - (void) lt_dtrace_collect(); - - delta_time = current_time; - current_time = lt_millisecond(); - delta_time = current_time - delta_time; - - if (log_interval > 0 && - current_time - last_logged > log_interval * 1000) { - lt_klog_write(); - last_logged = current_time; - } - - running = lt_display_loop(refresh_interval * 1000 - - delta_time); - } while (running != 0); - - lt_klog_write(); - - /* Cleanup */ - lt_display_deinit(); - -end_ubreak: - lt_dtrace_deinit(); - lt_stat_free_all(); - -end_nodtrace: - lt_table_deinit(); - -end_notable: - lt_klog_deinit(); - -end_none: - lt_gpipe_deinit(); - if (g_config.config_name != NULL) { - free(g_config.config_name); - } - - return (retval); -}
--- a/usr/src/cmd/latencytop/common/latencytop.d Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,305 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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) 2008-2009, Intel Corporation. - * All Rights Reserved. - */ - -#pragma D option aggsize=8m -#pragma D option bufsize=16m -#pragma D option dynvarsize=16m -#pragma D option aggrate=0 -#pragma D option stackframes=64 - -#if defined(ENABLE_SCHED) -#define TRACE_FILTER -#define TRACE_FILTER_COND(a) / (a) / -#else -#define TRACE_FILTER / pid != 0 / -#define TRACE_FILTER_COND(a) / pid != 0 && (a) / -#endif - -#define FILTER_THRESHOLD 5000000 -/* From thread.h */ -#define T_WAKEABLE 2 - -/* - * This array is used to store the timestamp when threads are enqueued - * to dispq. - * self-> is not accessible when enqueue happens. - */ -unsigned long long lt_timestamps[int, int]; - -self unsigned int lt_is_block_wakeable; -self unsigned long long lt_sleep_start; -self unsigned long long lt_sleep_duration; -self unsigned long long lt_sch_delay; -self unsigned int lt_counter; /* only used in low overhead */ -self unsigned long long lt_timestamp; /* only used in low overhead */ - -/* - * Make sure we leave nothing behind, - * otherwise memory will eventually run out. - */ -proc:::lwp-exit -{ - lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid] = 0; - self->lt_sleep_start = 0; - self->lt_is_block_wakeable = 0; - self->lt_counter = 0; - self->lt_timestamp = 0; -} - -#if !defined(ENABLE_LOW_OVERHEAD) -/* - * Log timestamp when a thread is off CPU. - */ -sched::resume:off-cpu -TRACE_FILTER_COND(curlwpsinfo->pr_state == SSLEEP) -{ - self->lt_sleep_start = timestamp; - self->lt_is_block_wakeable = curthread->t_flag & T_WAKEABLE; - lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid] = - self->lt_sleep_start; -} - -/* - * Log timestamp when a thread is put on a dispatch queue and becomes runnable. - */ -sched:::enqueue -/ lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid] != 0 / -{ - lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid] = timestamp; -} - -/* - * Calculate latencies when the thread is actually on CPU. - * This is necessary to get the right stack(). - */ -this unsigned long long end; -this unsigned long long now; -sched::resume:on-cpu -/ self->lt_sleep_start != 0 / -{ - this->end = lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid]; - this->now = timestamp; - lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid] = 0; - this->end = (this->end != 0 && this->end != self->lt_sleep_start) - ? this->end : this->now; - self->lt_sch_delay = this->now - this->end; - self->lt_sleep_duration = this->end - self->lt_sleep_start; - self->lt_sleep_start = 0; -} - -/* - * Filter: drop all "large" latencies when it is wakeable, - * trying to filter sleep() etc. - */ -#if defined(ENABLE_FILTER) -sched::resume:on-cpu -/ self->lt_sleep_duration > FILTER_THRESHOLD && - self->lt_is_block_wakeable != 0 / -{ - self->lt_sch_delay = 0; - self->lt_sleep_duration = 0; - self->lt_is_block_wakeable = 0; -} -#endif /* defined(ENABLE_FILTER) */ - -/* - * Write sleep time to the aggregation. - * lt_sleep_duration is from thread off cpu to it is enqueued again. - */ -sched::resume:on-cpu -/ self->lt_sleep_duration != 0 / -{ - @lt_call_count[pid, tid, stack()] = count(); - @lt_call_sum[pid, tid, stack()] = sum(self->lt_sleep_duration); - @lt_call_max[pid, tid, stack()] = max(self->lt_sleep_duration); - self->lt_is_block_wakeable = 0; /* Clean the flag to avoid leak */ - self->lt_sleep_duration = 0; -} - -/* - * Write time spent in queue to the aggregation. - * lt_sch_delay: the interval between "thread runnable" and "thread on cpu". - */ -sched::resume:on-cpu -/ self->lt_sch_delay != 0 / -{ - @lt_named_count[pid, tid, "Wait for available CPU"] = count(); - @lt_named_sum[pid, tid, "Wait for available CPU"] = - sum(self->lt_sch_delay); - @lt_named_max[pid, tid, "Wait for available CPU"] = - max(self->lt_sch_delay); - self->lt_sch_delay = 0; -} - -/* - * Probes that tracks lock spinning - */ -lockstat:::adaptive-spin -TRACE_FILTER -{ - @lt_named_count[pid, tid, "Adapt. lock spin"] = count(); - @lt_named_sum[pid, tid, "Adapt. lock spin"] = sum(arg1); - @lt_named_max[pid, tid, "Adapt. lock spin"] = max(arg1); -} - -lockstat:::spin-spin -TRACE_FILTER -{ - @lt_named_count[pid, tid, "Spinlock spin"] = count(); - @lt_named_sum[pid, tid, "Spinlock spin"] = sum(arg1); - @lt_named_max[pid, tid, "Spinlock spin"] = max(arg1); -} - -/* - * Probes that tracks lock blocking - */ -lockstat:::adaptive-block -TRACE_FILTER -{ - @lt_named_count[pid, tid, "#Adapt. lock block"] = count(); - @lt_named_sum[pid, tid, "#Adapt. lock block"] = sum(arg1); - @lt_named_max[pid, tid, "#Adapt. lock block"] = max(arg1); -} - -lockstat:::rw-block -TRACE_FILTER -{ - @lt_named_count[pid, tid, "#RW. lock block"] = count(); - @lt_named_sum[pid, tid, "#RW. lock block"] = sum(arg1); - @lt_named_max[pid, tid, "#RW. lock block"] = max(arg1); -} - -#if defined(ENABLE_SYNCOBJ) -/* - * Probes that tracks synchronization objects. - */ -this int stype; -this unsigned long long wchan; -this unsigned long long wtime; -sched:::wakeup -/* - * Currently we are not able to track wakeup from sched, because all lwpid - * are zero for when we trace sched. That makes lt_timestamps not usable. - */ -/ args[1]->pr_pid != 0 && - lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid] != 0 / -{ - this->stype = args[0]->pr_stype; - this->wchan = args[0]->pr_wchan; - /* - * We can use lt_timestamps[] here, because - * wakeup is always fired before enqueue. - * After enqueue, lt_timestamps[] will be overwritten. - */ - this->wtime = timestamp - - lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid]; - @lt_sync_count[args[1]->pr_pid, args[0]->pr_lwpid, this->stype, - this->wchan] = count(); - @lt_sync_sum[args[1]->pr_pid, args[0]->pr_lwpid, this->stype, - this->wchan] = sum(this->wtime); - @lt_sync_max[args[1]->pr_pid, args[0]->pr_lwpid, this->stype, - this->wchan] = max(this->wtime); -} -#endif /* defined(ENABLE_SYNCOBJ) */ - -#else /* !defined(ENABLE_LOW_OVERHEAD) */ - -/* - * This is the low overhead mode. - * In order to reduce the number of instructions executed during each - * off-cpu and on-cpu event, we do: - * 1. Use sampling, only update aggregations roughly 1/100 times (SAMPLE_TIMES). - * 2. Do not track anything other than needed for "main" window. - * 3. Use as few thread local variables as possible. - */ - -#define SAMPLE_TIMES 100 -#define SAMPLE_THRESHOLD 50000000 - -/* - * Log timestamp when a thread is off CPU. - */ -sched::resume:off-cpu -TRACE_FILTER_COND(curlwpsinfo->pr_state == SSLEEP) -{ - self->lt_timestamp = timestamp; -#if defined(ENABLE_FILTER) - self->lt_is_block_wakeable = curthread->t_flag & T_WAKEABLE; -#endif /* defined(ENABLE_FILTER) */ -} - -/* - * Calculate latencies when the thread is actually on CPU. - */ -this int need_skip; -sched::resume:on-cpu -/ self->lt_timestamp != 0 / -{ - self->lt_timestamp = timestamp - self->lt_timestamp; - -#if defined(ENABLE_FILTER) - self->lt_timestamp = - (self->lt_timestamp > FILTER_THRESHOLD && - self->lt_is_block_wakeable != 0) ? 0 : self->lt_timestamp; - self->lt_is_block_wakeable = 0; -#endif /* defined(ENABLE_FILTER) */ - - this->need_skip = (self->lt_counter < (SAMPLE_TIMES - 1) && - self->lt_timestamp <= SAMPLE_THRESHOLD) ? 1 : 0; - self->lt_timestamp = this->need_skip ? 0 : self->lt_timestamp; - self->lt_counter += this->need_skip; -} - -/* - * Log large ones first. - */ -sched::resume:on-cpu -/ self->lt_timestamp > SAMPLE_THRESHOLD / -{ - @lt_call_count[pid, tid, stack()] = sum(1); - @lt_call_sum[pid, tid, stack()] = sum(self->lt_timestamp); - @lt_call_max[pid, tid, stack()] = max(self->lt_timestamp); - - self->lt_timestamp = 0; -} - -/* - * If we fall to this probe, this must be a small latency and counter - * reaches SAMPLE_TIMES. - */ -sched::resume:on-cpu -/ self->lt_timestamp != 0 / -{ - /* Need +1 because lt_counter has not been updated in this cycle. */ - @lt_call_count[pid, tid, stack()] = sum(self->lt_counter + 1); - @lt_call_sum[pid, tid, stack()] = - sum((self->lt_counter + 1) * self->lt_timestamp); - @lt_call_max[pid, tid, stack()] = max(self->lt_timestamp); - - self->lt_timestamp = 0; - self->lt_counter = 0; -} - -#endif /* !defined(ENABLE_LOW_OVERHEAD) */
--- a/usr/src/cmd/latencytop/common/latencytop.h Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,272 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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) 2008-2009, Intel Corporation. - * All Rights Reserved. - */ - -#ifndef _LATENCYTOP_H -#define _LATENCYTOP_H - -#include <sys/types.h> - -/* - * GLib header file, including TRUE and FALSE definitions - */ -#include <glib.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Lint seems to be confused by glib header file. - */ -#ifdef __lint -#undef g_assert -#define g_assert(x) ((void)(x)) -#undef TRUE -#define TRUE 1 -#endif - -/* - * To avoid compiler warning, we define our own convertion. - */ -#define LT_POINTER_TO_INT(a) ((int)(long)(a)) -#define LT_INT_TO_POINTER(a) ((void *)(unsigned long)(a)) - -#define TITLE "LatencyTOP for OpenSolaris, version 1.0" -#define COPYRIGHT "Copyright (c) 2008-2009, Intel Corporation." -#define DEFAULT_KLOG_FILE "/var/log/latencytop.log" - -#define INVALID_PID (~0) -#define INVALID_TID (~0) -#define PID_SYS_GLOBAL INVALID_PID -#define INVALID_CAUSE 0 -#define HIGHER_PRIORITY(a, b) ((a) > (b)) - -#ifdef EMBED_CONFIGS -/* - * LatencyTOP configurations embedded in the binary. - * Array will be generated by /usr/bin/xxd. - */ -extern unsigned char latencytop_d[]; -extern unsigned int latencytop_d_len; -extern unsigned char latencytop_trans[]; -extern unsigned int latencytop_trans_len; -#else -/* - * LatencyTOP configurations is externally. This is easy for debugging. - */ -#define DEFAULT_CONFIG_NAME "./latencytop.trans" -#define DEFAULT_D_SCRIPT_NAME "./latencytop.d" -#endif - -typedef enum { - LT_STAT_COUNT, - LT_STAT_MAX, - LT_STAT_SUM, -} lt_stat_type_t; - -#define LT_KLOG_LEVEL_NONE 0 /* Log nothing */ -#define LT_KLOG_LEVEL_UNMAPPED 1 /* Log only stacks not mapped */ -#define LT_KLOG_LEVEL_MAPPED 2 /* Log only stacks mapped */ -#define LT_KLOG_LEVEL_ALL 3 /* Log all stacks, mapped or not */ - -typedef enum { - LT_LEVEL_GLOBAL, /* System wide statistics */ - LT_LEVEL_PROCESS, /* Per-process statistics */ - LT_LEVEL_THREAD, /* Per-thread statistics */ -} lt_stat_level_t; - -typedef enum { - LT_SORT_TOTAL, - LT_SORT_MAX, - LT_SORT_AVG, - LT_SORT_COUNT, -} lt_sort_t; - -typedef enum { - LT_FIELD_FNAME, - LT_FIELD_PSARGS, -} lt_field_t; - -typedef enum { - LT_LIST_CAUSE, /* Lists latency by the causes (default) */ - LT_LIST_SPECIALS, /* Lists only "special" causes. */ - LT_LIST_SOBJ /* Lists synchronization objects. */ -} lt_list_type_t; - -/* - * Data entry which contains the statistics. - */ -typedef struct { - uint64_t count; - uint64_t total; - uint64_t max; -} lt_stat_data_t; - -/* - * Data entry stored along with its name. - */ -typedef struct { - enum { - STAT_CAUSE, - STAT_SOBJ - } type; - const char *string; - lt_stat_data_t data; - union { - struct { - int id; - int flags; - } cause; - struct { - int id; - } sobj; - } type_data; -} lt_stat_entry_t; - -typedef struct { - int enable_filter; - int trace_sched; - int trace_syncobj; - int low_overhead_mode; - int snap_interval; - char *config_name; -} lt_config_t; - -extern lt_config_t g_config; /* The global settings */ - -/* - * Causes can be disabled in the configuration file. - * Once disabled, DTrace script will still capture such causes, - * but they will not be counted in LatencyTOP. - */ -#define CAUSE_FLAG_DISABLED 1 -/* - * Causes with this flag will not show and count as part of summary in - * "kstack window". - */ -#define CAUSE_FLAG_HIDE_IN_SUMMARY 2 -/* - * This is generated from D script (named cause), which is "special". - */ -#define CAUSE_FLAG_SPECIAL 4 -#define CAUSE_ALL_FLAGS 0xffffffff - -/* - * These functions collect data using DTrace. - */ -extern int lt_dtrace_init(void); -extern int lt_dtrace_work(int); -extern int lt_dtrace_collect(void); -extern void lt_dtrace_deinit(void); - -/* - * These functions maintain configuration, e.g. symbol to cause mapping. - */ -extern int lt_table_init(void); -extern int lt_table_lookup_cause(const char *, int *, int *); -extern const char *lt_table_get_cause_name(int); -extern int lt_table_get_cause_flag(int, int); -extern int lt_table_lookup_named_cause(char *, int); -extern void lt_table_deinit(void); - -/* - * These functions update tatistic data of all causes collected from DTrace. - */ -extern void lt_stat_update(pid_t, id_t, char *, lt_stat_type_t, uint64_t); -extern void lt_stat_update_cause(pid_t, id_t, int, lt_stat_type_t, uint64_t); -extern void lt_stat_update_sobj(pid_t, id_t, int, unsigned long long, - lt_stat_type_t, uint64_t); -extern void lt_stat_clear_all(void); -extern void lt_stat_free_all(void); - -/* - * These functions produce lists for display part. - * Note: after a call to lt_stat_update_*, the old lists will be invalid. - */ -extern void *lt_stat_list_create(lt_list_type_t, lt_stat_level_t, - pid_t, id_t, int, lt_sort_t); -extern int lt_stat_list_has_item(void *, int); -extern const char *lt_stat_list_get_reason(void *, int); -extern uint64_t lt_stat_list_get_max(void *, int); -extern uint64_t lt_stat_list_get_sum(void *, int); -extern uint64_t lt_stat_list_get_count(void *, int); -extern uint64_t lt_stat_list_get_gtotal(void *); -extern void lt_stat_list_free(void *); - -/* - * These functions produce process and thread list. - */ -extern int lt_stat_proc_list_create(pid_t **, id_t **); -extern void lt_stat_proc_list_free(pid_t *, id_t *); -extern const char *lt_stat_proc_get_name(pid_t); -extern int lt_stat_proc_get_nthreads(pid_t); - -/* - * Console based display functions using ncurses. - */ -extern void lt_display_init(void); -extern int lt_display_loop(int); -extern void lt_display_error(const char *, ...); -extern void lt_display_deinit(void); - -/* - * Write statistics to a log file. - * Useful for debug and offline analysis. - */ -extern void lt_klog_init(void); -extern void lt_klog_deinit(void); -extern int lt_klog_set_log_file(const char *); -extern int lt_klog_set_log_level(int); -extern void lt_klog_write(void); -extern void lt_klog_log(int, pid_t, char *, lt_stat_type_t, - uint64_t); - -/* - * Utility functions. - */ -extern uint64_t lt_millisecond(void); -extern const char *lt_text(const char *); -extern void *lt_malloc(size_t); -extern void *lt_zalloc(size_t); -extern char *lt_strdup(const char *); -extern void lt_check_null(void *); -extern void lt_time_str(char *, int); -extern char *lt_get_proc_field(pid_t, lt_field_t); -extern void lt_update_stat_value(lt_stat_data_t *, lt_stat_type_t, uint64_t); -extern int lt_sort_by_total_desc(lt_stat_entry_t *, lt_stat_entry_t *); -extern int lt_sort_by_max_desc(lt_stat_entry_t *, lt_stat_entry_t *); -extern int lt_sort_by_count_desc(lt_stat_entry_t *, lt_stat_entry_t *); -extern int lt_sort_by_avg_desc(lt_stat_entry_t *, lt_stat_entry_t *); -extern void lt_gpipe_init(void); -extern void lt_gpipe_deinit(void); -extern void lt_gpipe_break(const char *); -extern int lt_gpipe_readfd(void); -extern int lt_file_exist(const char *); - -#ifdef __cplusplus -} -#endif - -#endif /* _LATENCYTOP_H */
--- a/usr/src/cmd/latencytop/common/latencytop.trans Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,425 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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) 2008-2009, Intel Corporation. -# All Rights Reserved. -# -# LatencyTOP 0.1 configuration -# - -# Format: -# <priority> <module>`<function> <Category> -# Special command: -# ; <command> <option value> -# <command>: -# disable_category <category name> : do not count and display <category name> - -# Stream ops -40 genunix`strdoioctl Stream ioctl -40 genunix`strclose Stream close -40 genunix`strread Stream read -40 genunix`strwrite Stream write - -# Door ops -50 doorfs`door_call Door call -50 doorfs`door_return Door release - -# sockfs -50 sockfs`socktpi_close Close socket -50 sockfs`sotpi_connect Create socket connection -50 sockfs`socktpi_write Write to socket -50 sockfs`socktpi_read Read from socket - -# SCSI -40 sd`sd_ssc_send Execute USCSI command -40 sd`sdread SCSI read -40 sd`sdwrite SCSI write -30 sd`sd_check_media SCSI wait for device ready - -# UFS -50 ufs`ufs_sync UFS sync -50 ufs`ufs_fsync UFS sync -50 ufs`ufs_remove UFS remove file -50 ufs`ufs_create UFS create file -40 ufs`ufs_getpage UFS getpage -40 ufs`ufs_putpage UFS putpage -40 ufs`ufs_iget_alloced UFS get inode -40 ufs`ufs_ialloc UFS create inode -40 ufs`ldl_waito UFS log -40 ufs`alloc UFS alloc block - -# ZFS -50 zfs`zil_commit ZFS intent log commit -40 zfs`zfs_fsync ZFS sync -40 zfs`zfs_read ZFS read -40 zfs`zfs_write ZFS write -40 zfs`zfs_getattr ZFS get file attribute -40 zfs`zfs_remove ZFS remove file -40 zfs`zfs_create ZFS create file -40 zfs`zfs_close ZFS close file -40 zfs`zfs_open ZFS open file -40 zfs`zfs_getsecattr ZFS security check -40 zfs`zfs_umount ZFS unmount -30 zfs`zio_wait ZFS wait for I/O complete -30 zfs`spa_export ZFS export storage pool -30 zfs`spa_import ZFS import storage pool -30 zfs`zio_execute ZFS execute IO -30 zfs`spa_sync ZFS sync transaction group - -# Page fault -60 unix`pagefault Page fault - -# FIFO -50 fifofs`fifo_read Read from pipe/FIFO -50 fifofs`fifo_write Write to pipe/FIFO - -# Module -60 genunix`modload Loading kernel module - -# Devfs -50 devfs`dv_find Devfs lookup -50 dev`sdev_lookup Devfs lookup - -# Misc. -40 genunix`lookuppnat File system directory operation - -# -# FSFlush daemon -# - -15 genunix`fsflush Sleep in daemon (fsflush) - -# -# Pageout -# - -15 genunix`pageout_scanner Sleep in daemon (pageout) -15 genunix`pageout Sleep in daemon (pageout) - -# -# Syscalls -# -# Syscalls have priority 10, this is the lowest priority defined as default. -# This is to ensure a latency is traced to one of the syscalls if nothing -# else matches. -# - -15 unix`trap Processor Trap -15 genunix`post_syscall Post Syscall -5 unix`sys_syscall32 Syscall - -10 genunix`indir Syscall: indir -10 genunix`rexit Syscall: exit -10 genunix`forkall Syscall: forkall -10 genunix`read Syscall: read -10 genunix`read32 Syscall: read -10 genunix`write Syscall: write -10 genunix`write32 Syscall: write -10 genunix`open Syscall: open -10 genunix`open32 Syscall: open -10 genunix`close Syscall: close -10 genunix`wait Syscall: wait -10 genunix`creat Syscall: creat -10 genunix`creat32 Syscall: creat -10 genunix`link Syscall: link -10 genunix`unlink Syscall: unlink -10 genunix`exec Syscall: exec -10 genunix`chdir Syscall: chdir -10 genunix`gtime Syscall: time -10 genunix`mknod Syscall: mknod -10 genunix`chmod Syscall: chmod -10 genunix`chown Syscall: chown -10 genunix`brk Syscall: brk -10 genunix`stat Syscall: stat -10 genunix`stat32 Syscall: stat -10 genunix`lseek64 Syscall: lseek -10 genunix`lseek32 Syscall: lseek -10 genunix`getpid Syscall: getpid -10 genunix`mount Syscall: mount -10 genunix`umount Syscall: umount -10 genunix`setuid Syscall: setuid -10 genunix`getuid Syscall: getuid -10 genunix`stime Syscall: stime -10 genunix`stime32 Syscall: stime -10 genunix`pcsample Syscall: pcsample -10 genunix`alarm Syscall: alarm -10 genunix`fstat Syscall: fstat -10 genunix`fstat32 Syscall: fstat -10 genunix`pause Syscall: pause -10 genunix`utime Syscall: utime -10 genunix`stty Syscall: stty -10 genunix`gtty Syscall: gtty -10 genunix`access Syscall: access -10 genunix`nice Syscall: nice -10 genunix`statfs32 Syscall: statfs -10 genunix`syssync Syscall: sync -10 genunix`kill Syscall: kill -10 genunix`fstatfs32 Syscall: fstatfs -10 genunix`setpgrp Syscall: setpgrp -10 genunix`uucopystr Syscall: uucopystr -10 genunix`dup Syscall: dup -10 genunix`times Syscall: times -10 genunix`times32 Syscall: times -10 genunix`profil Syscall: prof -10 genunix`setgid Syscall: setgid -10 genunix`getgid Syscall: getgid -10 genunix`ssig Syscall: sig -10 unix`sysi86 Syscall: sysi86 -10 genunix`ioctl Syscall: ioctl -10 genunix`uadmin Syscall: uadmin -10 genunix`utssys64 Syscall: utssys -10 genunix`utssys32 Syscall: utssys -10 genunix`fdsync Syscall: fdsync -10 genunix`exece Syscall: exece -10 genunix`umask Syscall: umask -10 genunix`chroot Syscall: chroot -10 genunix`fcntl Syscall: fcntl -10 genunix`ulimit Syscall: ulimit -10 genunix`ulimit32 Syscall: ulimit -10 genunix`tasksys Syscall: tasksys -10 genunix`getpagesizes Syscall: getpagesizes -10 genunix`getpagesizes32 Syscall: getpagesizes -10 genunix`rctlsys Syscall: rctlsys -10 genunix`sidsys Syscall: sidsys -10 genunix`fsat64 Syscall: fsat -10 genunix`fsat32 Syscall: fsat -10 genunix`syslwp_park Syscall: lwp_park -10 genunix`sendfilev Syscall: sendfilev -10 genunix`rmdir Syscall: rmdir -10 genunix`mkdir Syscall: mkdir -10 genunix`getdents64 Syscall: getdents -10 genunix`getdents32 Syscall: getdents -10 genunix`privsys Syscall: privsys -10 genunix`privsys32 Syscall: privsys -10 genunix`ucredsys Syscall: ucredsys -10 genunix`ucredsys32 Syscall: ucredsys -10 genunix`sysfs Syscall: sysfs -10 genunix`getmsg Syscall: getmsg -10 genunix`getmsg32 Syscall: getmsg -10 genunix`putmsg Syscall: putmsg -10 genunix`putmsg32 Syscall: putmsg -10 genunix`poll Syscall: poll -10 genunix`lstat Syscall: lstat -10 genunix`lstat32 Syscall: lstat -10 genunix`symlink Syscall: symlink -10 genunix`readlink Syscall: readlink -10 genunix`readlink32 Syscall: readlink -10 genunix`setgroups Syscall: setgroups -10 genunix`getgroups Syscall: getgroups -10 genunix`fchmod Syscall: fchmod -10 genunix`fchown Syscall: fchown -10 genunix`sigprocmask Syscall: sigprocmask -10 genunix`sigsuspend Syscall: sigsuspend -10 genunix`sigaltstack Syscall: sigaltstack -10 genunix`sigaltstack32 Syscall: sigaltstack -10 genunix`sigaction Syscall: sigaction -10 genunix`sigaction32 Syscall: sigaction -10 genunix`sigpending Syscall: sigpending -10 genunix`getsetcontext Syscall: getsetcontext -10 genunix`getsetcontext32 Syscall: getsetcontext -10 genunix`statvfs Syscall: statvfs -10 genunix`statvfs32 Syscall: statvfs -10 genunix`fstatvfs Syscall: fstatvfs -10 genunix`fstatvfs32 Syscall: fstatvfs -10 genunix`getloadavg Syscall: getloadavg -10 genunix`waitsys Syscall: waitsys -10 genunix`waitsys32 Syscall: waitsys -10 genunix`sigsendsys Syscall: sigsendset -10 unix`hrtsys Syscall: hrtsys -10 genunix`sigresend Syscall: sigresend -10 genunix`priocntlsys Syscall: priocntlsys -10 genunix`pathconf Syscall: pathconf -10 genunix`mincore Syscall: mincore -10 genunix`smmap64 Syscall: mmap -10 genunix`smmap32 Syscall: mmap -10 genunix`mprotect Syscall: mprotect -10 genunix`munmap Syscall: munmap -10 genunix`fpathconf Syscall: fpathconf -10 genunix`vfork Syscall: vfork -10 genunix`fchdir Syscall: fchdir -10 genunix`readv Syscall: readv -10 genunix`readv32 Syscall: readv -10 genunix`writev Syscall: writev -10 genunix`writev32 Syscall: writev -10 genunix`xstat Syscall: xstat -10 genunix`xstat32 Syscall: xstat -10 genunix`lxstat Syscall: lxstat -10 genunix`lxstat32 Syscall: lxstat -10 genunix`fxstat Syscall: fxstat -10 genunix`fxstat32 Syscall: fxstat -10 genunix`xmknod Syscall: xmknod -10 genunix`setrlimit64 Syscall: setrlimit -10 genunix`setrlimit32 Syscall: setrlimit -10 genunix`getrlimit64 Syscall: getrlimit -10 genunix`getrlimit32 Syscall: getrlimit -10 genunix`lchown Syscall: lchown -10 genunix`memcntl Syscall: memcntl -10 genunix`getpmsg Syscall: getpmsg -10 genunix`getpmsg32 Syscall: getpmsg -10 genunix`putpmsg Syscall: putpmsg -10 genunix`putpmsg32 Syscall: putpmsg -10 genunix`rename Syscall: rename -10 genunix`uname Syscall: uname -10 genunix`setegid Syscall: setegid -10 genunix`sysconfig Syscall: sysconfig -10 genunix`adjtime Syscall: adjtime -10 genunix`systeminfo Syscall: systeminfo -10 genunix`seteuid Syscall: seteuid -10 genunix`forksys Syscall: forksys -10 genunix`fork1 Syscall: fork1 -10 genunix`sigtimedwait Syscall: sigtimedwait -10 genunix`lwp_info Syscall: lwp_info -10 genunix`yield Syscall: yield -10 genunix`lwp_sema_wait Syscall: lwp_sema_wait -10 genunix`lwp_sema_post Syscall: lwp_sema_post -10 genunix`lwp_sema_trywait Syscall: lwp_sema_trywait -10 genunix`lwp_detach Syscall: lwp_detach -10 genunix`corectl Syscall: corectl -10 genunix`modctl Syscall: modctl -10 genunix`fchroot Syscall: fchroot -10 genunix`utimes Syscall: utimes -10 genunix`vhangup Syscall: vhangup -10 genunix`gettimeofday Syscall: gettimeofday -10 genunix`getitimer Syscall: getitimer -10 genunix`setitimer Syscall: setitimer -10 genunix`syslwp_create Syscall: lwp_create -10 genunix`syslwp_exit Syscall: lwp_exit -10 genunix`syslwp_suspend Syscall: lwp_suspend -10 genunix`syslwp_continue Syscall: lwp_continue -10 genunix`lwp_kill Syscall: lwp_kill -10 genunix`lwp_self Syscall: lwp_self -10 genunix`lwp_sigmask Syscall: lwp_sigmask -10 genunix`syslwp_private Syscall: lwp_private -10 genunix`lwp_wait Syscall: lwp_wait -10 genunix`lwp_mutex_wakeup Syscall: lwp_mutex_wakeup -10 genunix`lwp_mutex_lock Syscall: lwp_mutex_lock -10 genunix`lwp_cond_wait Syscall: lwp_cond_wait -10 genunix`lwp_cond_signal Syscall: lwp_cond_signal -10 genunix`lwp_cond_broadcast Syscall: lwp_cond_broadcast -10 genunix`pread Syscall: pread -10 genunix`pread32 Syscall: pread -10 genunix`pwrite Syscall: pwrite -10 genunix`pwrite32 Syscall: pwrite -10 genunix`llseek32 Syscall: llseek -10 genunix`brandsys Syscall: brandsys -10 genunix`lgrpsys Syscall: lgrpsys -10 genunix`rusagesys Syscall: rusagesys -10 portfs`portfs Syscall: portfs -10 portfs`portfs32 Syscall: portfs -10 genunix`pollsys Syscall: pollsys -10 genunix`labelsys Syscall: labelsys -10 genunix`acl Syscall: acl -10 genunix`auditsys Syscall: auditsys -10 genunix`processor_bind Syscall: processor_bind -10 genunix`processor_info Syscall: processor_info -10 genunix`p_online Syscall: p_online -10 genunix`sigqueue Syscall: sigqueue -10 genunix`sigqueue32 Syscall: sigqueue -10 genunix`clock_gettime Syscall: clock_gettime -10 genunix`clock_settime Syscall: clock_settime -10 genunix`clock_getres Syscall: clock_getres -10 genunix`timer_create Syscall: timer_create -10 genunix`timer_delete Syscall: timer_delete -10 genunix`timer_settime Syscall: timer_settime -10 genunix`timer_gettime Syscall: timer_gettime -10 genunix`timer_getoverrun Syscall: timer_getoverrun -10 genunix`nanosleep Syscall: nanosleep -10 genunix`facl Syscall: facl -10 doorfs`doorfs Syscall: door -10 doorfs`doorfs32 Syscall: door -10 genunix`setreuid Syscall: setreuid -10 genunix`setregid Syscall: setregid -10 genunix`install_utrap Syscall: install_utrap -10 genunix`signotify Syscall: signotify -10 genunix`schedctl Syscall: schedctl -10 genunix`sparc_utrap_install Syscall: sparc_utrap_install -10 genunix`resolvepath Syscall: resolvepath -10 genunix`lwp_mutex_timedlock Syscall: lwp_mutex_timedlock -10 genunix`lwp_sema_timedwait Syscall: lwp_sema_timedwait -10 genunix`lwp_rwlock_sys Syscall: lwp_rwlock_sys -10 genunix`getdents64 Syscall: getdents64 -10 genunix`smmaplf32 Syscall: smmaplf32 -10 genunix`stat64 Syscall: stat64 -10 genunix`stat64_32 Syscall: stat64 -10 genunix`lstat64 Syscall: lstat64 -10 genunix`lstat64_32 Syscall: lstat64 -10 genunix`fstat64 Syscall: fstat64 -10 genunix`fstat64_32 Syscall: fstat64 -10 genunix`statvfs64 Syscall: statvfs64 -10 genunix`statvfs64_32 Syscall: statvfs64 -10 genunix`fstatvfs64 Syscall: fstatvfs64 -10 genunix`fstatvfs64_32 Syscall: fstatvfs64 -10 genunix`setrlimit64 Syscall: setrlimit64 -10 genunix`getrlimit64 Syscall: getrlimit64 -10 genunix`pread64 Syscall: pread64 -10 genunix`pwrite64 Syscall: pwrite64 -10 genunix`creat64 Syscall: creat64 -10 genunix`open64 Syscall: open64 -10 genunix`zone Syscall: zone -10 genunix`getcwd Syscall: getcwd -10 sockfs`so_socket Syscall: so_socket -10 sockfs`so_socketpair Syscall: so_socketpair -10 sockfs`bind Syscall: bind -10 sockfs`listen Syscall: listen -10 sockfs`accept Syscall: accept -10 sockfs`connect Syscall: connect -10 sockfs`shutdown Syscall: shutdown -10 sockfs`recv Syscall: recv -10 sockfs`recv32 Syscall: recv -10 sockfs`recvfrom Syscall: recvfrom -10 sockfs`recvfrom32 Syscall: recvfrom -10 sockfs`recvmsg Syscall: recvmsg -10 sockfs`send Syscall: send -10 sockfs`send32 Syscall: send -10 sockfs`sendmsg Syscall: sendmsg -10 sockfs`sendto Syscall: sendto -10 sockfs`sendto32 Syscall: sendto -10 sockfs`getpeername Syscall: getpeername -10 sockfs`getsockname Syscall: getsockname -10 sockfs`getsockopt Syscall: getsockopt -10 sockfs`setsockopt Syscall: setsockopt -10 sockfs`sockconfig Syscall: sockconfig -10 genunix`ntp_gettime Syscall: ntp_gettime -10 genunix`ntp_adjtime Syscall: ntp_adjtime -10 genunix`lwp_mutex_unlock Syscall: lwp_mutex_unlock -10 genunix`lwp_mutex_trylock Syscall: lwp_mutex_trylock -10 genunix`lwp_mutex_register Syscall: lwp_mutex_register -10 genunix`cladm Syscall: cladm -10 genunix`uucopy Syscall: uucopy -10 genunix`umount2 Syscall: umount2 - -# sched (pid = 0) -5 genunix`taskq_d_thread Sleep in daemon (sched) -5 ufs`trans_roll Sleep in daemon (sched) -5 zfs`txg_sync_thread Sleep in daemon (sched) -5 genunix`taskq_thread Sleep in daemon (sched) -5 zfs`l2arc_feed_thread Sleep in daemon (sched) -5 scsi`scsi_watch_thread Sleep in daemon (sched) -5 genunix`seg_pasync_thread Sleep in daemon (sched) -5 zfs`arc_reclaim_thread Sleep in daemon (sched) -5 zfs`txg_thread_wait Sleep in daemon (sched) -5 ip`squeue_worker Sleep in daemon (sched) -5 genunix`thread_reaper Sleep in daemon (sched) -5 zfs`txg_quiesce_thread Sleep in daemon (sched) -5 ufs`ufs_thread_delete Sleep in daemon (sched) - -#; disable_cause Sleep in daemon (fsflush) -#; disable_cause Sleep in daemon (pageout) -#; disable_cause Sleep in daemon (sched)
--- a/usr/src/cmd/latencytop/common/stat.c Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,995 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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) 2008-2009, Intel Corporation. - * All Rights Reserved. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <memory.h> -#include <string.h> -#include <limits.h> -#include <sys/stat.h> - -#include "latencytop.h" - -/* Statistics for each process/thread. */ -typedef struct _lt_stat_collection lt_stat_collection_t; -typedef gboolean (*check_child_func_t) (gpointer key, - lt_stat_collection_t *stat, void *user); - -typedef struct { - lt_stat_entry_t summary; - /* cause_id -> stat entry */ - GHashTable *sctable; -} lt_datagroup_t; - -#define NGROUPS 2 -#define GROUP_CAUSE 0 -#define GROUP_SOBJ 1 - -/* - * A data collection (i.e. a "bucket"). E.g. system, process or thread. - * Collections are hierarchic, 1 sys -> many processes -> more threads. - */ -struct _lt_stat_collection { - lt_stat_level_t level; - unsigned int id; - char *name; - lt_datagroup_t groups[NGROUPS]; - /* - * The following fields: parent, children and check_child_func - * maintain the tree structure. - */ - lt_stat_collection_t *parent; /* Parent node */ - GHashTable *children; /* pid (or tid) -> lt_stat_collection_t */ - check_child_func_t check_child_func; /* Release dead children */ -}; - -/* Internal data struct backs up a stat_list */ -typedef struct _lt_stat_list lt_stat_list_t; -typedef void (*free_list_func_t)(lt_stat_list_t *); -struct _lt_stat_list { - int entry_count; - lt_stat_entry_t **entries; - uint64_t gtotal; - free_list_func_t free_func; -}; - -/* The root collection: system level statistics */ -static lt_stat_collection_t *stat_system = NULL; - -/* - * The data structure which supports synchronization objects. - * We don't use normal "cause table" because this needs to be cleared - * every time we refresh, so that dead synchronization objects don't - * eat up memory little by little. - */ -typedef struct { - int sobj_type; - unsigned long long sobj_addr; -} lt_sobj_id_t; -typedef struct { - lt_sobj_id_t sobj_id; - int cause_id; - char string[32]; /* Enough to hold "%s: 0x%llX" */ -} lt_sobj_t; - -static GHashTable *sobj_table = NULL; -static int sobj_table_len = 0; - -/* - * Hash synchronize object ID by returning lower 32bit of its address. - */ -static guint -sobj_id_hash(lt_sobj_id_t *id) -{ - g_assert(id != NULL); - return (id->sobj_addr & 0xFFFFFFFF); -} - -/* - * Test if two synchronization objects are the same. - */ -static gboolean -sobj_id_equal(lt_sobj_id_t *a, lt_sobj_id_t *b) -{ - g_assert(a != NULL && b != NULL); - return (a->sobj_type == b->sobj_type && a->sobj_addr == b->sobj_addr); -} - -/* - * Lookup the cause_id of an synchronization object. - * Note this cause_id is only unique in GROUP_SOBJ, and changes after refresh. - */ -static lt_sobj_t * -lookup_sobj(lt_sobj_id_t *id) -{ - const char *stype_str[] = { - "None", - "Mutex", - "RWLock", - "CV", - "Sema", - "User", - "User_PI", - "Shuttle" - }; - const int stype_str_len = - sizeof (stype_str) / sizeof (stype_str[0]); - lt_sobj_t *ret = NULL; - - g_assert(id != NULL); - if (id->sobj_type < 0 || id->sobj_type >= stype_str_len) { - return (NULL); - } - - if (sobj_table != NULL) { - ret = (lt_sobj_t *)g_hash_table_lookup(sobj_table, id); - } else { - sobj_table = g_hash_table_new_full( - (GHashFunc)sobj_id_hash, (GEqualFunc)sobj_id_equal, - NULL, (GDestroyNotify)free); - lt_check_null(sobj_table); - } - - if (ret == NULL) { - ret = (lt_sobj_t *)lt_zalloc(sizeof (lt_sobj_t)); - ret->cause_id = ++sobj_table_len; - (void) snprintf(ret->string, sizeof (ret->string), - "%s: 0x%llX", stype_str[id->sobj_type], id->sobj_addr); - ret->sobj_id.sobj_type = id->sobj_type; - ret->sobj_id.sobj_addr = id->sobj_addr; - - g_hash_table_insert(sobj_table, &ret->sobj_id, ret); - } - - return (ret); -} - -/* - * Check if a process is alive by looking at /proc/pid - */ -/* ARGSUSED */ -static gboolean -check_process(gpointer key, lt_stat_collection_t *stat, void *user) -{ - char name[PATH_MAX]; - - (void) snprintf(name, PATH_MAX, "/proc/%u", stat->id); - /* Don't remove (return FALSE) if file exists */ - return (lt_file_exist(name) ? FALSE : TRUE); -} - -/* - * Check if a thread is alive by looking at /proc/pid/lwp/tid - */ -/* ARGSUSED */ -static gboolean -check_thread(gpointer key, lt_stat_collection_t *stat, void *user) -{ - char name[PATH_MAX]; - - g_assert(stat->parent != NULL); - g_assert(stat->parent->level == LT_LEVEL_PROCESS); - - (void) snprintf(name, PATH_MAX, "/proc/%u/lwp/%u", - stat->parent->id, stat->id); - /* Don't remove (return FALSE) if file exists */ - return (lt_file_exist(name) ? FALSE : TRUE); -} - -/* - * Helper function to free a stat node. - */ -static void -free_stat(lt_stat_collection_t *stat) -{ - int i; - - if (stat == NULL) { - return; - } - - for (i = 0; i < NGROUPS; ++i) { - if (stat->groups[i].sctable != NULL) { - g_hash_table_destroy(stat->groups[i].sctable); - } - } - - if (stat->children != NULL) { - g_hash_table_destroy(stat->children); - } - - if (stat->name != NULL) { - free(stat->name); - } - - free(stat); -} - -/* - * Helper function zeroing a stat node. - */ -/* ARGSUSED */ -static void -clear_stat(gpointer key, lt_stat_collection_t *stat, void *user) -{ - int i; - - g_assert(stat != NULL); - - for (i = 0; i < NGROUPS; ++i) { - if (stat->groups[i].sctable != NULL) { - g_hash_table_destroy(stat->groups[i].sctable); - stat->groups[i].sctable = NULL; - } - - stat->groups[i].summary.data.count = 0; - stat->groups[i].summary.data.total = 0; - stat->groups[i].summary.data.max = 0; - } - - if (stat->children != NULL) { - g_hash_table_foreach_remove(stat->children, - (GHRFunc)stat->check_child_func, NULL); - g_hash_table_foreach(stat->children, - (GHFunc)clear_stat, NULL); - } -} - -/* - * Update a collection for the value given. - * Recursively update its parent until it reaches the root. - */ -static void -update_stat_entry(lt_stat_collection_t *stat, int cause_id, - lt_stat_type_t type, uint64_t value, - const char *string, int group_to_use) -{ - lt_stat_entry_t *entry = NULL; - lt_datagroup_t *group; - - if (group_to_use < 0 || group_to_use >= NGROUPS) { - return; - } - group = &(stat->groups[group_to_use]); - - if (group->sctable != NULL) { - entry = (lt_stat_entry_t *)g_hash_table_lookup( - group->sctable, LT_INT_TO_POINTER(cause_id)); - } else { - group->sctable = g_hash_table_new_full( - g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify)free); - lt_check_null(group->sctable); - } - - if (entry == NULL) { - entry = (lt_stat_entry_t *)lt_zalloc(sizeof (lt_stat_entry_t)); - entry->string = string; - - switch (group_to_use) { - case GROUP_CAUSE: - entry->type = STAT_CAUSE; - entry->type_data.cause.id = cause_id; - entry->type_data.cause.flags = - lt_table_get_cause_flag(cause_id, CAUSE_ALL_FLAGS); - /* hide the first '#' */ - if ((entry->type_data.cause.flags - & CAUSE_FLAG_HIDE_IN_SUMMARY) != 0) { - ++entry->string; - } - break; - case GROUP_SOBJ: - entry->type = STAT_SOBJ; - entry->type_data.sobj.id = cause_id; - break; - } - - g_hash_table_insert(group->sctable, LT_INT_TO_POINTER(cause_id), - entry); - } - - lt_update_stat_value(&entry->data, type, value); - - if (group_to_use == GROUP_SOBJ || - (entry->type_data.cause.flags & CAUSE_FLAG_HIDE_IN_SUMMARY) == 0) { - lt_update_stat_value(&group->summary.data, type, value); - } - - if (stat->parent != NULL) { - update_stat_entry(stat->parent, cause_id, type, value, - string, group_to_use); - } -} - -/* - * Identify the cause from a stack trace. - * Returns the cause_id. - */ -static int -find_cause(char *stack) -{ - int cause_temp; - int prio_temp; - int cause = INVALID_CAUSE; - int priority = 0; - int found = 0; - - while (stack != NULL) { - char *sep; - sep = strchr(stack, ' '); - if (sep != NULL) { - *sep = 0; - } - - found = lt_table_lookup_cause(stack, &cause_temp, &prio_temp); - if (found && (cause == INVALID_CAUSE || - HIGHER_PRIORITY(prio_temp, priority))) { - cause = cause_temp; - priority = prio_temp; - } - - if (sep != NULL) { - *sep = ' '; - stack = sep + 1; - } else { - stack = NULL; - } - } - return (cause); -} - -/* - * Create a new collection, hook it to the parent. - */ -static lt_stat_collection_t * -new_collection(lt_stat_level_t level, unsigned int id, char *name, - lt_stat_collection_t *parent, check_child_func_t check_child_func) -{ - int i; - lt_stat_collection_t *ret; - - ret = (lt_stat_collection_t *) - lt_zalloc(sizeof (lt_stat_collection_t)); - - ret->level = level; - ret->check_child_func = check_child_func; - ret->id = id; - ret->name = name; - - for (i = 0; i < NGROUPS; ++i) { - ret->groups[i].summary.string = (const char *)name; - } - - if (parent != NULL) { - ret->parent = parent; - if (parent->children == NULL) { - parent->children = g_hash_table_new_full( - g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify)free_stat); - lt_check_null(parent->children); - } - g_hash_table_insert(parent->children, - LT_INT_TO_POINTER((int)id), ret); - } - - return (ret); -} - -/* - * Finds the "leaf" collection, use given pid and tid. - */ -static lt_stat_collection_t * -get_stat_c(pid_t pid, id_t tid) -{ - lt_stat_collection_t *stat_p = NULL; - lt_stat_collection_t *stat_t = NULL; - - if (stat_system == NULL) { - stat_system = new_collection(LT_LEVEL_GLOBAL, - PID_SYS_GLOBAL, lt_strdup("SYSTEM"), NULL, check_process); - } else if (stat_system->children != NULL) { - stat_p = (lt_stat_collection_t *) - g_hash_table_lookup(stat_system->children, - LT_INT_TO_POINTER(pid)); - } - - if (stat_p == NULL) { - char *fname; - - fname = lt_get_proc_field(pid, LT_FIELD_FNAME); - if (fname == NULL) { - /* - * we cannot get process execname, - * process is probably already dead. - */ - return (NULL); - } - - stat_p = new_collection(LT_LEVEL_PROCESS, - (unsigned int)pid, fname, stat_system, check_thread); - } else if (stat_p->children != NULL) { - stat_t = (lt_stat_collection_t *) - g_hash_table_lookup(stat_p->children, - LT_INT_TO_POINTER(tid)); - } - - if (stat_t == NULL) { - const int tname_size = 16; /* Enough for "Thread %d" */ - char *tname; - - tname = (char *)lt_malloc(tname_size); - (void) snprintf(tname, tname_size, "Thread %d", tid); - - stat_t = new_collection(LT_LEVEL_THREAD, - (unsigned int)tid, tname, stat_p, NULL); - } - - return (stat_t); -} - -/* - * Update the statistics given cause_id directly. Value will be added to - * internal statistics. - */ -void -lt_stat_update_cause(pid_t pid, id_t tid, int cause_id, lt_stat_type_t type, - uint64_t value) -{ - const char *string; - lt_stat_collection_t *stat_t = NULL; - - if (cause_id < 0 || value == 0) { - return; - } - - if (lt_table_get_cause_flag(cause_id, CAUSE_FLAG_DISABLED)) { - /* we don't care about this cause, ignore. */ - return; - } - - stat_t = get_stat_c(pid, tid); - if (stat_t == NULL) { - /* cannot get fname, process must be dead. */ - return; - } - - string = lt_table_get_cause_name(cause_id); - - update_stat_entry(stat_t, cause_id, type, value, string, GROUP_CAUSE); -} - -/* - * Update the statistics given the stack trace. - * Internally it will be mapped to a cause using lt_table_lookup_cause(), - * and call lt_stat_update_cause(). - */ -void -lt_stat_update(pid_t pid, id_t tid, char *stack, lt_stat_type_t type, - uint64_t value) -{ - int cause_id = INVALID_CAUSE; - - if (value == 0) { - return; - } - - cause_id = find_cause(stack); - if (cause_id == INVALID_CAUSE) { - cause_id = lt_table_lookup_named_cause(stack, 1); - lt_klog_log(LT_KLOG_LEVEL_UNMAPPED, pid, stack, type, value); - } else { - lt_klog_log(LT_KLOG_LEVEL_MAPPED, pid, stack, type, value); - } - - lt_stat_update_cause(pid, tid, cause_id, type, value); -} - -/* - * Zero all statistics, but keep the data structure in memory - * to be filled with new data immediately after. - */ -void -lt_stat_clear_all(void) -{ - if (stat_system != NULL) { - clear_stat(NULL, stat_system, NULL); - } - - if (sobj_table != NULL) { - g_hash_table_destroy(sobj_table); - sobj_table = NULL; - } -} - -/* - * Clean up function that frees all memory used by statistics. - */ -void -lt_stat_free_all(void) -{ - if (stat_system != NULL) { - free_stat(stat_system); - stat_system = NULL; - } - - if (sobj_table != NULL) { - g_hash_table_destroy(sobj_table); - sobj_table = NULL; - } -} - -/* - * Get top N causes of latency for a process. Returns handle to a stat_list. - * Use pid = PID_SYS_GLOBAL to get global top list. - * Call lt_stat_list_free after use. - */ -void * -lt_stat_list_create(lt_list_type_t list_type, lt_stat_level_t level, - pid_t pid, id_t tid, int count, lt_sort_t sort_by) -{ - GCompareFunc func; - GList *list, *walk; - lt_stat_collection_t *stat_c = NULL; - lt_stat_list_t *ret; - lt_datagroup_t *group; - - if (level == LT_LEVEL_GLOBAL) { - /* Use global entry */ - stat_c = stat_system; - } else if (stat_system != NULL && stat_system->children != NULL) { - /* Find process entry first */ - stat_c = (lt_stat_collection_t *)g_hash_table_lookup( - stat_system->children, LT_INT_TO_POINTER(pid)); - - if (level == LT_LEVEL_THREAD) { - /* - * If we request thread entry, find it based on - * process entry. - */ - if (stat_c != NULL && stat_c->children != NULL) { - stat_c = (lt_stat_collection_t *) - g_hash_table_lookup(stat_c->children, - LT_INT_TO_POINTER(tid)); - } else { - /* - * Couldn't find thread entry, set it to NULL - * so we will return empty list later. - */ - stat_c = NULL; - } - } - } - - ret = (lt_stat_list_t *)lt_zalloc(sizeof (lt_stat_list_t)); - ret->entries = (lt_stat_entry_t **) - lt_zalloc(count * sizeof (lt_stat_entry_t *)); - - if (stat_c == NULL) { - /* empty list */ - return (ret); - } - - if (list_type == LT_LIST_SOBJ) { - group = &(stat_c->groups[GROUP_SOBJ]); - } else { - group = &(stat_c->groups[GROUP_CAUSE]); - } - - if (group->sctable == NULL) { - /* empty list */ - return (ret); - } - - ret->gtotal = group->summary.data.total; - - list = g_hash_table_get_values(group->sctable); - - switch (sort_by) { - case LT_SORT_TOTAL: - func = (GCompareFunc)lt_sort_by_total_desc; - break; - case LT_SORT_MAX: - func = (GCompareFunc)lt_sort_by_max_desc; - break; - case LT_SORT_AVG: - func = (GCompareFunc)lt_sort_by_avg_desc; - break; - case LT_SORT_COUNT: - func = (GCompareFunc)lt_sort_by_count_desc; - break; - } - list = g_list_sort(list, func); - - for (walk = list; - walk != NULL && count > 0; - walk = g_list_next(walk), --count) { - lt_stat_entry_t *data = (lt_stat_entry_t *)walk->data; - - if (list_type == LT_LIST_CAUSE && - data->type == STAT_CAUSE && - (data->type_data.cause.flags & CAUSE_FLAG_HIDE_IN_SUMMARY) - != 0) { - continue; - } - if (list_type == LT_LIST_SPECIALS && - data->type == STAT_CAUSE && - (data->type_data.cause.flags & CAUSE_FLAG_SPECIAL) - == 0) { - continue; - } - if (data->data.count == 0) { - break; - } - ret->entries[ret->entry_count++] = data; - } - - g_list_free(list); - - return (ret); -} - -/* - * Free memory allocated by lt_stat_list_create(). - */ -void -lt_stat_list_free(void *ptr) -{ - lt_stat_list_t *list = (lt_stat_list_t *)ptr; - - if (list == NULL) { - return; - } - - if (list->free_func != NULL) { - list->free_func(list); - } - - if (list->entries != NULL) { - free(list->entries); - } - - free(list); -} - -/* - * Check if the list has item number i. - */ -int -lt_stat_list_has_item(void *ptr, int i) -{ - lt_stat_list_t *list = (lt_stat_list_t *)ptr; - - if (list == NULL || i < 0 || i >= list->entry_count || - list->entries[i] == NULL) { - return (0); - } - return (1); -} - -/* - * Get the display name of item number i in the list. - */ -const char * -lt_stat_list_get_reason(void *ptr, int i) -{ - lt_stat_list_t *list = (lt_stat_list_t *)ptr; - if (list == NULL || i < 0 || i >= list->entry_count || - list->entries[i] == NULL) { - return (NULL); - } - - g_assert(list->entries[i]->string != NULL); - - return (list->entries[i]->string); -} - -/* - * Get the max. of item number i in the list. - */ -uint64_t -lt_stat_list_get_max(void *ptr, int i) -{ - lt_stat_list_t *list = (lt_stat_list_t *)ptr; - - if (list == NULL || i < 0 || i >= list->entry_count || - list->entries[i] == NULL) { - return (0); - } - - return (list->entries[i]->data.max); -} - -/* - * Get the total of item number i in the list. - */ -uint64_t -lt_stat_list_get_sum(void *ptr, int i) -{ - lt_stat_list_t *list = (lt_stat_list_t *)ptr; - - if (list == NULL || i < 0 || i >= list->entry_count || - list->entries[i] == NULL) { - return (0); - } - - return (list->entries[i]->data.total); -} - -/* - * Get the count of item number i in the list. - */ -uint64_t -lt_stat_list_get_count(void *ptr, int i) -{ - lt_stat_list_t *list = (lt_stat_list_t *)ptr; - - if (list == NULL || i < 0 || i >= list->entry_count || - list->entries[i] == NULL) { - return (0); - } - - return (list->entries[i]->data.count); -} - -/* - * Get grand total of all latencies in the pid where the list is drawn. - */ -uint64_t -lt_stat_list_get_gtotal(void *ptr) -{ - lt_stat_list_t *list = (lt_stat_list_t *)ptr; - - if (list == NULL) { - return (0); - } - return (list->gtotal); -} - -/* - * ============================================================================ - * Process and thread list. - * They share a lot of static variables as stat part does, - * so put them in the same file. - */ - -/* - * Helper function, sort by PID/TID ascend. - */ -static int -sort_id(lt_stat_collection_t *a, lt_stat_collection_t *b) -{ - return ((int)(a->id - b->id)); -} - -/* - * Get current list of processes. Call lt_stat_proc_list_free after use. - */ -static int -plist_create(pid_t ** list) -{ - GList *pid_list, *walk; - int ret, count; - - ret = g_hash_table_size(stat_system->children); - *list = (pid_t *)lt_malloc(sizeof (pid_t) * ret); - - pid_list = g_hash_table_get_values(stat_system->children); - pid_list = g_list_sort(pid_list, (GCompareFunc)sort_id); - - for (walk = pid_list, count = 0; - walk != NULL && count < ret; - walk = g_list_next(walk), ++count) { - (*list)[count] = (int) - ((lt_stat_collection_t *)(walk->data))->id; - } - - g_list_free(pid_list); - - return (ret); -} - -/* - * Count how many threads are found so far in a process. - * Only thread caused SSLEEP will be found. - */ -/* ARGSUSED */ -static void -count_threads(gpointer key, lt_stat_collection_t *stat_c, int *ret) -{ - g_assert(ret != NULL); - - if (stat_c->children != NULL) { - *ret += g_hash_table_size(stat_c->children); - } -} - -/* - * Get current list of processes+threads. - * Call lt_stat_proc_list_free after use. - */ -static int -tlist_create(pid_t ** plist, id_t ** tlist) -{ - GList *pid_list, *walk_p; - GList *tid_list, *walk_t; - int ret = 0; - int count = 0; - - g_hash_table_foreach(stat_system->children, - (GHFunc)count_threads, &ret); - - *plist = (pid_t *)lt_malloc(sizeof (pid_t) * ret); - *tlist = (id_t *)lt_malloc(sizeof (id_t) * ret); - - pid_list = g_hash_table_get_values(stat_system->children); - pid_list = g_list_sort(pid_list, (GCompareFunc)sort_id); - - for (walk_p = pid_list; walk_p != NULL; - walk_p = g_list_next(walk_p)) { - lt_stat_collection_t *stat_p = - (lt_stat_collection_t *)walk_p->data; - - if (stat_p->children == NULL) { - continue; - } - - tid_list = g_hash_table_get_values(stat_p->children); - tid_list = g_list_sort(tid_list, (GCompareFunc)sort_id); - - for (walk_t = tid_list; walk_t != NULL; - walk_t = g_list_next(walk_t)) { - lt_stat_collection_t *stat_t = - (lt_stat_collection_t *)walk_t->data; - - (*plist)[count] = (int)stat_p->id; - (*tlist)[count] = (int)stat_t->id; - - ++count; - } - g_list_free(tid_list); - } - - g_list_free(pid_list); - g_assert(count == ret); - - return (ret); -} - -/* - * List processes that have been processed in LatencyTOP. - */ -int -lt_stat_proc_list_create(pid_t ** plist, id_t ** tlist) -{ - if (plist == NULL) { - return (-1); - } - - if (stat_system == NULL || stat_system->children == NULL) { - *plist = NULL; - - if (tlist != NULL) { - *tlist = NULL; - } - - return (0); - } - - if (tlist == NULL) { - return (plist_create(plist)); - } else { - return (tlist_create(plist, tlist)); - } -} - -/* - * Free memory allocated by lt_stat_proc_list_create(). - */ -void -lt_stat_proc_list_free(pid_t *plist, id_t *tlist) -{ - if (plist != NULL) { - free(plist); - } - - if (tlist != NULL) { - free(tlist); - } -} - -/* - * Get execname of a PID. - */ -const char * -lt_stat_proc_get_name(pid_t pid) -{ - lt_stat_collection_t *stat_p = NULL; - - if (stat_system == NULL || stat_system->children == NULL) { - return (NULL); - } - - stat_p = (lt_stat_collection_t *) - g_hash_table_lookup(stat_system->children, LT_INT_TO_POINTER(pid)); - - if (stat_p != NULL) { - return (stat_p->name); - } else { - return (NULL); - } -} - -/* - * Get number of threads. - */ -int -lt_stat_proc_get_nthreads(pid_t pid) -{ - lt_stat_collection_t *stat_p = NULL; - - if (stat_system == NULL || stat_system->children == NULL) { - return (0); - } - - stat_p = (lt_stat_collection_t *) - g_hash_table_lookup(stat_system->children, LT_INT_TO_POINTER(pid)); - - if (stat_p != NULL) { - return (g_hash_table_size(stat_p->children)); - } else { - return (0); - } -} - -/* - * Update the statistics for synchronization objects. - */ -void -lt_stat_update_sobj(pid_t pid, id_t tid, int stype, - unsigned long long wchan, - lt_stat_type_t type, uint64_t value) -{ - lt_sobj_id_t id; - lt_sobj_t *sobj; - int cause_id; - lt_stat_collection_t *stat_t = NULL; - - stat_t = get_stat_c(pid, tid); - if (stat_t == NULL) { - return; - } - - id.sobj_type = stype; - id.sobj_addr = wchan; - sobj = lookup_sobj(&id); - if (sobj == NULL) { - return; - } - - cause_id = sobj->cause_id; - - update_stat_entry(stat_t, cause_id, type, value, - sobj->string, GROUP_SOBJ); -}
--- a/usr/src/cmd/latencytop/common/table.c Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,560 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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) 2008-2009, Intel Corporation. - * All Rights Reserved. - */ - -#include <stdlib.h> -#include <string.h> -#include <memory.h> -#include <stdio.h> -#include <ctype.h> - -#include "latencytop.h" - -/* - * Structure that holds detail of a cause. - */ -typedef struct { - int cause_id; - int flags; - char *name; -} lt_cause_t; - -/* - * Structure that represents a matched cause. - */ -typedef struct { - int priority; - int cause_id; -} lt_match_t; - -/* All lt_cause_t that are created. */ -static GPtrArray *causes_array = NULL; -static int causes_array_len = 0; -/* - * This hash table maps a symbol to a cause entry. - * key type is "char *" and value type is "lt_match_t *". - */ -static GHashTable *symbol_lookup_table = NULL; -/* - * This hash table maps a cause name to an cause id. - * Note only cause names that are found in D script is put in this table. - * key type is "char *" and value type is "int" (which is cause_id). - */ -static GHashTable *named_causes = NULL; - -/* - * Help function to free one lt_cause_t structure. - */ -/* ARGSUSED */ -static void -free_cause(lt_cause_t *cause, void *user) -{ - g_assert(cause != NULL && cause->name != NULL); - - free(cause->name); - free(cause); -} - -/* - * Add a cause. - * Note this function takes ownership of char *name. - */ -static lt_cause_t * -new_cause(char *name, int flags) -{ - lt_cause_t *entry; - - g_assert(name != NULL); - - entry = (lt_cause_t *)lt_malloc(sizeof (lt_cause_t)); - entry->flags = flags; - entry->name = name; - entry->cause_id = causes_array_len; - - g_ptr_array_add(causes_array, entry); - ++causes_array_len; - - return (entry); -} - -/* - * Set a cause to "disabled" state. - */ -static void -disable_cause(char *cause_str, GHashTable *cause_table) -{ - lt_cause_t *cause; - - cause = (lt_cause_t *)g_hash_table_lookup(cause_table, cause_str); - if (cause != NULL) { - cause->flags |= CAUSE_FLAG_DISABLED; - } -} - -/* - * Helper functions that reads a line from a char * array. - */ -static int -read_line_from_mem(const char *mem, int mem_len, char *line, int line_len, - int *index) -{ - g_assert(mem != NULL && line != NULL && index != NULL); - - if (line_len <= 0 || mem_len <= 0) { - return (0); - } - if (*index >= mem_len) { - return (0); - } - - while (line_len > 1 && *index < mem_len) { - *line = mem[(*index)++]; - --line_len; - ++line; - if (*(line-1) == '\r' || *(line-1) == '\n') { - break; - } - } - *line = 0; - - return (1); -} - -/* - * The main loop that parses the translation rules one line at a time, - * and construct latencytop lookup data structure from it. - */ -static int -parse_config(const char *work, int work_len) -{ - char line[256]; - int len; - char *begin, *end, *tmp; - int priority = 0; - char *match; - char *match_dup; - char *cause_str; - lt_cause_t *cause; - lt_match_t *match_entry; - int current = 0; - GHashTable *cause_lookup; - GSequence *cmd_disable; - - cause_lookup = g_hash_table_new(g_str_hash, g_str_equal); - lt_check_null(cause_lookup); - - cmd_disable = g_sequence_new((GDestroyNotify)free); - lt_check_null(cmd_disable); - - while (read_line_from_mem(work, work_len, line, sizeof (line), - ¤t)) { - len = strlen(line); - if (line[len-1] != '\n' && line[len-1] != '\r' && - current < work_len) { - lt_display_error("Configuration line too long.\n"); - goto err; - } - - begin = line; - while (isspace(*begin)) { - ++begin; - } - if (*begin == '\0') { - /* empty line, ignore */ - continue; - } - - /* Delete trailing spaces. */ - end = begin + strlen(begin) - 1; - while (isspace(*end)) { - --end; - } - end[1] = 0; - - if (*begin == '#') { - continue; - } else if (*begin == ';') { - char old_chr = 0; - /* special command */ - /* ; disable_cause FSFlush Daemon */ - /* ^ */ - ++begin; - - while (isspace(*begin)) { - ++begin; - } - /* ; disable_cause FSFlush Daemon */ - /* ^ */ - if (*begin == '\0') { - continue; - } - - for (tmp = begin; - *tmp != '\0' && !isspace(*tmp); - ++tmp) { - } - old_chr = *tmp; - *tmp = 0; - - if (strcmp("disable_cause", begin) == 0) { - if (old_chr == '\0') { - /* Must have an argument */ - lt_display_error( - "Invalid command format: %s\n", - begin); - goto err; - } - - begin = tmp+1; - while (isspace(*begin)) { - ++begin; - } - - g_sequence_append(cmd_disable, - lt_strdup(begin)); - } else { - *tmp = old_chr; - lt_display_error( - "Unknown command: %s\n", begin); - goto err; - } - continue; - } - - g_assert(*begin != '#' && *begin != ';'); - - /* 10 genunix`indir Syscall indir */ - /* ^ */ - priority = strtol(begin, &tmp, 10); - if (tmp == begin || priority == 0) { - lt_display_error( - "Invalid configuration line: %s\n", line); - goto err; - } - begin = tmp; - - /* 10 genunix`indir Syscall indir */ - /* ^ */ - while (isspace(*begin)) { - ++begin; - } - if (*begin == 0) { - lt_display_error( - "Invalid configuration line: %s\n", line); - goto err; - } - - /* 10 genunix`indir Syscall indir */ - /* -----^ */ - for (tmp = begin; - *tmp != '\0' && !isspace(*tmp); - ++tmp) { - } - if (*tmp == '\0') { - lt_display_error( - "Invalid configuration line: %s\n", line); - goto err; - } - *tmp = 0; - match = begin; - - /* Check if we have mapped this function before. */ - match_entry = (lt_match_t *) - g_hash_table_lookup(symbol_lookup_table, match); - if (match_entry != NULL && - HIGHER_PRIORITY(match_entry->priority, priority)) { - /* We already have a higher entry. Ignore this. */ - continue; - } - - begin = tmp+1; - - /* 10 genunix`indir Syscall indir */ - /* -------------------------------------^ */ - while (isspace(*begin)) { - ++begin; - } - if (*begin == 0) { - lt_display_error( - "Invalid configuration line: %s\n", line); - goto err; - } - cause_str = begin; - - /* Check if we have mapped this cause before. */ - cause = (lt_cause_t *) - g_hash_table_lookup(cause_lookup, cause_str); - if (cause == NULL) { - char *cause_dup = lt_strdup(cause_str); - cause = new_cause(cause_dup, 0); - g_hash_table_insert(cause_lookup, cause_dup, cause); - } - - match_entry = (lt_match_t *)lt_malloc(sizeof (lt_match_t)); - g_assert(NULL != match_entry); - match_entry->priority = priority; - match_entry->cause_id = cause->cause_id; - match_dup = lt_strdup(match); - - g_hash_table_insert(symbol_lookup_table, match_dup, - match_entry); - } - - g_sequence_foreach(cmd_disable, (GFunc)disable_cause, cause_lookup); - g_sequence_free(cmd_disable); - g_hash_table_destroy(cause_lookup); - - return (0); - -err: - g_sequence_free(cmd_disable); - g_hash_table_destroy(cause_lookup); - - return (-1); -} - -/* - * Init function, called when latencytop starts. - * It loads the translation rules from a file. - * A configuration file defines some causes and symbols matching these causes. - */ -int -lt_table_init(void) -{ - char *config_loaded = NULL; - int config_loaded_len = 0; - const char *work = NULL; - int work_len = 0; - lt_cause_t *cause; - -#ifdef EMBED_CONFIGS - work = (char *)latencytop_trans; - work_len = latencytop_trans_len; -#endif - - if (g_config.config_name != NULL) { - FILE *fp; - - fp = fopen(g_config.config_name, "r"); - if (NULL == fp) { - lt_display_error( - "Unable to open configuration file.\n"); - return (-1); - } - - (void) fseek(fp, 0, SEEK_END); - config_loaded_len = (int)ftell(fp); - config_loaded = (char *)lt_malloc(config_loaded_len); - (void) fseek(fp, 0, SEEK_SET); - - if (fread(config_loaded, config_loaded_len, 1, fp) == 0) { - lt_display_error( - "Unable to read configuration file.\n"); - (void) fclose(fp); - free(config_loaded); - return (-1); - } - - (void) fclose(fp); - (void) printf("Loaded configuration from %s\n", - g_config.config_name); - - work = config_loaded; - work_len = config_loaded_len; - } - - g_assert(work != NULL && work_len != 0); - - lt_table_deinit(); - causes_array = g_ptr_array_new(); - lt_check_null(causes_array); - - /* 0 is not used, to keep a place for bugs etc. */ - cause = new_cause(lt_strdup("Nothing"), CAUSE_FLAG_DISABLED); - g_assert(cause->cause_id == INVALID_CAUSE); - - symbol_lookup_table = g_hash_table_new_full( - g_str_hash, g_str_equal, - (GDestroyNotify)free, (GDestroyNotify)free); - lt_check_null(symbol_lookup_table); - - if (parse_config(work, work_len) != 0) { - return (-1); - } - - if (config_loaded != NULL) { - free(config_loaded); - } - - return (0); -} - -/* - * Some causes, such as "lock spinning", does not have stack trace. - * Instead, their names are explicitly specified in DTrace script. - * This function will resolve such causes, and dynamically add them - * to the global tables when first met (lazy initialization). - * auto_create: set to TRUE will create the entry if it is not found. - * Returns cause_id of the cause. - */ -int -lt_table_lookup_named_cause(char *name, int auto_create) -{ - int cause_id = INVALID_CAUSE; - - if (named_causes == NULL) { - named_causes = g_hash_table_new_full( - g_str_hash, g_str_equal, (GDestroyNotify)free, NULL); - lt_check_null(named_causes); - } else { - cause_id = LT_POINTER_TO_INT(g_hash_table_lookup( - named_causes, name)); - } - - if (cause_id == INVALID_CAUSE && auto_create) { - int flags = CAUSE_FLAG_SPECIAL; - lt_cause_t *cause; - - if (name[0] == '#') { - flags |= CAUSE_FLAG_HIDE_IN_SUMMARY; - } - - cause = new_cause(lt_strdup(name), flags); - if (cause == NULL) { - return (INVALID_CAUSE); - } - cause_id = cause->cause_id; - - g_hash_table_insert(named_causes, lt_strdup(name), - LT_INT_TO_POINTER(cause_id)); - } - - return (cause_id); -} - -/* - * Try to map a symbol on stack to a known cause. - * module_func has the format "module_name`function_name". - * cause_id and priority will be set if a cause is found. - * Returns 1 if found, 0 if not found. - */ -int -lt_table_lookup_cause(const char *module_func, int *cause_id, int *priority) -{ - lt_match_t *match; - - g_assert(module_func != NULL && cause_id != NULL && priority != NULL); - - if (symbol_lookup_table == NULL) { - return (0); - } - - match = (lt_match_t *) - g_hash_table_lookup(symbol_lookup_table, module_func); - if (match == NULL) { - char *func = strchr(module_func, '`'); - - if (func != NULL) { - match = (lt_match_t *) - g_hash_table_lookup(symbol_lookup_table, func); - } - } - - if (match == NULL) { - return (0); - } else { - *cause_id = match->cause_id; - *priority = match->priority; - return (1); - } -} - -/* - * Get the display name of a cause. Cause_id must be valid, - * which is usually return from lt_table_lookup_cause() or - * lt_table_lookup_named_cause(). - */ -const char * -lt_table_get_cause_name(int cause_id) -{ - lt_cause_t *cause; - - if (cause_id < 0 || cause_id >= causes_array_len) { - return (NULL); - } - - cause = (lt_cause_t *)g_ptr_array_index(causes_array, cause_id); - if (cause == NULL) { - return (NULL); - } else { - return (cause->name); - } -} - -/* - * Check a cause's flag, e.g. if it has CAUSE_FLAG_DISABLED. - * Use CAUSE_ALL_FLAGS to get all flags at once. - */ -int -lt_table_get_cause_flag(int cause_id, int flag) -{ - lt_cause_t *cause; - - if (cause_id < 0 || cause_id >= causes_array_len) { - return (0); - } - cause = (lt_cause_t *)g_ptr_array_index(causes_array, cause_id); - - if (cause == NULL) { - return (0); - } else { - return (cause->flags & flag); - } -} - -/* - * Clean up function. - * Free the resource used for symbol table. E.g. symbols, causes. - */ -void -lt_table_deinit(void) -{ - if (symbol_lookup_table != NULL) { - g_hash_table_destroy(symbol_lookup_table); - symbol_lookup_table = NULL; - } - - if (named_causes != NULL) { - g_hash_table_destroy(named_causes); - named_causes = NULL; - } - - if (causes_array != NULL) { - g_ptr_array_foreach(causes_array, (GFunc)free_cause, NULL); - g_ptr_array_free(causes_array, TRUE); - causes_array = NULL; - } - - causes_array_len = 0; -}
--- a/usr/src/cmd/latencytop/common/util.c Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,323 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (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) 2008-2009, Intel Corporation. - * All Rights Reserved. - */ - -#include <unistd.h> -#include <libintl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <procfs.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include "latencytop.h" - -/* pipe that breaks the event loop (and exit early) */ -static int signal_pipe[2]; - -/* - * Get current system time in milliseconds (1e-3). - */ -uint64_t -lt_millisecond(void) -{ - struct timeval p; - (void) gettimeofday(&p, NULL); - return ((uint64_t)p.tv_sec * 1000 + p.tv_usec / 1000); -} - -/* - * Wrapper of gettext(). - */ -const char * -lt_text(const char *text) -{ - if (text == NULL) { - return (""); - } - - return (gettext(text)); -} - -/* - * Checks if OOM happens by comparing pointers with NULL in various places. - */ -void -lt_check_null(void *p) -{ - if (p == NULL) { - (void) printf("Out of memory!\n"); - g_assert(0); - exit(2); - } -} - -/* - * Safe malloc. - */ -void * -lt_malloc(size_t size) -{ - void *ret = malloc(size); - - lt_check_null(ret); - - return (ret); -} - -/* - * Safe alloc with memory cleared. - * Named it "zalloc" because its signature is different from - * calloc() in stdlib. - */ -void * -lt_zalloc(size_t size) -{ - void *ret = lt_malloc(size); - (void) memset(ret, 0, size); - return (ret); -} - -/* - * Safe strdup. - */ -char * -lt_strdup(const char *str) -{ - char *ret = strdup(str); - - lt_check_null(ret); - - return (ret); -} - -/* - * Get string for current time, e.g. YYYY-MM-DD - */ -void -lt_time_str(char *buffer, int len) -{ - struct tm tms; - time_t t; - int i; - - (void) time(&t); - (void) gmtime_r(&t, &tms); - (void) asctime_r(&tms, buffer, len); - - for (i = strlen(buffer)-1; i > 0; --i) { - if (isspace(buffer[i])) { - buffer[i] = 0; - } else { - break; - } - } -} - -/* - * Retrieves process exeutable name etc. from /proc. - */ -char * -lt_get_proc_field(pid_t pid, lt_field_t field) -{ - char name[PATH_MAX]; - int fd; - int ret; - psinfo_t psinfo; - - (void) snprintf(name, PATH_MAX, "/proc/%d/psinfo", (int)pid); - fd = open(name, O_RDONLY); - if (fd == -1) { - return (NULL); - } - - ret = read(fd, (char *)&psinfo, sizeof (psinfo_t)); - (void) close(fd); - if (ret < 0) { - return (NULL); - } - - switch (field) { - case LT_FIELD_FNAME: - return (lt_strdup(psinfo.pr_fname)); - case LT_FIELD_PSARGS: - return (lt_strdup(psinfo.pr_psargs)); - } - return (NULL); -} - -/* - * Help function to update the data structure. - */ -void -lt_update_stat_value(lt_stat_data_t *entry, - lt_stat_type_t type, uint64_t value) -{ - switch (type) { - case LT_STAT_COUNT: - entry->count += value; - break; - case LT_STAT_SUM: - entry->total += value; - break; - case LT_STAT_MAX: - if (value > entry->max) { - entry->max = value; - } - break; - default: - break; - } -} - -/* - * Help function to sort by total. - */ -int -lt_sort_by_total_desc(lt_stat_entry_t *a, lt_stat_entry_t *b) -{ - g_assert(a != NULL && b != NULL); - /* - * ->data.total is int64, so we can't simply return - * b->data.total - a->data.total - */ - if (b->data.total > a->data.total) { - return (1); - } else if (b->data.total < a->data.total) { - return (-1); - } else { - return (0); - } -} - -/* - * Help function to sort by max. - */ -int -lt_sort_by_max_desc(lt_stat_entry_t *a, lt_stat_entry_t *b) -{ - g_assert(a != NULL && b != NULL); - - if (b->data.max > a->data.max) { - return (1); - } else if (b->data.max < a->data.max) { - return (-1); - } else { - return (0); - } -} - -/* - * Help function to sort by count. - */ -int -lt_sort_by_count_desc(lt_stat_entry_t *a, lt_stat_entry_t *b) -{ - g_assert(a != NULL && b != NULL); - - if (b->data.count > a->data.count) { - return (1); - } else if (b->data.count < a->data.count) { - return (-1); - } else { - return (0); - } -} - -/* - * Help function to sort by average. - */ -int -lt_sort_by_avg_desc(lt_stat_entry_t *a, lt_stat_entry_t *b) -{ - double avg_a, avg_b; - - g_assert(a != NULL && b != NULL); - - avg_a = (double)a->data.total / a->data.count; - avg_b = (double)b->data.total / b->data.count; - - if (avg_b > avg_a) { - return (1); - } else if (avg_b < avg_a) { - return (-1); - } else { - return (0); - } -} - -/* - * Create pipe for signal handler and wakeup. - */ -void -lt_gpipe_init(void) -{ - (void) pipe(signal_pipe); -} - -/* - * Release pipe used in signal handler. - */ -void -lt_gpipe_deinit(void) -{ - (void) close(signal_pipe[0]); - (void) close(signal_pipe[1]); -} - -/* - * Break from main loop early. - */ -void -lt_gpipe_break(const char *ch) -{ - (void) write(signal_pipe[1], ch, 1); -} - -/* - * Returns fd# used to detect "break main loop". - */ -int -lt_gpipe_readfd(void) -{ - return (signal_pipe[0]); -} - -/* - * Check if a file exists. - */ -int -lt_file_exist(const char *name) -{ - struct stat64 st; - - if (stat64(name, &st) == 0) { - return (1); - } else { - return (0); - } -}
--- a/usr/src/cmd/latencytop/i386/Makefile Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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) 2008-2009, Intel Corporation. -# All Rights Reserved. -# - -include ../Makefile.com - -install: all $(ROOTPROG32)
--- a/usr/src/cmd/latencytop/sparcv9/Makefile Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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) 2008-2009, Intel Corporation. -# All Rights Reserved. -# -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# - -include ../Makefile.com -include ../../Makefile.cmd.64 - -install: all $(ROOTPROG64)
--- a/usr/src/pkgdefs/Makefile Sat Jul 18 02:19:44 2009 -0700 +++ b/usr/src/pkgdefs/Makefile Sat Jul 18 04:34:57 2009 -0700 @@ -316,7 +316,6 @@ SUNWixgbe \ SUNWkrbr \ SUNWkrbu \ - SUNWlatencytop \ SUNWldskint \ SUNWlibsasl \ SUNWllc \
--- a/usr/src/pkgdefs/SUNWlatencytop/Makefile Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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) 2008-2009, Intel Corporation. -# All Rights Reserved. -# - -include ../Makefile.com - -.KEEP_STATE: - -all: $(FILES) depend -install: all pkg - -include ../Makefile.targ
--- a/usr/src/pkgdefs/SUNWlatencytop/depend Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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) 2008-2009, Intel Corporation. -# All Rights Reserved. -# - -P SUNWcsu Core Solaris, (Usr) -P SUNWcslr Core Solaris Libraries (Root) -P SUNWdtrc DTrace Clients -P SUNWdtrp DTrace Providers -P SUNWGlib GLIB - Library of useful routines for C programming
--- a/usr/src/pkgdefs/SUNWlatencytop/pkginfo.tmpl Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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) 2008-2009, Intel Corporation. -# All Rights Reserved. -# - -# -# This required package information file describes characteristics of the -# package, such as package abbreviation, full package name, package version, -# and package architecture. -# -PKG="SUNWlatencytop" -NAME="LatencyTOP tool" -ARCH="ISA" -VERSION="ONVERS,REV=0.0.0" -CATEGORY="system" -SUNW_PRODNAME="SunOS" -SUNW_PRODVERS="RELEASE/VERSION" -DESC="LatencyTOP tool" -BASEDIR=/ -SUNW_PKGVERS="1.0" -SUNW_PKGTYPE="usr" -VENDOR="Sun Microsystems, Inc." -HOTLINE="Please contact your local service provider" -EMAIL="" -MAXINST="1000" -CLASSES="none" -SUNW_PKG_ALLZONES="true" -SUNW_PKG_HOLLOW="false" -SUNW_PKG_THISZONE="false"
--- a/usr/src/pkgdefs/SUNWlatencytop/prototype_com Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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) 2008-2009, Intel Corporation. -# All Rights Reserved. -# - -# This required package information file contains a list of package contents. -# The 'pkgmk' command uses this file to identify the contents of a package -# and their location on the development machine when building the package. -# Can be created via a text editor or through use of the 'pkgproto' command. - -#!search <pathname pathname ...> # where to find pkg objects -#!include <filename> # include another 'prototype' file -#!default <mode> <owner> <group> # default used if not specified on entry -#!<param>=<value> # puts parameter in pkg environment - -# packaging files -i pkginfo -i copyright -i depend -# -# source locations relative to the prototype file -# -# SUNWlatencytop -# -d none usr 0755 root sys -d none usr/bin 0755 root bin -l none usr/bin/latencytop=../../usr/lib/isaexec
--- a/usr/src/pkgdefs/SUNWlatencytop/prototype_i386 Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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) 2008-2009, Intel Corporation. -# All Rights Reserved. -# - -# This required package information file contains a list of package contents. -# The 'pkgmk' command uses this file to identify the contents of a package -# and their location on the development machine when building the package. -# Can be created via a text editor or through use of the 'pkgproto' command. - -#!search <pathname pathname ...> # where to find pkg objects -#!include <filename> # include another 'prototype' file -#!default <mode> <owner> <group> # default used if not specified on entry -#!<param>=<value> # puts parameter in pkg environment - -# -# Include ISA independent files (prototype_com) -# -!include prototype_com -# -# -# -# List files which are I386 specific here -# -# source locations relative to the prototype file -# -# -# SUNWlatencytop -# -d none usr/bin/i86 755 root bin -f none usr/bin/i86/latencytop 555 root bin -d none usr/bin/amd64 755 root bin -f none usr/bin/amd64/latencytop 555 root bin
--- a/usr/src/pkgdefs/SUNWlatencytop/prototype_sparc Sat Jul 18 02:19:44 2009 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -# -# CDDL HEADER START -# -# The contents of this file are subject to the terms of the -# Common Development and Distribution License (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) 2008-2009, Intel Corporation. -# All Rights Reserved. -# - -# This required package information file contains a list of package contents. -# The 'pkgmk' command uses this file to identify the contents of a package -# and their location on the development machine when building the package. -# Can be created via a text editor or through use of the 'pkgproto' command. - -#!search <pathname pathname ...> # where to find pkg objects -#!include <filename> # include another 'prototype' file -#!default <mode> <owner> <group> # default used if not specified on entry -#!<param>=<value> # puts parameter in pkg environment - -# -# Include ISA independent files (prototype_com) -# -!include prototype_com -# -# -# -# List files which are SPARC specific here -# -# source locations relative to the prototype file -# -# -# SUNWlatencytop -# -d none usr/bin/sparcv9 755 root bin -f none usr/bin/sparcv9/latencytop 555 root bin