xref: /illumos-gate/usr/src/cmd/latencytop/display.c (revision 486c6fda)
1*486c6fdaSRichard Lowe /*
2*486c6fdaSRichard Lowe  * CDDL HEADER START
3*486c6fdaSRichard Lowe  *
4*486c6fdaSRichard Lowe  * The contents of this file are subject to the terms of the
5*486c6fdaSRichard Lowe  * Common Development and Distribution License (the "License").
6*486c6fdaSRichard Lowe  * You may not use this file except in compliance with the License.
7*486c6fdaSRichard Lowe  *
8*486c6fdaSRichard Lowe  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*486c6fdaSRichard Lowe  * or http://www.opensolaris.org/os/licensing.
10*486c6fdaSRichard Lowe  * See the License for the specific language governing permissions
11*486c6fdaSRichard Lowe  * and limitations under the License.
12*486c6fdaSRichard Lowe  *
13*486c6fdaSRichard Lowe  * When distributing Covered Code, include this CDDL HEADER in each
14*486c6fdaSRichard Lowe  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*486c6fdaSRichard Lowe  * If applicable, add the following below this CDDL HEADER, with the
16*486c6fdaSRichard Lowe  * fields enclosed by brackets "[]" replaced with your own identifying
17*486c6fdaSRichard Lowe  * information: Portions Copyright [yyyy] [name of copyright owner]
18*486c6fdaSRichard Lowe  *
19*486c6fdaSRichard Lowe  * CDDL HEADER END
20*486c6fdaSRichard Lowe  */
21*486c6fdaSRichard Lowe /*
22*486c6fdaSRichard Lowe  * Copyright (c) 2008-2009, Intel Corporation.
23*486c6fdaSRichard Lowe  * All Rights Reserved.
24*486c6fdaSRichard Lowe  */
25*486c6fdaSRichard Lowe 
26*486c6fdaSRichard Lowe #include <stdio.h>
27*486c6fdaSRichard Lowe #include <stdlib.h>
28*486c6fdaSRichard Lowe #include <unistd.h>
29*486c6fdaSRichard Lowe #include <string.h>
30*486c6fdaSRichard Lowe #include <sys/types.h>
31*486c6fdaSRichard Lowe #include <sys/time.h>
32*486c6fdaSRichard Lowe #include <dirent.h>
33*486c6fdaSRichard Lowe #include <curses.h>
34*486c6fdaSRichard Lowe #include <time.h>
35*486c6fdaSRichard Lowe #include <wchar.h>
36*486c6fdaSRichard Lowe #include <ctype.h>
37*486c6fdaSRichard Lowe #include <stdarg.h>
38*486c6fdaSRichard Lowe #include <signal.h>
39*486c6fdaSRichard Lowe 
40*486c6fdaSRichard Lowe #include "latencytop.h"
41*486c6fdaSRichard Lowe 
42*486c6fdaSRichard Lowe #define	LT_WINDOW_X			80
43*486c6fdaSRichard Lowe #define	LT_WINDOW_Y			24
44*486c6fdaSRichard Lowe 
45*486c6fdaSRichard Lowe #define	LT_COLOR_DEFAULT		1
46*486c6fdaSRichard Lowe #define	LT_COLOR_HEADER			2
47*486c6fdaSRichard Lowe 
48*486c6fdaSRichard Lowe /* Windows created by libcurses */
49*486c6fdaSRichard Lowe static WINDOW	*titlebar = NULL;
50*486c6fdaSRichard Lowe static WINDOW	*captionbar = NULL;
51*486c6fdaSRichard Lowe static WINDOW	*sysglobal_window = NULL;
52*486c6fdaSRichard Lowe static WINDOW	*taskbar = NULL;
53*486c6fdaSRichard Lowe static WINDOW	*process_window = NULL;
54*486c6fdaSRichard Lowe static WINDOW	*hintbar = NULL;
55*486c6fdaSRichard Lowe /* Screen dimension */
56*486c6fdaSRichard Lowe static int	screen_width = 1, screen_height = 1;
57*486c6fdaSRichard Lowe /* Is display initialized, i.e. are window pointers set up. */
58*486c6fdaSRichard Lowe static int	display_initialized = FALSE;
59*486c6fdaSRichard Lowe /* Is initscr() called */
60*486c6fdaSRichard Lowe static int	curses_inited = FALSE;
61*486c6fdaSRichard Lowe 
62*486c6fdaSRichard Lowe /* To handle user key presses */
63*486c6fdaSRichard Lowe static pid_t selected_pid = INVALID_PID;
64*486c6fdaSRichard Lowe static id_t selected_tid = INVALID_TID;
65*486c6fdaSRichard Lowe static lt_sort_t sort_type = LT_SORT_TOTAL;
66*486c6fdaSRichard Lowe static int thread_mode = FALSE;
67*486c6fdaSRichard Lowe /* Type of list being displayed */
68*486c6fdaSRichard Lowe static int current_list_type = LT_LIST_CAUSE;
69*486c6fdaSRichard Lowe static int show_help = FALSE;
70*486c6fdaSRichard Lowe 
71*486c6fdaSRichard Lowe /* Help functions that append/prepend a blank to the given string */
72*486c6fdaSRichard Lowe #define	fill_space_right(a, b, c)	fill_space((a), (b), (c), TRUE)
73*486c6fdaSRichard Lowe #define	fill_space_left(a, b, c)	fill_space((a), (b), (c), FALSE)
74*486c6fdaSRichard Lowe 
75*486c6fdaSRichard Lowe static void
fill_space(char * buffer,int len,int buffer_limit,int is_right)76*486c6fdaSRichard Lowe fill_space(char *buffer, int len, int buffer_limit, int is_right)
77*486c6fdaSRichard Lowe {
78*486c6fdaSRichard Lowe 	int i = 0;
79*486c6fdaSRichard Lowe 	int tofill;
80*486c6fdaSRichard Lowe 
81*486c6fdaSRichard Lowe 	if (len >= buffer_limit) {
82*486c6fdaSRichard Lowe 		len = buffer_limit - 1;
83*486c6fdaSRichard Lowe 	}
84*486c6fdaSRichard Lowe 
85*486c6fdaSRichard Lowe 	i = strlen(buffer);
86*486c6fdaSRichard Lowe 
87*486c6fdaSRichard Lowe 	if (i >= len) {
88*486c6fdaSRichard Lowe 		return;
89*486c6fdaSRichard Lowe 	}
90*486c6fdaSRichard Lowe 
91*486c6fdaSRichard Lowe 	tofill = len - i;
92*486c6fdaSRichard Lowe 
93*486c6fdaSRichard Lowe 	if (is_right) {
94*486c6fdaSRichard Lowe 		(void) memset(&buffer[i], ' ', tofill);
95*486c6fdaSRichard Lowe 		buffer[len] = '\0';
96*486c6fdaSRichard Lowe 	} else {
97*486c6fdaSRichard Lowe 		(void) memmove(&buffer[tofill], buffer, i+1);
98*486c6fdaSRichard Lowe 		(void) memset(buffer, ' ', tofill);
99*486c6fdaSRichard Lowe 	}
100*486c6fdaSRichard Lowe }
101*486c6fdaSRichard Lowe 
102*486c6fdaSRichard Lowe /* Convert the nanosecond value to a human readable string */
103*486c6fdaSRichard Lowe static const char *
get_time_string(double nanoseconds,char * buffer,int len,int fill_width)104*486c6fdaSRichard Lowe get_time_string(double nanoseconds, char *buffer, int len, int fill_width)
105*486c6fdaSRichard Lowe {
106*486c6fdaSRichard Lowe 	const double ONE_USEC = 1000.0;
107*486c6fdaSRichard Lowe 	const double ONE_MSEC = 1000000.0;
108*486c6fdaSRichard Lowe 	const double ONE_SEC  = 1000000000.0;
109*486c6fdaSRichard Lowe 
110*486c6fdaSRichard Lowe 	if (nanoseconds < (ONE_USEC - .5)) {
111*486c6fdaSRichard Lowe 		(void) snprintf(buffer, len, "%3.1f nsec", nanoseconds);
112*486c6fdaSRichard Lowe 	} else if (nanoseconds < (ONE_MSEC - .5 * ONE_USEC)) {
113*486c6fdaSRichard Lowe 		(void) snprintf(buffer, len,
114*486c6fdaSRichard Lowe 		    "%3.1f usec", nanoseconds / ONE_USEC);
115*486c6fdaSRichard Lowe 	} else if (nanoseconds < (ONE_SEC - .5 * ONE_MSEC)) {
116*486c6fdaSRichard Lowe 		(void) snprintf(buffer, len,
117*486c6fdaSRichard Lowe 		    "%3.1f msec", nanoseconds / ONE_MSEC);
118*486c6fdaSRichard Lowe 	} else if (nanoseconds < 999.5 * ONE_SEC) {
119*486c6fdaSRichard Lowe 		(void) snprintf(buffer, len,
120*486c6fdaSRichard Lowe 		    "%3.1f  sec", nanoseconds / ONE_SEC);
121*486c6fdaSRichard Lowe 	} else {
122*486c6fdaSRichard Lowe 		(void) snprintf(buffer, len,
123*486c6fdaSRichard Lowe 		    "%.0e sec", nanoseconds / ONE_SEC);
124*486c6fdaSRichard Lowe 	}
125*486c6fdaSRichard Lowe 
126*486c6fdaSRichard Lowe 	fill_space_left(buffer, fill_width, len);
127*486c6fdaSRichard Lowe 	return (buffer);
128*486c6fdaSRichard Lowe }
129*486c6fdaSRichard Lowe 
130*486c6fdaSRichard Lowe /* Used in print_statistics below */
131*486c6fdaSRichard Lowe #define	WIDTH_REASON_STRING	36
132*486c6fdaSRichard Lowe #define	WIDTH_COUNT		12
133*486c6fdaSRichard Lowe #define	WIDTH_AVG		12
134*486c6fdaSRichard Lowe #define	WIDTH_MAX		12
135*486c6fdaSRichard Lowe #define	WIDTH_PCT		8
136*486c6fdaSRichard Lowe #define	BEGIN_COUNT		WIDTH_REASON_STRING
137*486c6fdaSRichard Lowe #define	BEGIN_AVG		(BEGIN_COUNT + WIDTH_COUNT)
138*486c6fdaSRichard Lowe #define	BEGIN_MAX		(BEGIN_AVG + WIDTH_AVG)
139*486c6fdaSRichard Lowe #define	BEGIN_PCT		(BEGIN_MAX + WIDTH_MAX)
140*486c6fdaSRichard Lowe 
141*486c6fdaSRichard Lowe /*
142*486c6fdaSRichard Lowe  * Print statistics in global/process pane. Called by print_sysglobal
143*486c6fdaSRichard Lowe  * print_process.
144*486c6fdaSRichard Lowe  *
145*486c6fdaSRichard Lowe  * Parameters:
146*486c6fdaSRichard Lowe  *		window - the global or process statistics window.
147*486c6fdaSRichard Lowe  *		begin_line - where to start printing.
148*486c6fdaSRichard Lowe  *		count - how many lines should be printed.
149*486c6fdaSRichard Lowe  *		list - a stat_list.
150*486c6fdaSRichard Lowe  */
151*486c6fdaSRichard Lowe static void
print_statistics(WINDOW * window,int begin_line,int nlines,void * list)152*486c6fdaSRichard Lowe print_statistics(WINDOW * window, int begin_line, int nlines, void *list)
153*486c6fdaSRichard Lowe {
154*486c6fdaSRichard Lowe 	uint64_t total;
155*486c6fdaSRichard Lowe 	int i = 0;
156*486c6fdaSRichard Lowe 
157*486c6fdaSRichard Lowe 	if (!display_initialized) {
158*486c6fdaSRichard Lowe 		return;
159*486c6fdaSRichard Lowe 	}
160*486c6fdaSRichard Lowe 
161*486c6fdaSRichard Lowe 	total = lt_stat_list_get_gtotal(list);
162*486c6fdaSRichard Lowe 
163*486c6fdaSRichard Lowe 	if (total == 0) {
164*486c6fdaSRichard Lowe 		return;
165*486c6fdaSRichard Lowe 	}
166*486c6fdaSRichard Lowe 
167*486c6fdaSRichard Lowe 	while (i < nlines && lt_stat_list_has_item(list, i)) {
168*486c6fdaSRichard Lowe 
169*486c6fdaSRichard Lowe 		char tmp[WIDTH_REASON_STRING];
170*486c6fdaSRichard Lowe 		const char *reason = lt_stat_list_get_reason(list, i);
171*486c6fdaSRichard Lowe 		uint64_t count = lt_stat_list_get_count(list, i);
172*486c6fdaSRichard Lowe 
173*486c6fdaSRichard Lowe 		if (count == 0) {
174*486c6fdaSRichard Lowe 			continue;
175*486c6fdaSRichard Lowe 		}
176*486c6fdaSRichard Lowe 
177*486c6fdaSRichard Lowe 		(void) snprintf(tmp, sizeof (tmp), "%s", reason);
178*486c6fdaSRichard Lowe 		(void) mvwprintw(window, i + begin_line, 0, "%s", tmp);
179*486c6fdaSRichard Lowe 
180*486c6fdaSRichard Lowe 		(void) snprintf(tmp, sizeof (tmp), "%llu", count);
181*486c6fdaSRichard Lowe 		fill_space_left(tmp, WIDTH_COUNT, sizeof (tmp));
182*486c6fdaSRichard Lowe 		(void) mvwprintw(window, i + begin_line, BEGIN_COUNT,
183*486c6fdaSRichard Lowe 		    "%s", tmp);
184*486c6fdaSRichard Lowe 
185*486c6fdaSRichard Lowe 		(void) mvwprintw(window, i + begin_line, BEGIN_AVG,
186*486c6fdaSRichard Lowe 		    "%s", get_time_string(
187*486c6fdaSRichard Lowe 		    (double)lt_stat_list_get_sum(list, i) / count,
188*486c6fdaSRichard Lowe 		    tmp, sizeof (tmp), WIDTH_AVG));
189*486c6fdaSRichard Lowe 
190*486c6fdaSRichard Lowe 		(void) mvwprintw(window, i + begin_line, BEGIN_MAX,
191*486c6fdaSRichard Lowe 		    "%s", get_time_string(
192*486c6fdaSRichard Lowe 		    (double)lt_stat_list_get_max(list, i),
193*486c6fdaSRichard Lowe 		    tmp, sizeof (tmp), WIDTH_MAX));
194*486c6fdaSRichard Lowe 
195*486c6fdaSRichard Lowe 		if (LT_LIST_SPECIALS != current_list_type) {
196*486c6fdaSRichard Lowe 			(void) snprintf(tmp, sizeof (tmp), "%.1f %%",
197*486c6fdaSRichard Lowe 			    (double)lt_stat_list_get_sum(list, i)
198*486c6fdaSRichard Lowe 			    / total * 100.0);
199*486c6fdaSRichard Lowe 		} else {
200*486c6fdaSRichard Lowe 			(void) snprintf(tmp, sizeof (tmp), "--- ");
201*486c6fdaSRichard Lowe 		}
202*486c6fdaSRichard Lowe 
203*486c6fdaSRichard Lowe 		fill_space_left(tmp, WIDTH_PCT, sizeof (tmp));
204*486c6fdaSRichard Lowe 
205*486c6fdaSRichard Lowe 		(void) mvwprintw(window, i + begin_line, BEGIN_PCT,
206*486c6fdaSRichard Lowe 		    "%s", tmp);
207*486c6fdaSRichard Lowe 		i++;
208*486c6fdaSRichard Lowe 	}
209*486c6fdaSRichard Lowe }
210*486c6fdaSRichard Lowe 
211*486c6fdaSRichard Lowe /*
212*486c6fdaSRichard Lowe  * Print statistics in global pane.
213*486c6fdaSRichard Lowe  */
214*486c6fdaSRichard Lowe static void
print_sysglobal(void)215*486c6fdaSRichard Lowe print_sysglobal(void)
216*486c6fdaSRichard Lowe {
217*486c6fdaSRichard Lowe 	void *list;
218*486c6fdaSRichard Lowe 	char header[256];
219*486c6fdaSRichard Lowe 
220*486c6fdaSRichard Lowe 	if (!display_initialized) {
221*486c6fdaSRichard Lowe 		return;
222*486c6fdaSRichard Lowe 	}
223*486c6fdaSRichard Lowe 
224*486c6fdaSRichard Lowe 	(void) werase(sysglobal_window);
225*486c6fdaSRichard Lowe 
226*486c6fdaSRichard Lowe 	(void) wattron(sysglobal_window, A_REVERSE);
227*486c6fdaSRichard Lowe 	(void) snprintf(header, sizeof (header),
228*486c6fdaSRichard Lowe 	    "%s", "System wide latencies");
229*486c6fdaSRichard Lowe 	fill_space_right(header, screen_width, sizeof (header));
230*486c6fdaSRichard Lowe 	(void) mvwprintw(sysglobal_window, 0, 0, "%s", header);
231*486c6fdaSRichard Lowe 	(void) wattroff(sysglobal_window, A_REVERSE);
232*486c6fdaSRichard Lowe 
233*486c6fdaSRichard Lowe 	list = lt_stat_list_create(current_list_type,
234*486c6fdaSRichard Lowe 	    LT_LEVEL_GLOBAL, 0, 0, 10, sort_type);
235*486c6fdaSRichard Lowe 	print_statistics(sysglobal_window, 1, 10, list);
236*486c6fdaSRichard Lowe 	lt_stat_list_free(list);
237*486c6fdaSRichard Lowe 
238*486c6fdaSRichard Lowe 	(void) wrefresh(sysglobal_window);
239*486c6fdaSRichard Lowe }
240*486c6fdaSRichard Lowe 
241*486c6fdaSRichard Lowe /*
242*486c6fdaSRichard Lowe  * Prints current operation mode. Mode is combination of:
243*486c6fdaSRichard Lowe  *
244*486c6fdaSRichard Lowe  *	"Process or Thread", and "1 or 2 or 3".
245*486c6fdaSRichard Lowe  */
246*486c6fdaSRichard Lowe static void
print_current_mode()247*486c6fdaSRichard Lowe print_current_mode()
248*486c6fdaSRichard Lowe {
249*486c6fdaSRichard Lowe 	char type;
250*486c6fdaSRichard Lowe 
251*486c6fdaSRichard Lowe 	if (!display_initialized) {
252*486c6fdaSRichard Lowe 		return;
253*486c6fdaSRichard Lowe 	}
254*486c6fdaSRichard Lowe 
255*486c6fdaSRichard Lowe 	switch (current_list_type) {
256*486c6fdaSRichard Lowe 	case LT_LIST_CAUSE:
257*486c6fdaSRichard Lowe 		type = '1';
258*486c6fdaSRichard Lowe 		break;
259*486c6fdaSRichard Lowe 	case LT_LIST_SPECIALS:
260*486c6fdaSRichard Lowe 		type = '2';
261*486c6fdaSRichard Lowe 		break;
262*486c6fdaSRichard Lowe 	case LT_LIST_SOBJ:
263*486c6fdaSRichard Lowe 		type = '3';
264*486c6fdaSRichard Lowe 		break;
265*486c6fdaSRichard Lowe 	default:
266*486c6fdaSRichard Lowe 		type = '?';
267*486c6fdaSRichard Lowe 		break;
268*486c6fdaSRichard Lowe 	}
269*486c6fdaSRichard Lowe 
270*486c6fdaSRichard Lowe 	(void) mvwprintw(process_window, 0, screen_width - 8, "View: %c%c",
271*486c6fdaSRichard Lowe 	    type, thread_mode ? 'T' : 'P');
272*486c6fdaSRichard Lowe }
273*486c6fdaSRichard Lowe 
274*486c6fdaSRichard Lowe /*
275*486c6fdaSRichard Lowe  * Print process window bar when the list is empty.
276*486c6fdaSRichard Lowe  */
277*486c6fdaSRichard Lowe static void
print_empty_process_bar()278*486c6fdaSRichard Lowe print_empty_process_bar()
279*486c6fdaSRichard Lowe {
280*486c6fdaSRichard Lowe 	char header[256];
281*486c6fdaSRichard Lowe 
282*486c6fdaSRichard Lowe 	if (!display_initialized) {
283*486c6fdaSRichard Lowe 		return;
284*486c6fdaSRichard Lowe 	}
285*486c6fdaSRichard Lowe 
286*486c6fdaSRichard Lowe 	(void) werase(process_window);
287*486c6fdaSRichard Lowe 	(void) wattron(process_window, A_REVERSE);
288*486c6fdaSRichard Lowe 	(void) snprintf(header, sizeof (header),
289*486c6fdaSRichard Lowe 	    "No process/thread data is available");
290*486c6fdaSRichard Lowe 	fill_space_right(header, screen_width, sizeof (header));
291*486c6fdaSRichard Lowe 	(void) mvwprintw(process_window, 0, 0, "%s", header);
292*486c6fdaSRichard Lowe 
293*486c6fdaSRichard Lowe 	print_current_mode();
294*486c6fdaSRichard Lowe 	(void) wattroff(process_window, A_REVERSE);
295*486c6fdaSRichard Lowe 
296*486c6fdaSRichard Lowe 	(void) wrefresh(process_window);
297*486c6fdaSRichard Lowe }
298*486c6fdaSRichard Lowe 
299*486c6fdaSRichard Lowe /*
300*486c6fdaSRichard Lowe  * Print per-process statistics in process pane.
301*486c6fdaSRichard Lowe  * This is called when mode of operation is process.
302*486c6fdaSRichard Lowe  */
303*486c6fdaSRichard Lowe static void
print_process(unsigned int pid)304*486c6fdaSRichard Lowe print_process(unsigned int pid)
305*486c6fdaSRichard Lowe {
306*486c6fdaSRichard Lowe 	void *list;
307*486c6fdaSRichard Lowe 	char header[256];
308*486c6fdaSRichard Lowe 	char tmp[30];
309*486c6fdaSRichard Lowe 
310*486c6fdaSRichard Lowe 	if (!display_initialized) {
311*486c6fdaSRichard Lowe 		return;
312*486c6fdaSRichard Lowe 	}
313*486c6fdaSRichard Lowe 
314*486c6fdaSRichard Lowe 	list = lt_stat_list_create(current_list_type, LT_LEVEL_PROCESS,
315*486c6fdaSRichard Lowe 	    pid, 0, 8, sort_type);
316*486c6fdaSRichard Lowe 
317*486c6fdaSRichard Lowe 	(void) werase(process_window);
318*486c6fdaSRichard Lowe 	(void) wattron(process_window, A_REVERSE);
319*486c6fdaSRichard Lowe 	(void) snprintf(header, sizeof (header), "Process %s (%i), %d threads",
320*486c6fdaSRichard Lowe 	    lt_stat_proc_get_name(pid), pid, lt_stat_proc_get_nthreads(pid));
321*486c6fdaSRichard Lowe 	fill_space_right(header, screen_width, sizeof (header));
322*486c6fdaSRichard Lowe 	(void) mvwprintw(process_window, 0, 0, "%s", header);
323*486c6fdaSRichard Lowe 
324*486c6fdaSRichard Lowe 	if (current_list_type != LT_LIST_SPECIALS) {
325*486c6fdaSRichard Lowe 		(void) mvwprintw(process_window, 0, 48, "Total: %s",
326*486c6fdaSRichard Lowe 		    get_time_string((double)lt_stat_list_get_gtotal(list),
327*486c6fdaSRichard Lowe 		    tmp, sizeof (tmp), 12));
328*486c6fdaSRichard Lowe 	}
329*486c6fdaSRichard Lowe 
330*486c6fdaSRichard Lowe 	print_current_mode();
331*486c6fdaSRichard Lowe 	(void) wattroff(process_window, A_REVERSE);
332*486c6fdaSRichard Lowe 	print_statistics(process_window, 1, 8, list);
333*486c6fdaSRichard Lowe 	lt_stat_list_free(list);
334*486c6fdaSRichard Lowe 
335*486c6fdaSRichard Lowe 	(void) wrefresh(process_window);
336*486c6fdaSRichard Lowe }
337*486c6fdaSRichard Lowe 
338*486c6fdaSRichard Lowe /*
339*486c6fdaSRichard Lowe  * Display the list of processes that are tracked, in task bar.
340*486c6fdaSRichard Lowe  * This one is called when mode of operation is process.
341*486c6fdaSRichard Lowe  */
342*486c6fdaSRichard Lowe static void
print_taskbar_process(pid_t * pidlist,int pidlist_len,int pidlist_index)343*486c6fdaSRichard Lowe print_taskbar_process(pid_t *pidlist, int pidlist_len, int pidlist_index)
344*486c6fdaSRichard Lowe {
345*486c6fdaSRichard Lowe 	const int ITEM_WIDTH = 8;
346*486c6fdaSRichard Lowe 
347*486c6fdaSRichard Lowe 	int number_item;
348*486c6fdaSRichard Lowe 	int i;
349*486c6fdaSRichard Lowe 	int xpos = 0;
350*486c6fdaSRichard Lowe 
351*486c6fdaSRichard Lowe 	if (!display_initialized) {
352*486c6fdaSRichard Lowe 		return;
353*486c6fdaSRichard Lowe 	}
354*486c6fdaSRichard Lowe 
355*486c6fdaSRichard Lowe 	number_item = (screen_width / ITEM_WIDTH) - 1;
356*486c6fdaSRichard Lowe 	i = pidlist_index - (pidlist_index % number_item);
357*486c6fdaSRichard Lowe 
358*486c6fdaSRichard Lowe 	(void) werase(taskbar);
359*486c6fdaSRichard Lowe 
360*486c6fdaSRichard Lowe 	if (i != 0) {
361*486c6fdaSRichard Lowe 		(void) mvwprintw(taskbar, 0, xpos, "<-");
362*486c6fdaSRichard Lowe 	}
363*486c6fdaSRichard Lowe 
364*486c6fdaSRichard Lowe 	xpos = ITEM_WIDTH / 2;
365*486c6fdaSRichard Lowe 
366*486c6fdaSRichard Lowe 	while (xpos + ITEM_WIDTH <= screen_width && i < pidlist_len) {
367*486c6fdaSRichard Lowe 		char str[ITEM_WIDTH+1];
368*486c6fdaSRichard Lowe 		int slen;
369*486c6fdaSRichard Lowe 		const char *pname = lt_stat_proc_get_name(pidlist[i]);
370*486c6fdaSRichard Lowe 
371*486c6fdaSRichard Lowe 		if (pname && pname[0]) {
372*486c6fdaSRichard Lowe 			(void) snprintf(str, sizeof (str) - 1, "%s", pname);
373*486c6fdaSRichard Lowe 		} else {
374*486c6fdaSRichard Lowe 			(void) snprintf(str, sizeof (str) - 1,
375*486c6fdaSRichard Lowe 			    "<%d>", pidlist[i]);
376*486c6fdaSRichard Lowe 		}
377*486c6fdaSRichard Lowe 
378*486c6fdaSRichard Lowe 		slen = strlen(str);
379*486c6fdaSRichard Lowe 
380*486c6fdaSRichard Lowe 		if (slen < ITEM_WIDTH) {
381*486c6fdaSRichard Lowe 			(void) memset(&str[slen], ' ', ITEM_WIDTH - slen);
382*486c6fdaSRichard Lowe 		}
383*486c6fdaSRichard Lowe 
384*486c6fdaSRichard Lowe 		str[sizeof (str) - 1] = '\0';
385*486c6fdaSRichard Lowe 
386*486c6fdaSRichard Lowe 		if (i == pidlist_index) {
387*486c6fdaSRichard Lowe 			(void) wattron(taskbar, A_REVERSE);
388*486c6fdaSRichard Lowe 		}
389*486c6fdaSRichard Lowe 
390*486c6fdaSRichard Lowe 		(void) mvwprintw(taskbar, 0, xpos, "%s", str);
391*486c6fdaSRichard Lowe 
392*486c6fdaSRichard Lowe 		if (i == pidlist_index) {
393*486c6fdaSRichard Lowe 			(void) wattroff(taskbar, A_REVERSE);
394*486c6fdaSRichard Lowe 		}
395*486c6fdaSRichard Lowe 
396*486c6fdaSRichard Lowe 		xpos += ITEM_WIDTH;
397*486c6fdaSRichard Lowe 		i++;
398*486c6fdaSRichard Lowe 	}
399*486c6fdaSRichard Lowe 
400*486c6fdaSRichard Lowe 	if (i != pidlist_len) {
401*486c6fdaSRichard Lowe 		(void) mvwprintw(taskbar, 0, screen_width - 2, "->");
402*486c6fdaSRichard Lowe 	}
403*486c6fdaSRichard Lowe 
404*486c6fdaSRichard Lowe 	(void) wrefresh(taskbar);
405*486c6fdaSRichard Lowe }
406*486c6fdaSRichard Lowe 
407*486c6fdaSRichard Lowe /*
408*486c6fdaSRichard Lowe  * Display the list of processes that are tracked, in task bar.
409*486c6fdaSRichard Lowe  * This one is called when mode of operation is thread.
410*486c6fdaSRichard Lowe  */
411*486c6fdaSRichard Lowe static void
print_taskbar_thread(pid_t * pidlist,id_t * tidlist,int list_len,int list_index)412*486c6fdaSRichard Lowe print_taskbar_thread(pid_t *pidlist, id_t *tidlist, int list_len,
413*486c6fdaSRichard Lowe     int list_index)
414*486c6fdaSRichard Lowe {
415*486c6fdaSRichard Lowe 	const int ITEM_WIDTH = 12;
416*486c6fdaSRichard Lowe 
417*486c6fdaSRichard Lowe 	int number_item;
418*486c6fdaSRichard Lowe 	int i;
419*486c6fdaSRichard Lowe 	int xpos = 0;
420*486c6fdaSRichard Lowe 	const char *pname = NULL;
421*486c6fdaSRichard Lowe 	pid_t last_pid = INVALID_PID;
422*486c6fdaSRichard Lowe 
423*486c6fdaSRichard Lowe 
424*486c6fdaSRichard Lowe 	if (!display_initialized) {
425*486c6fdaSRichard Lowe 		return;
426*486c6fdaSRichard Lowe 	}
427*486c6fdaSRichard Lowe 
428*486c6fdaSRichard Lowe 	number_item = (screen_width - 8) / ITEM_WIDTH;
429*486c6fdaSRichard Lowe 	i = list_index - (list_index % number_item);
430*486c6fdaSRichard Lowe 
431*486c6fdaSRichard Lowe 	(void) werase(taskbar);
432*486c6fdaSRichard Lowe 
433*486c6fdaSRichard Lowe 	if (i != 0) {
434*486c6fdaSRichard Lowe 		(void) mvwprintw(taskbar, 0, xpos, "<-");
435*486c6fdaSRichard Lowe 	}
436*486c6fdaSRichard Lowe 
437*486c6fdaSRichard Lowe 	xpos = 4;
438*486c6fdaSRichard Lowe 
439*486c6fdaSRichard Lowe 	while (xpos + ITEM_WIDTH <= screen_width && i < list_len) {
440*486c6fdaSRichard Lowe 		char str[ITEM_WIDTH+1];
441*486c6fdaSRichard Lowe 		int slen, tlen;
442*486c6fdaSRichard Lowe 
443*486c6fdaSRichard Lowe 		if (pidlist[i] != last_pid) {
444*486c6fdaSRichard Lowe 			pname = lt_stat_proc_get_name(pidlist[i]);
445*486c6fdaSRichard Lowe 			last_pid = pidlist[i];
446*486c6fdaSRichard Lowe 		}
447*486c6fdaSRichard Lowe 
448*486c6fdaSRichard Lowe 		/*
449*486c6fdaSRichard Lowe 		 * Calculate length of thread's ID; use shorter process name
450*486c6fdaSRichard Lowe 		 * in order to save space on the screen.
451*486c6fdaSRichard Lowe 		 */
452*486c6fdaSRichard Lowe 		tlen = snprintf(NULL, 0, "_%d", tidlist[i]);
453*486c6fdaSRichard Lowe 
454*486c6fdaSRichard Lowe 		if (pname && pname[0]) {
455*486c6fdaSRichard Lowe 			(void) snprintf(str, sizeof (str) - tlen - 1,
456*486c6fdaSRichard Lowe 			    "%s", pname);
457*486c6fdaSRichard Lowe 		} else {
458*486c6fdaSRichard Lowe 			(void) snprintf(str, sizeof (str) - tlen - 1,
459*486c6fdaSRichard Lowe 			    "<%d>", pidlist[i]);
460*486c6fdaSRichard Lowe 		}
461*486c6fdaSRichard Lowe 
462*486c6fdaSRichard Lowe 		slen = strlen(str);
463*486c6fdaSRichard Lowe 
464*486c6fdaSRichard Lowe 		(void) snprintf(&str[slen], sizeof (str) - slen,
465*486c6fdaSRichard Lowe 		    "_%d", tidlist[i]);
466*486c6fdaSRichard Lowe 
467*486c6fdaSRichard Lowe 		slen += tlen;
468*486c6fdaSRichard Lowe 
469*486c6fdaSRichard Lowe 		if (slen < ITEM_WIDTH) {
470*486c6fdaSRichard Lowe 			(void) memset(&str[slen], ' ', ITEM_WIDTH - slen);
471*486c6fdaSRichard Lowe 		}
472*486c6fdaSRichard Lowe 
473*486c6fdaSRichard Lowe 		str[sizeof (str) - 1] = '\0';
474*486c6fdaSRichard Lowe 
475*486c6fdaSRichard Lowe 		if (i == list_index) {
476*486c6fdaSRichard Lowe 			(void) wattron(taskbar, A_REVERSE);
477*486c6fdaSRichard Lowe 		}
478*486c6fdaSRichard Lowe 
479*486c6fdaSRichard Lowe 		(void) mvwprintw(taskbar, 0, xpos, "%s", str);
480*486c6fdaSRichard Lowe 
481*486c6fdaSRichard Lowe 		if (i == list_index) {
482*486c6fdaSRichard Lowe 			(void) wattroff(taskbar, A_REVERSE);
483*486c6fdaSRichard Lowe 		}
484*486c6fdaSRichard Lowe 
485*486c6fdaSRichard Lowe 		xpos += ITEM_WIDTH;
486*486c6fdaSRichard Lowe 		i++;
487*486c6fdaSRichard Lowe 	}
488*486c6fdaSRichard Lowe 
489*486c6fdaSRichard Lowe 	if (i != list_len) {
490*486c6fdaSRichard Lowe 		(void) mvwprintw(taskbar, 0, screen_width - 2, "->");
491*486c6fdaSRichard Lowe 	}
492*486c6fdaSRichard Lowe 
493*486c6fdaSRichard Lowe 	(void) wrefresh(taskbar);
494*486c6fdaSRichard Lowe }
495*486c6fdaSRichard Lowe 
496*486c6fdaSRichard Lowe /*
497*486c6fdaSRichard Lowe  * Print per-thread statistics in process pane.
498*486c6fdaSRichard Lowe  * This is called when mode of operation is thread.
499*486c6fdaSRichard Lowe  */
500*486c6fdaSRichard Lowe static void
print_thread(pid_t pid,id_t tid)501*486c6fdaSRichard Lowe print_thread(pid_t pid, id_t tid)
502*486c6fdaSRichard Lowe {
503*486c6fdaSRichard Lowe 	void *list;
504*486c6fdaSRichard Lowe 	char header[256];
505*486c6fdaSRichard Lowe 	char tmp[30];
506*486c6fdaSRichard Lowe 
507*486c6fdaSRichard Lowe 	if (!display_initialized) {
508*486c6fdaSRichard Lowe 		return;
509*486c6fdaSRichard Lowe 	}
510*486c6fdaSRichard Lowe 
511*486c6fdaSRichard Lowe 	list = lt_stat_list_create(current_list_type, LT_LEVEL_THREAD,
512*486c6fdaSRichard Lowe 	    pid, tid, 8, sort_type);
513*486c6fdaSRichard Lowe 
514*486c6fdaSRichard Lowe 	(void) werase(process_window);
515*486c6fdaSRichard Lowe 	(void) wattron(process_window, A_REVERSE);
516*486c6fdaSRichard Lowe 	(void) snprintf(header, sizeof (header),
517*486c6fdaSRichard Lowe 	    "Process %s (%i), LWP %d",
518*486c6fdaSRichard Lowe 	    lt_stat_proc_get_name(pid), pid, tid);
519*486c6fdaSRichard Lowe 	fill_space_right(header, screen_width, sizeof (header));
520*486c6fdaSRichard Lowe 	(void) mvwprintw(process_window, 0, 0, "%s", header);
521*486c6fdaSRichard Lowe 
522*486c6fdaSRichard Lowe 	if (current_list_type != LT_LIST_SPECIALS) {
523*486c6fdaSRichard Lowe 		(void) mvwprintw(process_window, 0, 48, "Total: %s",
524*486c6fdaSRichard Lowe 		    get_time_string(
525*486c6fdaSRichard Lowe 		    (double)lt_stat_list_get_gtotal(list),
526*486c6fdaSRichard Lowe 		    tmp, sizeof (tmp), 12));
527*486c6fdaSRichard Lowe 	}
528*486c6fdaSRichard Lowe 
529*486c6fdaSRichard Lowe 	print_current_mode();
530*486c6fdaSRichard Lowe 	(void) wattroff(process_window, A_REVERSE);
531*486c6fdaSRichard Lowe 	print_statistics(process_window, 1, 8, list);
532*486c6fdaSRichard Lowe 	lt_stat_list_free(list);
533*486c6fdaSRichard Lowe 	(void) wrefresh(process_window);
534*486c6fdaSRichard Lowe }
535*486c6fdaSRichard Lowe 
536*486c6fdaSRichard Lowe /*
537*486c6fdaSRichard Lowe  * Update hint string at the bottom line. The message to print is stored in
538*486c6fdaSRichard Lowe  * hint. If hint is NULL, the function will display its own message.
539*486c6fdaSRichard Lowe  */
540*486c6fdaSRichard Lowe static void
print_hint(const char * hint)541*486c6fdaSRichard Lowe print_hint(const char *hint)
542*486c6fdaSRichard Lowe {
543*486c6fdaSRichard Lowe 	const char *HINTS[] =    {
544*486c6fdaSRichard Lowe 		"Press '<' or '>' to switch between processes.",
545*486c6fdaSRichard Lowe 		"Press 'q' to exit.",
546*486c6fdaSRichard Lowe 		"Press 'r' to refresh immediately.",
547*486c6fdaSRichard Lowe 		"Press 't' to toggle Process/Thread display mode.",
548*486c6fdaSRichard Lowe 		"Press 'h' for help.",
549*486c6fdaSRichard Lowe 		"Use 'c', 'a', 'm', 'p' to change sort criteria.",
550*486c6fdaSRichard Lowe 		"Use '1', '2', '3' to switch between windows."
551*486c6fdaSRichard Lowe 	};
552*486c6fdaSRichard Lowe 	const uint64_t update_interval = 5000; /* 5 seconds */
553*486c6fdaSRichard Lowe 
554*486c6fdaSRichard Lowe 	static int index = 0;
555*486c6fdaSRichard Lowe 	static uint64_t next_hint = 0;
556*486c6fdaSRichard Lowe 	uint64_t now = lt_millisecond();
557*486c6fdaSRichard Lowe 
558*486c6fdaSRichard Lowe 	if (!display_initialized) {
559*486c6fdaSRichard Lowe 		return;
560*486c6fdaSRichard Lowe 	}
561*486c6fdaSRichard Lowe 
562*486c6fdaSRichard Lowe 	if (hint == NULL) {
563*486c6fdaSRichard Lowe 		if (now < next_hint) {
564*486c6fdaSRichard Lowe 			return;
565*486c6fdaSRichard Lowe 		}
566*486c6fdaSRichard Lowe 
567*486c6fdaSRichard Lowe 		hint = HINTS[index];
568*486c6fdaSRichard Lowe 		index = (index + 1) % (sizeof (HINTS) / sizeof (HINTS[0]));
569*486c6fdaSRichard Lowe 		next_hint = now + update_interval;
570*486c6fdaSRichard Lowe 	} else {
571*486c6fdaSRichard Lowe 		/*
572*486c6fdaSRichard Lowe 		 * Important messages are displayed at least every 2 cycles.
573*486c6fdaSRichard Lowe 		 */
574*486c6fdaSRichard Lowe 		next_hint = now + update_interval * 2;
575*486c6fdaSRichard Lowe 	}
576*486c6fdaSRichard Lowe 
577*486c6fdaSRichard Lowe 	(void) werase(hintbar);
578*486c6fdaSRichard Lowe 	(void) mvwprintw(hintbar, 0, (screen_width - strlen(hint)) / 2,
579*486c6fdaSRichard Lowe 	    "%s", hint);
580*486c6fdaSRichard Lowe 	(void) wrefresh(hintbar);
581*486c6fdaSRichard Lowe }
582*486c6fdaSRichard Lowe 
583*486c6fdaSRichard Lowe /*
584*486c6fdaSRichard Lowe  * Create a PID list or a PID/TID list (if operation mode is thread) from
585*486c6fdaSRichard Lowe  * available statistics.
586*486c6fdaSRichard Lowe  */
587*486c6fdaSRichard Lowe static void
get_plist(pid_t ** plist,id_t ** tlist,int * list_len,int * list_index)588*486c6fdaSRichard Lowe get_plist(pid_t **plist, id_t **tlist, int *list_len, int *list_index)
589*486c6fdaSRichard Lowe {
590*486c6fdaSRichard Lowe 	if (!thread_mode) {
591*486c6fdaSRichard Lowe 		/* Per-process mode */
592*486c6fdaSRichard Lowe 		*list_len = lt_stat_proc_list_create(plist, NULL);
593*486c6fdaSRichard Lowe 		/* Search for previously selected PID */
594*486c6fdaSRichard Lowe 		for (*list_index = 0; *list_index < *list_len &&
595*486c6fdaSRichard Lowe 		    (*plist)[*list_index] != selected_pid;
596*486c6fdaSRichard Lowe 		    ++*list_index) {
597*486c6fdaSRichard Lowe 		}
598*486c6fdaSRichard Lowe 
599*486c6fdaSRichard Lowe 		if (*list_index >= *list_len) {
600*486c6fdaSRichard Lowe 			/*
601*486c6fdaSRichard Lowe 			 * The previously selected pid is gone.
602*486c6fdaSRichard Lowe 			 * Select the first one.
603*486c6fdaSRichard Lowe 			 */
604*486c6fdaSRichard Lowe 			*list_index = 0;
605*486c6fdaSRichard Lowe 		}
606*486c6fdaSRichard Lowe 	} else {
607*486c6fdaSRichard Lowe 		/* Per-thread mode */
608*486c6fdaSRichard Lowe 		*list_len = lt_stat_proc_list_create(plist, tlist);
609*486c6fdaSRichard Lowe 
610*486c6fdaSRichard Lowe 		/* Search for previously selected PID & TID */
611*486c6fdaSRichard Lowe 		for (*list_index = 0; *list_index < *list_len;
612*486c6fdaSRichard Lowe 		    ++*list_index) {
613*486c6fdaSRichard Lowe 			if ((*plist)[*list_index] == selected_pid &&
614*486c6fdaSRichard Lowe 			    (*tlist)[*list_index] == selected_tid) {
615*486c6fdaSRichard Lowe 				break;
616*486c6fdaSRichard Lowe 			}
617*486c6fdaSRichard Lowe 		}
618*486c6fdaSRichard Lowe 
619*486c6fdaSRichard Lowe 		if (*list_index >= *list_len) {
620*486c6fdaSRichard Lowe 			/*
621*486c6fdaSRichard Lowe 			 * The previously selected pid/tid is gone.
622*486c6fdaSRichard Lowe 			 * Select the first one.
623*486c6fdaSRichard Lowe 			 */
624*486c6fdaSRichard Lowe 			for (*list_index = 0;
625*486c6fdaSRichard Lowe 			    *list_index < *list_len &&
626*486c6fdaSRichard Lowe 			    (*plist)[*list_index] != selected_pid;
627*486c6fdaSRichard Lowe 			    ++*list_index) {
628*486c6fdaSRichard Lowe 			}
629*486c6fdaSRichard Lowe 		}
630*486c6fdaSRichard Lowe 
631*486c6fdaSRichard Lowe 		if (*list_index >= *list_len) {
632*486c6fdaSRichard Lowe 			/*
633*486c6fdaSRichard Lowe 			 * The previously selected pid is gone.
634*486c6fdaSRichard Lowe 			 * Select the first one
635*486c6fdaSRichard Lowe 			 */
636*486c6fdaSRichard Lowe 			*list_index = 0;
637*486c6fdaSRichard Lowe 		}
638*486c6fdaSRichard Lowe 	}
639*486c6fdaSRichard Lowe }
640*486c6fdaSRichard Lowe 
641*486c6fdaSRichard Lowe /* Print help message when user presses 'h' hot key */
642*486c6fdaSRichard Lowe static void
print_help(void)643*486c6fdaSRichard Lowe print_help(void)
644*486c6fdaSRichard Lowe {
645*486c6fdaSRichard Lowe 	const char *HELP[] =    {
646*486c6fdaSRichard Lowe 		TITLE,
647*486c6fdaSRichard Lowe 		COPYRIGHT,
648*486c6fdaSRichard Lowe 		"",
649*486c6fdaSRichard Lowe 		"These single-character commands are available:",
650*486c6fdaSRichard Lowe 		"<       - Move to previous process/thread.",
651*486c6fdaSRichard Lowe 		">       - Move to next process/thread.",
652*486c6fdaSRichard Lowe 		"q       - Exit.",
653*486c6fdaSRichard Lowe 		"r       - Refresh.",
654*486c6fdaSRichard Lowe 		"t       - Toggle process/thread mode.",
655*486c6fdaSRichard Lowe 		"c       - Sort by count.",
656*486c6fdaSRichard Lowe 		"a       - Sort by average.",
657*486c6fdaSRichard Lowe 		"m       - Sort by maximum.",
658*486c6fdaSRichard Lowe 		"p       - Sort by percent.",
659*486c6fdaSRichard Lowe 		"1       - Show list by causes.",
660*486c6fdaSRichard Lowe 		"2       - Show list of special entries.",
661*486c6fdaSRichard Lowe 		"3       - Show list by synchronization objects.",
662*486c6fdaSRichard Lowe 		"h       - Show this help.",
663*486c6fdaSRichard Lowe 		"",
664*486c6fdaSRichard Lowe 		"Press any key to continue..."
665*486c6fdaSRichard Lowe 	};
666*486c6fdaSRichard Lowe 	int i;
667*486c6fdaSRichard Lowe 
668*486c6fdaSRichard Lowe 	if (!display_initialized) {
669*486c6fdaSRichard Lowe 		return;
670*486c6fdaSRichard Lowe 	}
671*486c6fdaSRichard Lowe 
672*486c6fdaSRichard Lowe 	for (i = 0; i < sizeof (HELP) / sizeof (HELP[0]); ++i) {
673*486c6fdaSRichard Lowe 		(void) mvwprintw(stdscr, i, 0, "%s", HELP[i]);
674*486c6fdaSRichard Lowe 	}
675*486c6fdaSRichard Lowe 
676*486c6fdaSRichard Lowe 	(void) refresh();
677*486c6fdaSRichard Lowe }
678*486c6fdaSRichard Lowe 
679*486c6fdaSRichard Lowe /*
680*486c6fdaSRichard Lowe  * Print title on screen
681*486c6fdaSRichard Lowe  */
682*486c6fdaSRichard Lowe static void
print_title(void)683*486c6fdaSRichard Lowe print_title(void)
684*486c6fdaSRichard Lowe {
685*486c6fdaSRichard Lowe 	if (!display_initialized) {
686*486c6fdaSRichard Lowe 		return;
687*486c6fdaSRichard Lowe 	}
688*486c6fdaSRichard Lowe 
689*486c6fdaSRichard Lowe 	(void) wattrset(titlebar, COLOR_PAIR(LT_COLOR_HEADER));
690*486c6fdaSRichard Lowe 	(void) wbkgd(titlebar, COLOR_PAIR(LT_COLOR_HEADER));
691*486c6fdaSRichard Lowe 	(void) werase(titlebar);
692*486c6fdaSRichard Lowe 
693*486c6fdaSRichard Lowe 	(void) mvwprintw(titlebar, 0, (screen_width - strlen(TITLE)) / 2,
694*486c6fdaSRichard Lowe 	    "%s", TITLE);
695*486c6fdaSRichard Lowe 	(void) wrefresh(titlebar);
696*486c6fdaSRichard Lowe 
697*486c6fdaSRichard Lowe 	(void) werase(captionbar);
698*486c6fdaSRichard Lowe 	(void) mvwprintw(captionbar, 0, 0, "%s",
699*486c6fdaSRichard Lowe 	    "               Cause                    "
700*486c6fdaSRichard Lowe 	    "Count      Average     Maximum   Percent");
701*486c6fdaSRichard Lowe 	(void) wrefresh(captionbar);
702*486c6fdaSRichard Lowe 
703*486c6fdaSRichard Lowe 	(void) wattrset(hintbar, COLOR_PAIR(LT_COLOR_HEADER));
704*486c6fdaSRichard Lowe 	(void) wbkgd(hintbar, COLOR_PAIR(LT_COLOR_HEADER));
705*486c6fdaSRichard Lowe }
706*486c6fdaSRichard Lowe 
707*486c6fdaSRichard Lowe /*
708*486c6fdaSRichard Lowe  * Handle signal from terminal resize
709*486c6fdaSRichard Lowe  */
710*486c6fdaSRichard Lowe /* ARGSUSED */
711*486c6fdaSRichard Lowe static void
on_resize(int sig)712*486c6fdaSRichard Lowe on_resize(int sig)
713*486c6fdaSRichard Lowe {
714*486c6fdaSRichard Lowe 	lt_gpipe_break("r");
715*486c6fdaSRichard Lowe }
716*486c6fdaSRichard Lowe 
717*486c6fdaSRichard Lowe /*
718*486c6fdaSRichard Lowe  * Initialize display. Display will be cleared when this function returns.
719*486c6fdaSRichard Lowe  */
720*486c6fdaSRichard Lowe void
lt_display_init(void)721*486c6fdaSRichard Lowe lt_display_init(void)
722*486c6fdaSRichard Lowe {
723*486c6fdaSRichard Lowe 	if (display_initialized) {
724*486c6fdaSRichard Lowe 		return;
725*486c6fdaSRichard Lowe 	}
726*486c6fdaSRichard Lowe 
727*486c6fdaSRichard Lowe 	/* Window resize signal */
728*486c6fdaSRichard Lowe 	(void) signal(SIGWINCH, on_resize);
729*486c6fdaSRichard Lowe 
730*486c6fdaSRichard Lowe 	/* Initialize curses library */
731*486c6fdaSRichard Lowe 	(void) initscr();
732*486c6fdaSRichard Lowe 	(void) start_color();
733*486c6fdaSRichard Lowe 	(void) keypad(stdscr, TRUE);
734*486c6fdaSRichard Lowe 	(void) nonl();
735*486c6fdaSRichard Lowe 	(void) cbreak();
736*486c6fdaSRichard Lowe 	(void) noecho();
737*486c6fdaSRichard Lowe 	(void) curs_set(0);
738*486c6fdaSRichard Lowe 
739*486c6fdaSRichard Lowe 	/* Set up color pairs */
740*486c6fdaSRichard Lowe 	(void) init_pair(LT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK);
741*486c6fdaSRichard Lowe 	(void) init_pair(LT_COLOR_HEADER, COLOR_BLACK, COLOR_WHITE);
742*486c6fdaSRichard Lowe 
743*486c6fdaSRichard Lowe 	curses_inited = TRUE;
744*486c6fdaSRichard Lowe 	getmaxyx(stdscr, screen_height, screen_width);
745*486c6fdaSRichard Lowe 
746*486c6fdaSRichard Lowe 	if (screen_width < LT_WINDOW_X || screen_height < LT_WINDOW_Y) {
747*486c6fdaSRichard Lowe 		(void) mvwprintw(stdscr, 0, 0, "Terminal size is too small.");
748*486c6fdaSRichard Lowe 		(void) mvwprintw(stdscr, 1, 0,
749*486c6fdaSRichard Lowe 		    "Please resize it to 80x24 or larger.");
750*486c6fdaSRichard Lowe 		(void) mvwprintw(stdscr, 2, 0, "Press q to quit.");
751*486c6fdaSRichard Lowe 		(void) refresh();
752*486c6fdaSRichard Lowe 		return;
753*486c6fdaSRichard Lowe 	}
754*486c6fdaSRichard Lowe 
755*486c6fdaSRichard Lowe 	/* Set up all window panes */
756*486c6fdaSRichard Lowe 	titlebar = subwin(stdscr, 1, screen_width, 0, 0);
757*486c6fdaSRichard Lowe 	captionbar = subwin(stdscr, 1, screen_width, 1, 0);
758*486c6fdaSRichard Lowe 	sysglobal_window = subwin(stdscr, screen_height / 2 - 1,
759*486c6fdaSRichard Lowe 	    screen_width, 2, 0);
760*486c6fdaSRichard Lowe 	process_window = subwin(stdscr, screen_height / 2 - 3,
761*486c6fdaSRichard Lowe 	    screen_width, screen_height / 2 + 1, 0);
762*486c6fdaSRichard Lowe 	taskbar = subwin(stdscr, 1, screen_width, screen_height - 2, 0);
763*486c6fdaSRichard Lowe 	hintbar = subwin(stdscr, 1, screen_width, screen_height - 1, 0);
764*486c6fdaSRichard Lowe 	(void) werase(stdscr);
765*486c6fdaSRichard Lowe 	(void) refresh();
766*486c6fdaSRichard Lowe 
767*486c6fdaSRichard Lowe 	display_initialized = TRUE;
768*486c6fdaSRichard Lowe 
769*486c6fdaSRichard Lowe 	print_title();
770*486c6fdaSRichard Lowe }
771*486c6fdaSRichard Lowe 
772*486c6fdaSRichard Lowe /*
773*486c6fdaSRichard Lowe  * The event loop for display. It displays data on screen and handles hotkey
774*486c6fdaSRichard Lowe  * presses.
775*486c6fdaSRichard Lowe  *
776*486c6fdaSRichard Lowe  * Parameter :
777*486c6fdaSRichard Lowe  *		duration - returns after 'duration'
778*486c6fdaSRichard Lowe  *
779*486c6fdaSRichard Lowe  * The function also returns if user presses 'q', 'Ctrl+C' or 'r'.
780*486c6fdaSRichard Lowe  *
781*486c6fdaSRichard Lowe  * Return value:
782*486c6fdaSRichard Lowe  *		0 - main() exits
783*486c6fdaSRichard Lowe  *		1 - main() calls it again
784*486c6fdaSRichard Lowe  */
785*486c6fdaSRichard Lowe int
lt_display_loop(int duration)786*486c6fdaSRichard Lowe lt_display_loop(int duration)
787*486c6fdaSRichard Lowe {
788*486c6fdaSRichard Lowe 	uint64_t start;
789*486c6fdaSRichard Lowe 	int remaining;
790*486c6fdaSRichard Lowe 	struct timeval timeout;
791*486c6fdaSRichard Lowe 	fd_set read_fd;
792*486c6fdaSRichard Lowe 	int need_refresh = TRUE;
793*486c6fdaSRichard Lowe 	pid_t *plist = NULL;
794*486c6fdaSRichard Lowe 	id_t *tlist = NULL;
795*486c6fdaSRichard Lowe 	int list_len = 0;
796*486c6fdaSRichard Lowe 	int list_index = 0;
797*486c6fdaSRichard Lowe 	int retval = 1;
798*486c6fdaSRichard Lowe 	int next_snap;
799*486c6fdaSRichard Lowe 	int gpipe;
800*486c6fdaSRichard Lowe 
801*486c6fdaSRichard Lowe 	start = lt_millisecond();
802*486c6fdaSRichard Lowe 	gpipe = lt_gpipe_readfd();
803*486c6fdaSRichard Lowe 
804*486c6fdaSRichard Lowe 	if (!show_help) {
805*486c6fdaSRichard Lowe 		print_hint(NULL);
806*486c6fdaSRichard Lowe 		print_sysglobal();
807*486c6fdaSRichard Lowe 	}
808*486c6fdaSRichard Lowe 
809*486c6fdaSRichard Lowe 	get_plist(&plist, &tlist, &list_len, &list_index);
810*486c6fdaSRichard Lowe 
811*486c6fdaSRichard Lowe 	for (;;) {
812*486c6fdaSRichard Lowe 		if (need_refresh && !show_help) {
813*486c6fdaSRichard Lowe 			if (list_len != 0) {
814*486c6fdaSRichard Lowe 				if (!thread_mode) {
815*486c6fdaSRichard Lowe 					print_taskbar_process(plist, list_len,
816*486c6fdaSRichard Lowe 					    list_index);
817*486c6fdaSRichard Lowe 					print_process(plist[list_index]);
818*486c6fdaSRichard Lowe 				} else {
819*486c6fdaSRichard Lowe 					print_taskbar_thread(plist, tlist,
820*486c6fdaSRichard Lowe 					    list_len, list_index);
821*486c6fdaSRichard Lowe 					print_thread(plist[list_index],
822*486c6fdaSRichard Lowe 					    tlist[list_index]);
823*486c6fdaSRichard Lowe 				}
824*486c6fdaSRichard Lowe 			} else {
825*486c6fdaSRichard Lowe 				print_empty_process_bar();
826*486c6fdaSRichard Lowe 			}
827*486c6fdaSRichard Lowe 		}
828*486c6fdaSRichard Lowe 
829*486c6fdaSRichard Lowe 		need_refresh = TRUE;	/* Usually we need refresh. */
830*486c6fdaSRichard Lowe 		remaining = duration - (int)(lt_millisecond() - start);
831*486c6fdaSRichard Lowe 
832*486c6fdaSRichard Lowe 		if (remaining <= 0) {
833*486c6fdaSRichard Lowe 			break;
834*486c6fdaSRichard Lowe 		}
835*486c6fdaSRichard Lowe 
836*486c6fdaSRichard Lowe 		/* Embedded dtrace snap action here. */
837*486c6fdaSRichard Lowe 		next_snap = lt_dtrace_work(0);
838*486c6fdaSRichard Lowe 
839*486c6fdaSRichard Lowe 		if (next_snap == 0) {
840*486c6fdaSRichard Lowe 			/*
841*486c6fdaSRichard Lowe 			 * Just did a snap, check time for the next one.
842*486c6fdaSRichard Lowe 			 */
843*486c6fdaSRichard Lowe 			next_snap = lt_dtrace_work(0);
844*486c6fdaSRichard Lowe 		}
845*486c6fdaSRichard Lowe 
846*486c6fdaSRichard Lowe 		if (next_snap > 0 && remaining > next_snap) {
847*486c6fdaSRichard Lowe 			remaining = next_snap;
848*486c6fdaSRichard Lowe 		}
849*486c6fdaSRichard Lowe 
850*486c6fdaSRichard Lowe 		timeout.tv_sec = remaining / 1000;
851*486c6fdaSRichard Lowe 		timeout.tv_usec = (remaining % 1000) * 1000;
852*486c6fdaSRichard Lowe 
853*486c6fdaSRichard Lowe 		FD_ZERO(&read_fd);
854*486c6fdaSRichard Lowe 		FD_SET(0, &read_fd);
855*486c6fdaSRichard Lowe 		FD_SET(gpipe, &read_fd);
856*486c6fdaSRichard Lowe 
857*486c6fdaSRichard Lowe 		/* Wait for keyboard input, or signal from gpipe */
858*486c6fdaSRichard Lowe 		if (select(gpipe + 1, &read_fd, NULL, NULL, &timeout) > 0) {
859*486c6fdaSRichard Lowe 			int k = 0;
860*486c6fdaSRichard Lowe 
861*486c6fdaSRichard Lowe 			if (FD_ISSET(gpipe, &read_fd)) {
862*486c6fdaSRichard Lowe 				/* Data from pipe has priority */
863*486c6fdaSRichard Lowe 				char ch;
864*486c6fdaSRichard Lowe 				(void) read(gpipe, &ch, 1);
865*486c6fdaSRichard Lowe 				k = ch; /* Need this for big-endianness */
866*486c6fdaSRichard Lowe 			} else {
867*486c6fdaSRichard Lowe 				k = getch();
868*486c6fdaSRichard Lowe 			}
869*486c6fdaSRichard Lowe 
870*486c6fdaSRichard Lowe 			/*
871*486c6fdaSRichard Lowe 			 * Check if we need to update the hint line whenever we
872*486c6fdaSRichard Lowe 			 * get a chance.
873*486c6fdaSRichard Lowe 			 * NOTE: current implementation depends on
874*486c6fdaSRichard Lowe 			 * g_config.lt_cfg_snap_interval, but it's OK because it
875*486c6fdaSRichard Lowe 			 * doesn't have to be precise.
876*486c6fdaSRichard Lowe 			 */
877*486c6fdaSRichard Lowe 			print_hint(NULL);
878*486c6fdaSRichard Lowe 			/*
879*486c6fdaSRichard Lowe 			 * If help is on display right now, and a key press
880*486c6fdaSRichard Lowe 			 * happens, we need to clear the help and continue.
881*486c6fdaSRichard Lowe 			 */
882*486c6fdaSRichard Lowe 			if (show_help) {
883*486c6fdaSRichard Lowe 				(void) werase(stdscr);
884*486c6fdaSRichard Lowe 				(void) refresh();
885*486c6fdaSRichard Lowe 				print_title();
886*486c6fdaSRichard Lowe 				print_sysglobal();
887*486c6fdaSRichard Lowe 				show_help = FALSE;
888*486c6fdaSRichard Lowe 				/* Drop this key and continue */
889*486c6fdaSRichard Lowe 				continue;
890*486c6fdaSRichard Lowe 			}
891*486c6fdaSRichard Lowe 
892*486c6fdaSRichard Lowe 			switch (k) {
893*486c6fdaSRichard Lowe 			case 'Q':
894*486c6fdaSRichard Lowe 			case 'q':
895*486c6fdaSRichard Lowe 				retval = 0;
896*486c6fdaSRichard Lowe 				goto quit;
897*486c6fdaSRichard Lowe 			case 'R':
898*486c6fdaSRichard Lowe 			case 'r':
899*486c6fdaSRichard Lowe 				lt_display_deinit();
900*486c6fdaSRichard Lowe 				lt_display_init();
901*486c6fdaSRichard Lowe 				goto quit;
902*486c6fdaSRichard Lowe 			case 'H':
903*486c6fdaSRichard Lowe 			case 'h':
904*486c6fdaSRichard Lowe 				show_help = TRUE;
905*486c6fdaSRichard Lowe 				(void) werase(stdscr);
906*486c6fdaSRichard Lowe 				(void) refresh();
907*486c6fdaSRichard Lowe 				print_help();
908*486c6fdaSRichard Lowe 				break;
909*486c6fdaSRichard Lowe 			case ',':
910*486c6fdaSRichard Lowe 			case '<':
911*486c6fdaSRichard Lowe 			case KEY_LEFT:
912*486c6fdaSRichard Lowe 				--list_index;
913*486c6fdaSRichard Lowe 
914*486c6fdaSRichard Lowe 				if (list_index < 0) {
915*486c6fdaSRichard Lowe 					list_index = 0;
916*486c6fdaSRichard Lowe 				}
917*486c6fdaSRichard Lowe 
918*486c6fdaSRichard Lowe 				break;
919*486c6fdaSRichard Lowe 			case '.':
920*486c6fdaSRichard Lowe 			case '>':
921*486c6fdaSRichard Lowe 			case KEY_RIGHT:
922*486c6fdaSRichard Lowe 				++list_index;
923*486c6fdaSRichard Lowe 
924*486c6fdaSRichard Lowe 				if (list_index >= list_len) {
925*486c6fdaSRichard Lowe 					list_index = list_len - 1;
926*486c6fdaSRichard Lowe 				}
927*486c6fdaSRichard Lowe 
928*486c6fdaSRichard Lowe 				break;
929*486c6fdaSRichard Lowe 			case 'a':
930*486c6fdaSRichard Lowe 			case 'A':
931*486c6fdaSRichard Lowe 				sort_type = LT_SORT_AVG;
932*486c6fdaSRichard Lowe 				print_sysglobal();
933*486c6fdaSRichard Lowe 				break;
934*486c6fdaSRichard Lowe 			case 'p':
935*486c6fdaSRichard Lowe 			case 'P':
936*486c6fdaSRichard Lowe 				sort_type = LT_SORT_TOTAL;
937*486c6fdaSRichard Lowe 				print_sysglobal();
938*486c6fdaSRichard Lowe 				break;
939*486c6fdaSRichard Lowe 			case 'm':
940*486c6fdaSRichard Lowe 			case 'M':
941*486c6fdaSRichard Lowe 				sort_type = LT_SORT_MAX;
942*486c6fdaSRichard Lowe 				print_sysglobal();
943*486c6fdaSRichard Lowe 				break;
944*486c6fdaSRichard Lowe 			case 'c':
945*486c6fdaSRichard Lowe 			case 'C':
946*486c6fdaSRichard Lowe 				sort_type = LT_SORT_COUNT;
947*486c6fdaSRichard Lowe 				print_sysglobal();
948*486c6fdaSRichard Lowe 				break;
949*486c6fdaSRichard Lowe 			case 't':
950*486c6fdaSRichard Lowe 			case 'T':
951*486c6fdaSRichard Lowe 				if (plist != NULL) {
952*486c6fdaSRichard Lowe 					selected_pid = plist[list_index];
953*486c6fdaSRichard Lowe 				}
954*486c6fdaSRichard Lowe 
955*486c6fdaSRichard Lowe 				selected_tid = INVALID_TID;
956*486c6fdaSRichard Lowe 				thread_mode = !thread_mode;
957*486c6fdaSRichard Lowe 				get_plist(&plist, &tlist,
958*486c6fdaSRichard Lowe 				    &list_len, &list_index);
959*486c6fdaSRichard Lowe 				break;
960*486c6fdaSRichard Lowe 			case '1':
961*486c6fdaSRichard Lowe 			case '!':
962*486c6fdaSRichard Lowe 				current_list_type = LT_LIST_CAUSE;
963*486c6fdaSRichard Lowe 				print_sysglobal();
964*486c6fdaSRichard Lowe 				break;
965*486c6fdaSRichard Lowe 			case '2':
966*486c6fdaSRichard Lowe 			case '@':
967*486c6fdaSRichard Lowe 				if (g_config.lt_cfg_low_overhead_mode) {
968*486c6fdaSRichard Lowe 					lt_display_error("Switching mode is "
969*486c6fdaSRichard Lowe 					    "not available for '-f low'.");
970*486c6fdaSRichard Lowe 				} else {
971*486c6fdaSRichard Lowe 					current_list_type = LT_LIST_SPECIALS;
972*486c6fdaSRichard Lowe 					print_sysglobal();
973*486c6fdaSRichard Lowe 				}
974*486c6fdaSRichard Lowe 
975*486c6fdaSRichard Lowe 				break;
976*486c6fdaSRichard Lowe 			case '3':
977*486c6fdaSRichard Lowe 			case '#':
978*486c6fdaSRichard Lowe 				if (g_config.lt_cfg_trace_syncobj) {
979*486c6fdaSRichard Lowe 					current_list_type = LT_LIST_SOBJ;
980*486c6fdaSRichard Lowe 					print_sysglobal();
981*486c6fdaSRichard Lowe 				} else if (g_config.lt_cfg_low_overhead_mode) {
982*486c6fdaSRichard Lowe 					lt_display_error("Switching mode is "
983*486c6fdaSRichard Lowe 					    "not available for '-f low'.");
984*486c6fdaSRichard Lowe 				} else {
985*486c6fdaSRichard Lowe 					lt_display_error("Tracing "
986*486c6fdaSRichard Lowe 					    "synchronization objects is "
987*486c6fdaSRichard Lowe 					    "disabled.");
988*486c6fdaSRichard Lowe 				}
989*486c6fdaSRichard Lowe 
990*486c6fdaSRichard Lowe 				break;
991*486c6fdaSRichard Lowe 			default:
992*486c6fdaSRichard Lowe 				/* Wake up for nothing; no refresh is needed */
993*486c6fdaSRichard Lowe 				need_refresh = FALSE;
994*486c6fdaSRichard Lowe 				break;
995*486c6fdaSRichard Lowe 			}
996*486c6fdaSRichard Lowe 		} else {
997*486c6fdaSRichard Lowe 			need_refresh = FALSE;
998*486c6fdaSRichard Lowe 		}
999*486c6fdaSRichard Lowe 	}
1000*486c6fdaSRichard Lowe 
1001*486c6fdaSRichard Lowe quit:
1002*486c6fdaSRichard Lowe 	if (plist != NULL) {
1003*486c6fdaSRichard Lowe 		selected_pid = plist[list_index];
1004*486c6fdaSRichard Lowe 	}
1005*486c6fdaSRichard Lowe 
1006*486c6fdaSRichard Lowe 	if (tlist != NULL) {
1007*486c6fdaSRichard Lowe 		selected_tid = tlist[list_index];
1008*486c6fdaSRichard Lowe 	}
1009*486c6fdaSRichard Lowe 
1010*486c6fdaSRichard Lowe 	lt_stat_proc_list_free(plist, tlist);
1011*486c6fdaSRichard Lowe 
1012*486c6fdaSRichard Lowe 	return (retval);
1013*486c6fdaSRichard Lowe }
1014*486c6fdaSRichard Lowe 
1015*486c6fdaSRichard Lowe /*
1016*486c6fdaSRichard Lowe  * Clean up display.
1017*486c6fdaSRichard Lowe  */
1018*486c6fdaSRichard Lowe void
lt_display_deinit(void)1019*486c6fdaSRichard Lowe lt_display_deinit(void)
1020*486c6fdaSRichard Lowe {
1021*486c6fdaSRichard Lowe 	if (curses_inited) {
1022*486c6fdaSRichard Lowe 		(void) clear();
1023*486c6fdaSRichard Lowe 		(void) refresh();
1024*486c6fdaSRichard Lowe 		(void) endwin();
1025*486c6fdaSRichard Lowe 	}
1026*486c6fdaSRichard Lowe 
1027*486c6fdaSRichard Lowe 	titlebar = NULL;
1028*486c6fdaSRichard Lowe 	captionbar = NULL;
1029*486c6fdaSRichard Lowe 	sysglobal_window = NULL;
1030*486c6fdaSRichard Lowe 	taskbar = NULL;
1031*486c6fdaSRichard Lowe 	process_window = NULL;
1032*486c6fdaSRichard Lowe 	hintbar = NULL;
1033*486c6fdaSRichard Lowe 	screen_width = 1;
1034*486c6fdaSRichard Lowe 	screen_height = 1;
1035*486c6fdaSRichard Lowe 
1036*486c6fdaSRichard Lowe 	display_initialized = FALSE;
1037*486c6fdaSRichard Lowe 	curses_inited = FALSE;
1038*486c6fdaSRichard Lowe }
1039*486c6fdaSRichard Lowe 
1040*486c6fdaSRichard Lowe /*
1041*486c6fdaSRichard Lowe  * Print message when display error happens.
1042*486c6fdaSRichard Lowe  */
1043*486c6fdaSRichard Lowe /* ARGSUSED */
1044*486c6fdaSRichard Lowe void
lt_display_error(const char * fmt,...)1045*486c6fdaSRichard Lowe lt_display_error(const char *fmt, ...)
1046*486c6fdaSRichard Lowe {
1047*486c6fdaSRichard Lowe 	va_list vl;
1048*486c6fdaSRichard Lowe 	char tmp[81];
1049*486c6fdaSRichard Lowe 	int l;
1050*486c6fdaSRichard Lowe 
1051*486c6fdaSRichard Lowe 	va_start(vl, fmt);
1052*486c6fdaSRichard Lowe 	(void) vsnprintf(tmp, sizeof (tmp), fmt, vl);
1053*486c6fdaSRichard Lowe 	va_end(vl);
1054*486c6fdaSRichard Lowe 
1055*486c6fdaSRichard Lowe 	l = strlen(tmp);
1056*486c6fdaSRichard Lowe 
1057*486c6fdaSRichard Lowe 	while (l > 0 && (tmp[l - 1] == '\n' || tmp[l - 1] == '\r')) {
1058*486c6fdaSRichard Lowe 		tmp[l - 1] = '\0';
1059*486c6fdaSRichard Lowe 		--l;
1060*486c6fdaSRichard Lowe 	}
1061*486c6fdaSRichard Lowe 
1062*486c6fdaSRichard Lowe 	if (!display_initialized) {
1063*486c6fdaSRichard Lowe 		(void) fprintf(stderr, "%s\n", tmp);
1064*486c6fdaSRichard Lowe 	} else if (!show_help) {
1065*486c6fdaSRichard Lowe 		print_hint(tmp);
1066*486c6fdaSRichard Lowe 	}
1067*486c6fdaSRichard Lowe 
1068*486c6fdaSRichard Lowe }
1069