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