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/latencytop.c
+++ new/usr/src/cmd/latencytop/latencytop.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 <unistd.h>
27 27 #include <getopt.h>
28 28 #include <stdio.h>
29 29 #include <string.h>
30 30 #include <stdlib.h>
31 31 #include <limits.h>
32 32 #include <libgen.h>
33 33 #include <signal.h>
34 34 #include "latencytop.h"
35 35
36 36 #define CMPOPT(a, b) strncmp((a), (b), sizeof (b))
37 37
38 38 /*
39 39 * This variable is used to check if "dynamic variable drop" in dtrace
40 40 * has happened.
41 41 */
42 42 boolean_t lt_drop_detected = 0;
43 43
44 44 lt_config_t g_config;
45 45
46 46 typedef enum {
47 47 LT_CMDOPT_INTERVAL,
48 48 LT_CMDOPT_LOG_FILE,
49 49 LT_CMDOPT_LOG_LEVEL,
50 50 LT_CMDOPT_LOG_INTERVAL,
51 51 LT_CMDOPT_CONFIG_FILE,
52 52 LT_CMDOPT_F_FILTER,
53 53 LT_CMDOPT_F_SCHED,
54 54 LT_CMDOPT_F_SOBJ,
55 55 LT_CMDOPT_F_LOW,
|
↓ open down ↓ |
55 lines elided |
↑ open up ↑ |
56 56 LT_CMDOPT_SELECT,
57 57 LT_CMDOPT__LAST /* Must be the last one */
58 58 } lt_cmd_option_id_t;
59 59
60 60 /*
61 61 * Check for duplicate command line options.
62 62 * Returns TRUE if duplicate options with different values are found,
63 63 * returns FALSE otherwise.
64 64 */
65 65 static int
66 -check_opt_dup(lt_cmd_option_id_t id, uint64_t value) {
66 +check_opt_dup(lt_cmd_option_id_t id, uint64_t value)
67 +{
67 68
68 69 static int opt_set[(int)LT_CMDOPT__LAST];
69 70 static uint64_t opt_val[(int)LT_CMDOPT__LAST];
70 71
71 72 const char *errmsg[] = {
72 73 "-t is set more than once with different values.",
73 74 "-o is set more than once.",
74 75 "-k is set more than once with different values.",
75 76 "-l is set more than once with different values.",
76 77 "-c is set more than once.",
77 78 "-f [no]filter is set more than once with different values.",
78 79 "-f [no]sched is set more than once with different values.",
79 80 "-f [no]sobj is set more than once with different values.",
80 81 "-f [no]low is set more than once with different values.",
81 82 "-s is set more than once with different values."
82 83 };
83 84
84 85 g_assert(sizeof (errmsg)/sizeof (errmsg[0]) == (int)LT_CMDOPT__LAST);
85 86
86 87 if (!opt_set[(int)id]) {
87 88 opt_set[(int)id] = TRUE;
88 89 opt_val[(int)id] = value;
89 90 return (FALSE);
90 91 }
91 92
92 93 if (opt_val[(int)id] != value) {
93 94 (void) fprintf(stderr, "%s\n", errmsg[(int)id]);
94 95 return (TRUE);
95 96 }
96 97
97 98 return (FALSE);
98 99 }
99 100
100 101 /*
101 102 * Print command-line help message.
102 103 */
103 104 static void
104 105 print_usage(const char *execname, int long_help)
105 106 {
106 107 char buffer[PATH_MAX];
107 108 (void) snprintf(buffer, sizeof (buffer), "%s", execname);
108 109
109 110 if (!long_help) {
110 111 /* Print short help to stderr. */
111 112 (void) fprintf(stderr, "Usage: %s [option(s)], ",
112 113 basename(buffer));
113 114 (void) fprintf(stderr, "use '%s -h' for details.\n",
114 115 basename(buffer));
115 116 return;
116 117 }
117 118
118 119 (void) printf("Usage: %s [option(s)]\n", basename(buffer));
119 120 (void) printf("Options:\n"
120 121 " -h, --help\n"
121 122 " Print this help.\n"
122 123 " -t, --interval TIME\n"
123 124 " Set refresh interval to TIME. "
124 125 "Valid range [1...60] seconds, default = 5\n"
125 126 /*
126 127 * Option "-c, --config FILE" is not user-visible for now.
127 128 * When we have chance to properly document the format of translation
128 129 * rules, we'll make it user-visible.
129 130 */
130 131 " -o, --output-log-file FILE\n"
131 132 " Output kernel log to FILE. Default = "
132 133 DEFAULT_KLOG_FILE "\n"
133 134 " -k, --kernel-log-level LEVEL\n"
134 135 " Set kernel log level to LEVEL.\n"
135 136 " 0(default) = None, 1 = Unmapped, 2 = Mapped, 3 = All.\n"
136 137 " -f, --feature [no]feature1,[no]feature2,...\n"
137 138 " Enable/disable features in LatencyTOP.\n"
138 139 " [no]filter:\n"
139 140 " Filter large interruptible latencies, e.g. sleep.\n"
140 141 " [no]sched:\n"
141 142 " Monitors sched (PID=0).\n"
142 143 " [no]sobj:\n"
143 144 " Monitors synchronization objects.\n"
144 145 " [no]low:\n"
145 146 " Lower overhead by sampling small latencies.\n"
146 147 " -l, --log-period TIME\n"
147 148 " Write and restart log every TIME seconds, TIME >= 60\n"
148 149 " -s --select [ pid=<pid> | pgid=<pgid> ]\n"
149 150 " Monitor only the given process or processes in the "
150 151 "given process group.\n");
151 152 }
152 153
153 154 /*
154 155 * Properly exit latencytop when it receives SIGINT or SIGTERM.
155 156 */
156 157 /* ARGSUSED */
157 158 static void
158 159 signal_handler(int sig)
159 160 {
160 161 lt_gpipe_break("q");
161 162 }
162 163
163 164 /*
164 165 * Convert string to integer. It returns error if extra characters are found.
165 166 */
166 167 static int
167 168 to_int(const char *str, int *result)
168 169 {
169 170 char *tail = NULL;
170 171 long ret;
171 172
172 173 if (str == NULL || result == NULL) {
173 174 return (-1);
174 175 }
175 176
176 177 ret = strtol(str, &tail, 10);
177 178
178 179 if (tail != NULL && *tail != '\0') {
179 180 return (-1);
180 181 }
181 182
182 183 *result = (int)ret;
183 184
184 185 return (0);
185 186 }
186 187
187 188 /*
188 189 * The main function.
189 190 */
190 191 int
191 192 main(int argc, char *argv[])
192 193 {
193 194 const char *opt_string = "t:o:k:hf:l:c:s:";
194 195 struct option const longopts[] = {
195 196 {"interval", required_argument, NULL, 't'},
196 197 {"output-log-file", required_argument, NULL, 'o'},
197 198 {"kernel-log-level", required_argument, NULL, 'k'},
198 199 {"help", no_argument, NULL, 'h'},
199 200 {"feature", required_argument, NULL, 'f'},
200 201 {"log-period", required_argument, NULL, 'l'},
201 202 {"config", required_argument, NULL, 'c'},
202 203 {"select", required_argument, NULL, 's'},
203 204 {NULL, 0, NULL, 0}
204 205 };
205 206
206 207 int optc;
207 208 int longind = 0;
208 209 int running = 1;
209 210 int unknown_option = FALSE;
210 211 int refresh_interval = 5;
211 212 int klog_level = 0;
212 213 int log_interval = 0;
213 214 long long last_logged = 0;
214 215 char *token = NULL;
215 216 int retval = 0;
216 217 int gpipe;
217 218 int err;
218 219 uint64_t collect_end;
219 220 uint64_t current_time;
220 221 uint64_t delta_time;
221 222 char logfile[PATH_MAX] = "";
222 223 int select_id;
223 224 int select_value;
224 225 char *select_str;
225 226 boolean_t no_dtrace_cleanup = B_TRUE;
226 227
227 228 lt_gpipe_init();
228 229 (void) signal(SIGINT, signal_handler);
229 230 (void) signal(SIGTERM, signal_handler);
230 231
231 232 /* Default global settings */
232 233 g_config.lt_cfg_enable_filter = 0;
233 234 g_config.lt_cfg_trace_sched = 0;
234 235 g_config.lt_cfg_trace_syncobj = 1;
235 236 g_config.lt_cfg_low_overhead_mode = 0;
236 237 g_config.lt_cfg_trace_pid = 0;
237 238 g_config.lt_cfg_trace_pgid = 0;
238 239 /* dtrace snapshot every 1 second */
239 240 g_config.lt_cfg_snap_interval = 1000;
240 241 #ifdef EMBED_CONFIGS
241 242 g_config.lt_cfg_config_name = NULL;
242 243 #else
243 244 g_config.lt_cfg_config_name = lt_strdup(DEFAULT_CONFIG_NAME);
244 245 #endif
245 246
246 247 /* Parse command line arguments. */
247 248 while ((optc = getopt_long(argc, argv, opt_string,
248 249 longopts, &longind)) != -1) {
249 250 switch (optc) {
250 251 case 'h':
251 252 print_usage(argv[0], TRUE);
252 253 goto end_none;
253 254 case 't':
254 255 if (to_int(optarg, &refresh_interval) != 0 ||
255 256 refresh_interval < 1 || refresh_interval > 60) {
256 257 lt_display_error(
257 258 "Invalid refresh interval: %s\n", optarg);
258 259 unknown_option = TRUE;
259 260 } else if (check_opt_dup(LT_CMDOPT_INTERVAL,
260 261 refresh_interval)) {
261 262 unknown_option = TRUE;
262 263 }
263 264
264 265 break;
265 266 case 'k':
266 267 if (to_int(optarg, &klog_level) != 0 ||
267 268 lt_klog_set_log_level(klog_level) != 0) {
268 269 lt_display_error(
269 270 "Invalid log level: %s\n", optarg);
270 271 unknown_option = TRUE;
271 272 } else if (check_opt_dup(LT_CMDOPT_LOG_LEVEL,
272 273 refresh_interval)) {
273 274 unknown_option = TRUE;
274 275 }
275 276
276 277 break;
277 278 case 'o':
278 279 if (check_opt_dup(LT_CMDOPT_LOG_FILE, optind)) {
279 280 unknown_option = TRUE;
280 281 } else if (strlen(optarg) >= sizeof (logfile)) {
281 282 lt_display_error(
282 283 "Log file name is too long: %s\n",
283 284 optarg);
284 285 unknown_option = TRUE;
285 286 } else {
286 287 (void) strncpy(logfile, optarg,
287 288 sizeof (logfile));
288 289 }
289 290
290 291 break;
291 292 case 'f':
292 293 for (token = strtok(optarg, ","); token != NULL;
293 294 token = strtok(NULL, ",")) {
294 295 int v = TRUE;
295 296
296 297 if (strncmp(token, "no", 2) == 0) {
297 298 v = FALSE;
298 299 token = &token[2];
299 300 }
300 301
301 302 if (CMPOPT(token, "filter") == 0) {
302 303 if (check_opt_dup(LT_CMDOPT_F_FILTER,
303 304 v)) {
304 305 unknown_option = TRUE;
305 306 } else {
306 307 g_config.lt_cfg_enable_filter
307 308 = v;
308 309 }
309 310 } else if (CMPOPT(token, "sched") == 0) {
310 311 if (check_opt_dup(LT_CMDOPT_F_SCHED,
311 312 v)) {
312 313 unknown_option = TRUE;
313 314 } else {
314 315 g_config.lt_cfg_trace_sched
315 316 = v;
316 317 }
317 318 } else if (CMPOPT(token, "sobj") == 0) {
318 319 if (check_opt_dup(LT_CMDOPT_F_SOBJ,
319 320 v)) {
320 321 unknown_option = TRUE;
321 322 } else {
322 323 g_config.lt_cfg_trace_syncobj
323 324 = v;
324 325 }
325 326 } else if (CMPOPT(token, "low") == 0) {
326 327 if (check_opt_dup(LT_CMDOPT_F_LOW,
327 328 v)) {
328 329 unknown_option = TRUE;
329 330 } else {
330 331 g_config.
331 332 lt_cfg_low_overhead_mode
332 333 = v;
333 334 }
334 335 } else {
335 336 lt_display_error(
336 337 "Unknown feature: %s\n", token);
337 338 unknown_option = TRUE;
338 339 }
339 340 }
340 341
341 342 break;
342 343 case 'l':
343 344 if (to_int(optarg, &log_interval) != 0 ||
344 345 log_interval < 60) {
345 346 lt_display_error(
346 347 "Invalid log interval: %s\n", optarg);
347 348 unknown_option = TRUE;
348 349 } else if (check_opt_dup(LT_CMDOPT_LOG_INTERVAL,
349 350 log_interval)) {
350 351 unknown_option = TRUE;
351 352 }
352 353
353 354 break;
354 355 case 'c':
355 356 if (strlen(optarg) >= PATH_MAX) {
356 357 lt_display_error(
357 358 "Configuration name is too long.\n");
358 359 unknown_option = TRUE;
359 360 } else if (check_opt_dup(LT_CMDOPT_CONFIG_FILE,
360 361 optind)) {
361 362 unknown_option = TRUE;
362 363 } else {
363 364 g_config.lt_cfg_config_name =
364 365 lt_strdup(optarg);
365 366 }
366 367
367 368 break;
368 369 case 's':
369 370 if (strncmp(optarg, "pid=", 4) == 0) {
370 371 select_id = 0;
371 372 select_str = &optarg[4];
372 373 } else if (strncmp(optarg, "pgid=", 5) == 0) {
373 374 select_id = 1;
374 375 select_str = &optarg[5];
375 376 } else {
376 377 lt_display_error(
377 378 "Invalid select option: %s\n", optarg);
378 379 unknown_option = TRUE;
379 380 break;
380 381 }
381 382
382 383 if (to_int(select_str, &select_value) != 0) {
383 384 lt_display_error(
384 385 "Invalid select option: %s\n", optarg);
385 386 unknown_option = TRUE;
386 387 break;
387 388 }
388 389
389 390 if (select_value <= 0) {
390 391 lt_display_error(
391 392 "Process/process group ID must be "
392 393 "greater than 0: %s\n", optarg);
393 394 unknown_option = TRUE;
394 395 break;
395 396 }
396 397
397 398 if (check_opt_dup(LT_CMDOPT_SELECT,
398 399 (((uint64_t)select_id) << 32) | select_value)) {
399 400 unknown_option = TRUE;
400 401 break;
401 402 }
402 403
403 404 if (select_id == 0) {
404 405 g_config.lt_cfg_trace_pid = select_value;
405 406 } else {
406 407 g_config.lt_cfg_trace_pgid = select_value;
407 408 }
408 409 break;
409 410 default:
410 411 unknown_option = TRUE;
411 412 break;
412 413 }
413 414 }
414 415
415 416 if (!unknown_option && strlen(logfile) > 0) {
416 417 err = lt_klog_set_log_file(logfile);
417 418
418 419 if (err == -1) {
419 420 lt_display_error("Log file name is too long: %s\n",
420 421 logfile);
421 422 unknown_option = TRUE;
422 423 } else if (err == -2) {
423 424 lt_display_error("Cannot write to log file: %s\n",
424 425 logfile);
425 426 unknown_option = TRUE;
426 427 }
427 428 }
428 429
429 430 /* Throw error for invalid/junk arguments */
430 431 if (optind < argc) {
431 432 int tmpind = optind;
432 433 (void) fprintf(stderr, "Unknown option(s): ");
433 434
434 435 while (tmpind < argc) {
435 436 (void) fprintf(stderr, "%s ", argv[tmpind++]);
436 437 }
437 438
438 439 (void) fprintf(stderr, "\n");
439 440 unknown_option = TRUE;
440 441 }
441 442
442 443 if (unknown_option) {
443 444 print_usage(argv[0], FALSE);
444 445 retval = 1;
445 446 goto end_none;
446 447 }
447 448
448 449 (void) printf("%s\n%s\n", TITLE, COPYRIGHT);
449 450
450 451 /*
451 452 * Initialization
452 453 */
453 454 lt_klog_init();
454 455
455 456 if (lt_table_init() != 0) {
456 457 lt_display_error("Unable to load configuration table.\n");
457 458 retval = 1;
458 459 goto end_notable;
459 460 }
460 461
461 462 if (lt_dtrace_init() != 0) {
462 463 lt_display_error("Unable to initialize dtrace.\n");
463 464 retval = 1;
464 465 goto end_nodtrace;
465 466 }
466 467
467 468 last_logged = lt_millisecond();
468 469
469 470 (void) printf("Collecting data for %d seconds...\n",
470 471 refresh_interval);
471 472
472 473 gpipe = lt_gpipe_readfd();
473 474 collect_end = last_logged + refresh_interval * 1000;
474 475 for (;;) {
475 476 fd_set read_fd;
476 477 struct timeval timeout;
477 478 int tsleep = collect_end - lt_millisecond();
478 479
479 480 if (tsleep <= 0) {
480 481 break;
481 482 }
482 483
483 484 /*
484 485 * Interval when we call dtrace_status() and collect
485 486 * aggregated data.
486 487 */
487 488 if (tsleep > g_config.lt_cfg_snap_interval) {
488 489 tsleep = g_config.lt_cfg_snap_interval;
489 490 }
490 491
491 492 timeout.tv_sec = tsleep / 1000;
492 493 timeout.tv_usec = (tsleep % 1000) * 1000;
493 494
494 495 FD_ZERO(&read_fd);
495 496 FD_SET(gpipe, &read_fd);
496 497
497 498 if (select(gpipe + 1, &read_fd, NULL, NULL, &timeout) > 0) {
498 499 goto end_ubreak;
499 500 }
500 501
501 502 (void) lt_dtrace_work(0);
502 503 }
503 504
504 505 lt_display_init();
505 506
506 507 do {
507 508 current_time = lt_millisecond();
508 509
509 510 lt_stat_clear_all();
510 511 (void) lt_dtrace_collect();
511 512
512 513 delta_time = current_time;
513 514 current_time = lt_millisecond();
514 515 delta_time = current_time - delta_time;
515 516
516 517 if (log_interval > 0 &&
517 518 current_time - last_logged > log_interval * 1000) {
518 519 lt_klog_write();
519 520 last_logged = current_time;
520 521 }
521 522
522 523 running = lt_display_loop(refresh_interval * 1000 -
523 524 delta_time);
524 525
525 526 /*
526 527 * This is to avoid dynamic variable drop
527 528 * in DTrace.
528 529 */
529 530 if (lt_drop_detected == B_TRUE) {
530 531 if (lt_dtrace_deinit() != 0) {
531 532 no_dtrace_cleanup = B_FALSE;
532 533 retval = 1;
533 534 break;
534 535 }
535 536
536 537 lt_drop_detected = B_FALSE;
537 538 if (lt_dtrace_init() != 0) {
538 539 retval = 1;
539 540 break;
540 541 }
541 542 }
542 543 } while (running != 0);
543 544
544 545 lt_klog_write();
545 546
546 547 /* Cleanup */
547 548 lt_display_deinit();
548 549
549 550 end_ubreak:
550 551 if (no_dtrace_cleanup == B_FALSE || lt_dtrace_deinit() != 0)
551 552 retval = 1;
552 553
553 554 lt_stat_free_all();
554 555
555 556 end_nodtrace:
556 557 lt_table_deinit();
557 558
558 559 end_notable:
559 560 lt_klog_deinit();
560 561
561 562 end_none:
562 563 lt_gpipe_deinit();
563 564
564 565 if (g_config.lt_cfg_config_name != NULL) {
565 566 free(g_config.lt_cfg_config_name);
566 567 }
567 568
568 569 return (retval);
569 570 }
|
↓ open down ↓ |
493 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX