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