12cd5e41aSRui Paulo /*
22cd5e41aSRui Paulo * CDDL HEADER START
32cd5e41aSRui Paulo *
42cd5e41aSRui Paulo * The contents of this file are subject to the terms of the
52cd5e41aSRui Paulo * Common Development and Distribution License (the "License").
62cd5e41aSRui Paulo * You may not use this file except in compliance with the License.
72cd5e41aSRui Paulo *
82cd5e41aSRui Paulo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92cd5e41aSRui Paulo * or http://www.opensolaris.org/os/licensing.
102cd5e41aSRui Paulo * See the License for the specific language governing permissions
112cd5e41aSRui Paulo * and limitations under the License.
122cd5e41aSRui Paulo *
132cd5e41aSRui Paulo * When distributing Covered Code, include this CDDL HEADER in each
142cd5e41aSRui Paulo * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152cd5e41aSRui Paulo * If applicable, add the following below this CDDL HEADER, with the
162cd5e41aSRui Paulo * fields enclosed by brackets "[]" replaced with your own identifying
172cd5e41aSRui Paulo * information: Portions Copyright [yyyy] [name of copyright owner]
182cd5e41aSRui Paulo *
192cd5e41aSRui Paulo * CDDL HEADER END
202cd5e41aSRui Paulo */
212cd5e41aSRui Paulo
222cd5e41aSRui Paulo /*
232cd5e41aSRui Paulo * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
242cd5e41aSRui Paulo * Use is subject to license terms.
252cd5e41aSRui Paulo */
262cd5e41aSRui Paulo
27bc96366cSSteven Hartland #ifdef illumos
282cd5e41aSRui Paulo #pragma ident "%Z%%M% %I% %E% SMI"
296544c919SRui Paulo #endif
302cd5e41aSRui Paulo
312cd5e41aSRui Paulo #include <assert.h>
322cd5e41aSRui Paulo #include <dtrace.h>
332cd5e41aSRui Paulo #include <limits.h>
342cd5e41aSRui Paulo #include <link.h>
352cd5e41aSRui Paulo #include <priv.h>
362cd5e41aSRui Paulo #include <signal.h>
372cd5e41aSRui Paulo #include <stdlib.h>
382cd5e41aSRui Paulo #include <stdarg.h>
392cd5e41aSRui Paulo #include <stdio.h>
402cd5e41aSRui Paulo #include <string.h>
412cd5e41aSRui Paulo #include <strings.h>
422cd5e41aSRui Paulo #include <errno.h>
432cd5e41aSRui Paulo #include <sys/wait.h>
442cd5e41aSRui Paulo #include <libgen.h>
452cd5e41aSRui Paulo #include <libproc.h>
466544c919SRui Paulo #include <libproc_compat.h>
472cd5e41aSRui Paulo
482cd5e41aSRui Paulo static char *g_pname;
492cd5e41aSRui Paulo static dtrace_hdl_t *g_dtp;
502cd5e41aSRui Paulo struct ps_prochandle *g_pr;
512cd5e41aSRui Paulo
522cd5e41aSRui Paulo #define E_SUCCESS 0
532cd5e41aSRui Paulo #define E_ERROR 1
542cd5e41aSRui Paulo #define E_USAGE 2
552cd5e41aSRui Paulo
562cd5e41aSRui Paulo /*
572cd5e41aSRui Paulo * For hold times we use a global associative array since for mutexes, in
582cd5e41aSRui Paulo * user-land, it's not invalid to release a sychonization primitive that
592cd5e41aSRui Paulo * another thread acquired; rwlocks require a thread-local associative array
602cd5e41aSRui Paulo * since multiple thread can hold the same lock for reading. Note that we
612cd5e41aSRui Paulo * ignore recursive mutex acquisitions and releases as they don't truly
622cd5e41aSRui Paulo * affect lock contention.
632cd5e41aSRui Paulo */
642cd5e41aSRui Paulo static const char *g_hold_init =
652cd5e41aSRui Paulo "plockstat$target:::rw-acquire\n"
662cd5e41aSRui Paulo "{\n"
672cd5e41aSRui Paulo " self->rwhold[arg0] = timestamp;\n"
682cd5e41aSRui Paulo "}\n"
692cd5e41aSRui Paulo "plockstat$target:::mutex-acquire\n"
702cd5e41aSRui Paulo "/arg1 == 0/\n"
712cd5e41aSRui Paulo "{\n"
722cd5e41aSRui Paulo " mtxhold[arg0] = timestamp;\n"
732cd5e41aSRui Paulo "}\n";
742cd5e41aSRui Paulo
752cd5e41aSRui Paulo static const char *g_hold_histogram =
762cd5e41aSRui Paulo "plockstat$target:::rw-release\n"
772cd5e41aSRui Paulo "/self->rwhold[arg0] && arg1 == 1/\n"
782cd5e41aSRui Paulo "{\n"
792cd5e41aSRui Paulo " @rw_w_hold[arg0, ustack()] =\n"
802cd5e41aSRui Paulo " quantize(timestamp - self->rwhold[arg0]);\n"
812cd5e41aSRui Paulo " self->rwhold[arg0] = 0;\n"
822cd5e41aSRui Paulo " rw_w_hold_found = 1;\n"
832cd5e41aSRui Paulo "}\n"
842cd5e41aSRui Paulo "plockstat$target:::rw-release\n"
852cd5e41aSRui Paulo "/self->rwhold[arg0]/\n"
862cd5e41aSRui Paulo "{\n"
872cd5e41aSRui Paulo " @rw_r_hold[arg0, ustack()] =\n"
882cd5e41aSRui Paulo " quantize(timestamp - self->rwhold[arg0]);\n"
892cd5e41aSRui Paulo " self->rwhold[arg0] = 0;\n"
902cd5e41aSRui Paulo " rw_r_hold_found = 1;\n"
912cd5e41aSRui Paulo "}\n"
922cd5e41aSRui Paulo "plockstat$target:::mutex-release\n"
932cd5e41aSRui Paulo "/mtxhold[arg0] && arg1 == 0/\n"
942cd5e41aSRui Paulo "{\n"
952cd5e41aSRui Paulo " @mtx_hold[arg0, ustack()] = quantize(timestamp - mtxhold[arg0]);\n"
962cd5e41aSRui Paulo " mtxhold[arg0] = 0;\n"
972cd5e41aSRui Paulo " mtx_hold_found = 1;\n"
982cd5e41aSRui Paulo "}\n"
992cd5e41aSRui Paulo "\n"
1002cd5e41aSRui Paulo "END\n"
1012cd5e41aSRui Paulo "/mtx_hold_found/\n"
1022cd5e41aSRui Paulo "{\n"
1032cd5e41aSRui Paulo " trace(\"Mutex hold\");\n"
1042cd5e41aSRui Paulo " printa(@mtx_hold);\n"
1052cd5e41aSRui Paulo "}\n"
1062cd5e41aSRui Paulo "END\n"
1072cd5e41aSRui Paulo "/rw_r_hold_found/\n"
1082cd5e41aSRui Paulo "{\n"
1092cd5e41aSRui Paulo " trace(\"R/W reader hold\");\n"
1102cd5e41aSRui Paulo " printa(@rw_r_hold);\n"
1112cd5e41aSRui Paulo "}\n"
1122cd5e41aSRui Paulo "END\n"
1132cd5e41aSRui Paulo "/rw_w_hold_found/\n"
1142cd5e41aSRui Paulo "{\n"
1152cd5e41aSRui Paulo " trace(\"R/W writer hold\");\n"
1162cd5e41aSRui Paulo " printa(@rw_w_hold);\n"
1172cd5e41aSRui Paulo "}\n";
1182cd5e41aSRui Paulo
1192cd5e41aSRui Paulo static const char *g_hold_times =
1202cd5e41aSRui Paulo "plockstat$target:::rw-release\n"
1212cd5e41aSRui Paulo "/self->rwhold[arg0] && arg1 == 1/\n"
1222cd5e41aSRui Paulo "{\n"
1232cd5e41aSRui Paulo " @rw_w_hold[arg0, ustack(5)] = sum(timestamp - self->rwhold[arg0]);\n"
1242cd5e41aSRui Paulo " @rw_w_hold_count[arg0, ustack(5)] = count();\n"
1252cd5e41aSRui Paulo " self->rwhold[arg0] = 0;\n"
1262cd5e41aSRui Paulo " rw_w_hold_found = 1;\n"
1272cd5e41aSRui Paulo "}\n"
1282cd5e41aSRui Paulo "plockstat$target:::rw-release\n"
1292cd5e41aSRui Paulo "/self->rwhold[arg0]/\n"
1302cd5e41aSRui Paulo "{\n"
1312cd5e41aSRui Paulo " @rw_r_hold[arg0, ustack(5)] = sum(timestamp - self->rwhold[arg0]);\n"
1322cd5e41aSRui Paulo " @rw_r_hold_count[arg0, ustack(5)] = count();\n"
1332cd5e41aSRui Paulo " self->rwhold[arg0] = 0;\n"
1342cd5e41aSRui Paulo " rw_r_hold_found = 1;\n"
1352cd5e41aSRui Paulo "}\n"
1362cd5e41aSRui Paulo "plockstat$target:::mutex-release\n"
1372cd5e41aSRui Paulo "/mtxhold[arg0] && arg1 == 0/\n"
1382cd5e41aSRui Paulo "{\n"
1392cd5e41aSRui Paulo " @mtx_hold[arg0, ustack(5)] = sum(timestamp - mtxhold[arg0]);\n"
1402cd5e41aSRui Paulo " @mtx_hold_count[arg0, ustack(5)] = count();\n"
1412cd5e41aSRui Paulo " mtxhold[arg0] = 0;\n"
1422cd5e41aSRui Paulo " mtx_hold_found = 1;\n"
1432cd5e41aSRui Paulo "}\n"
1442cd5e41aSRui Paulo "\n"
1452cd5e41aSRui Paulo "END\n"
1462cd5e41aSRui Paulo "/mtx_hold_found/\n"
1472cd5e41aSRui Paulo "{\n"
1482cd5e41aSRui Paulo " trace(\"Mutex hold\");\n"
1492cd5e41aSRui Paulo " printa(@mtx_hold, @mtx_hold_count);\n"
1502cd5e41aSRui Paulo "}\n"
1512cd5e41aSRui Paulo "END\n"
1522cd5e41aSRui Paulo "/rw_r_hold_found/\n"
1532cd5e41aSRui Paulo "{\n"
1542cd5e41aSRui Paulo " trace(\"R/W reader hold\");\n"
1552cd5e41aSRui Paulo " printa(@rw_r_hold, @rw_r_hold_count);\n"
1562cd5e41aSRui Paulo "}\n"
1572cd5e41aSRui Paulo "END\n"
1582cd5e41aSRui Paulo "/rw_w_hold_found/\n"
1592cd5e41aSRui Paulo "{\n"
1602cd5e41aSRui Paulo " trace(\"R/W writer hold\");\n"
1612cd5e41aSRui Paulo " printa(@rw_w_hold, @rw_w_hold_count);\n"
1622cd5e41aSRui Paulo "}\n";
1632cd5e41aSRui Paulo
1642cd5e41aSRui Paulo
1652cd5e41aSRui Paulo /*
1662cd5e41aSRui Paulo * For contention, we use thread-local associative arrays since we're tracing
1672cd5e41aSRui Paulo * a single thread's activity in libc and multiple threads can be blocking or
1682cd5e41aSRui Paulo * spinning on the same sychonization primitive.
1692cd5e41aSRui Paulo */
1702cd5e41aSRui Paulo static const char *g_ctnd_init =
1712cd5e41aSRui Paulo "plockstat$target:::rw-block\n"
1722cd5e41aSRui Paulo "{\n"
1732cd5e41aSRui Paulo " self->rwblock[arg0] = timestamp;\n"
1742cd5e41aSRui Paulo "}\n"
1752cd5e41aSRui Paulo "plockstat$target:::mutex-block\n"
1762cd5e41aSRui Paulo "{\n"
1772cd5e41aSRui Paulo " self->mtxblock[arg0] = timestamp;\n"
1782cd5e41aSRui Paulo "}\n"
1792cd5e41aSRui Paulo "plockstat$target:::mutex-spin\n"
1802cd5e41aSRui Paulo "{\n"
1812cd5e41aSRui Paulo " self->mtxspin[arg0] = timestamp;\n"
1822cd5e41aSRui Paulo "}\n";
1832cd5e41aSRui Paulo
1842cd5e41aSRui Paulo static const char *g_ctnd_histogram =
1852cd5e41aSRui Paulo "plockstat$target:::rw-blocked\n"
1862cd5e41aSRui Paulo "/self->rwblock[arg0] && arg1 == 1 && arg2 != 0/\n"
1872cd5e41aSRui Paulo "{\n"
1882cd5e41aSRui Paulo " @rw_w_block[arg0, ustack()] =\n"
1892cd5e41aSRui Paulo " quantize(timestamp - self->rwblock[arg0]);\n"
1902cd5e41aSRui Paulo " self->rwblock[arg0] = 0;\n"
1912cd5e41aSRui Paulo " rw_w_block_found = 1;\n"
1922cd5e41aSRui Paulo "}\n"
1932cd5e41aSRui Paulo "plockstat$target:::rw-blocked\n"
1942cd5e41aSRui Paulo "/self->rwblock[arg0] && arg2 != 0/\n"
1952cd5e41aSRui Paulo "{\n"
1962cd5e41aSRui Paulo " @rw_r_block[arg0, ustack()] =\n"
1972cd5e41aSRui Paulo " quantize(timestamp - self->rwblock[arg0]);\n"
1982cd5e41aSRui Paulo " self->rwblock[arg0] = 0;\n"
1992cd5e41aSRui Paulo " rw_r_block_found = 1;\n"
2002cd5e41aSRui Paulo "}\n"
2012cd5e41aSRui Paulo "plockstat$target:::rw-blocked\n"
2022cd5e41aSRui Paulo "/self->rwblock[arg0]/\n"
2032cd5e41aSRui Paulo "{\n"
2042cd5e41aSRui Paulo " self->rwblock[arg0] = 0;\n"
2052cd5e41aSRui Paulo "}\n"
2062cd5e41aSRui Paulo "plockstat$target:::mutex-spun\n"
2072cd5e41aSRui Paulo "/self->mtxspin[arg0] && arg1 != 0/\n"
2082cd5e41aSRui Paulo "{\n"
2092cd5e41aSRui Paulo " @mtx_spin[arg0, ustack()] =\n"
2102cd5e41aSRui Paulo " quantize(timestamp - self->mtxspin[arg0]);\n"
2112cd5e41aSRui Paulo " self->mtxspin[arg0] = 0;\n"
2122cd5e41aSRui Paulo " mtx_spin_found = 1;\n"
2132cd5e41aSRui Paulo "}\n"
2142cd5e41aSRui Paulo "plockstat$target:::mutex-spun\n"
2152cd5e41aSRui Paulo "/self->mtxspin[arg0]/\n"
2162cd5e41aSRui Paulo "{\n"
2172cd5e41aSRui Paulo " @mtx_vain_spin[arg0, ustack()] =\n"
2182cd5e41aSRui Paulo " quantize(timestamp - self->mtxspin[arg0]);\n"
2192cd5e41aSRui Paulo " self->mtxspin[arg0] = 0;\n"
2202cd5e41aSRui Paulo " mtx_vain_spin_found = 1;\n"
2212cd5e41aSRui Paulo "}\n"
2222cd5e41aSRui Paulo "plockstat$target:::mutex-blocked\n"
2232cd5e41aSRui Paulo "/self->mtxblock[arg0] && arg1 != 0/\n"
2242cd5e41aSRui Paulo "{\n"
2252cd5e41aSRui Paulo " @mtx_block[arg0, ustack()] =\n"
2262cd5e41aSRui Paulo " quantize(timestamp - self->mtxblock[arg0]);\n"
2272cd5e41aSRui Paulo " self->mtxblock[arg0] = 0;\n"
2282cd5e41aSRui Paulo " mtx_block_found = 1;\n"
2292cd5e41aSRui Paulo "}\n"
2302cd5e41aSRui Paulo "plockstat$target:::mutex-blocked\n"
2312cd5e41aSRui Paulo "/self->mtxblock[arg0]/\n"
2322cd5e41aSRui Paulo "{\n"
2332cd5e41aSRui Paulo " self->mtxblock[arg0] = 0;\n"
2342cd5e41aSRui Paulo "}\n"
2352cd5e41aSRui Paulo "\n"
2362cd5e41aSRui Paulo "END\n"
2372cd5e41aSRui Paulo "/mtx_block_found/\n"
2382cd5e41aSRui Paulo "{\n"
2392cd5e41aSRui Paulo " trace(\"Mutex block\");\n"
2402cd5e41aSRui Paulo " printa(@mtx_block);\n"
2412cd5e41aSRui Paulo "}\n"
2422cd5e41aSRui Paulo "END\n"
2432cd5e41aSRui Paulo "/mtx_spin_found/\n"
2442cd5e41aSRui Paulo "{\n"
2452cd5e41aSRui Paulo " trace(\"Mutex spin\");\n"
2462cd5e41aSRui Paulo " printa(@mtx_spin);\n"
2472cd5e41aSRui Paulo "}\n"
2482cd5e41aSRui Paulo "END\n"
2492cd5e41aSRui Paulo "/mtx_vain_spin_found/\n"
2502cd5e41aSRui Paulo "{\n"
2512cd5e41aSRui Paulo " trace(\"Mutex unsuccessful spin\");\n"
2522cd5e41aSRui Paulo " printa(@mtx_vain_spin);\n"
2532cd5e41aSRui Paulo "}\n"
2542cd5e41aSRui Paulo "END\n"
2552cd5e41aSRui Paulo "/rw_r_block_found/\n"
2562cd5e41aSRui Paulo "{\n"
2572cd5e41aSRui Paulo " trace(\"R/W reader block\");\n"
2582cd5e41aSRui Paulo " printa(@rw_r_block);\n"
2592cd5e41aSRui Paulo "}\n"
2602cd5e41aSRui Paulo "END\n"
2612cd5e41aSRui Paulo "/rw_w_block_found/\n"
2622cd5e41aSRui Paulo "{\n"
2632cd5e41aSRui Paulo " trace(\"R/W writer block\");\n"
2642cd5e41aSRui Paulo " printa(@rw_w_block);\n"
2652cd5e41aSRui Paulo "}\n";
2662cd5e41aSRui Paulo
2672cd5e41aSRui Paulo
2682cd5e41aSRui Paulo static const char *g_ctnd_times =
2692cd5e41aSRui Paulo "plockstat$target:::rw-blocked\n"
2702cd5e41aSRui Paulo "/self->rwblock[arg0] && arg1 == 1 && arg2 != 0/\n"
2712cd5e41aSRui Paulo "{\n"
2722cd5e41aSRui Paulo " @rw_w_block[arg0, ustack(5)] =\n"
2732cd5e41aSRui Paulo " sum(timestamp - self->rwblock[arg0]);\n"
2742cd5e41aSRui Paulo " @rw_w_block_count[arg0, ustack(5)] = count();\n"
2752cd5e41aSRui Paulo " self->rwblock[arg0] = 0;\n"
2762cd5e41aSRui Paulo " rw_w_block_found = 1;\n"
2772cd5e41aSRui Paulo "}\n"
2782cd5e41aSRui Paulo "plockstat$target:::rw-blocked\n"
2792cd5e41aSRui Paulo "/self->rwblock[arg0] && arg2 != 0/\n"
2802cd5e41aSRui Paulo "{\n"
2812cd5e41aSRui Paulo " @rw_r_block[arg0, ustack(5)] =\n"
2822cd5e41aSRui Paulo " sum(timestamp - self->rwblock[arg0]);\n"
2832cd5e41aSRui Paulo " @rw_r_block_count[arg0, ustack(5)] = count();\n"
2842cd5e41aSRui Paulo " self->rwblock[arg0] = 0;\n"
2852cd5e41aSRui Paulo " rw_r_block_found = 1;\n"
2862cd5e41aSRui Paulo "}\n"
2872cd5e41aSRui Paulo "plockstat$target:::rw-blocked\n"
2882cd5e41aSRui Paulo "/self->rwblock[arg0]/\n"
2892cd5e41aSRui Paulo "{\n"
2902cd5e41aSRui Paulo " self->rwblock[arg0] = 0;\n"
2912cd5e41aSRui Paulo "}\n"
2922cd5e41aSRui Paulo "plockstat$target:::mutex-spun\n"
2932cd5e41aSRui Paulo "/self->mtxspin[arg0] && arg1 != 0/\n"
2942cd5e41aSRui Paulo "{\n"
2952cd5e41aSRui Paulo " @mtx_spin[arg0, ustack(5)] =\n"
2962cd5e41aSRui Paulo " sum(timestamp - self->mtxspin[arg0]);\n"
2972cd5e41aSRui Paulo " @mtx_spin_count[arg0, ustack(5)] = count();\n"
2982cd5e41aSRui Paulo " self->mtxspin[arg0] = 0;\n"
2992cd5e41aSRui Paulo " mtx_spin_found = 1;\n"
3002cd5e41aSRui Paulo "}\n"
3012cd5e41aSRui Paulo "plockstat$target:::mutex-spun\n"
3022cd5e41aSRui Paulo "/self->mtxspin[arg0]/\n"
3032cd5e41aSRui Paulo "{\n"
3042cd5e41aSRui Paulo " @mtx_vain_spin[arg0, ustack(5)] =\n"
3052cd5e41aSRui Paulo " sum(timestamp - self->mtxspin[arg0]);\n"
3062cd5e41aSRui Paulo " @mtx_vain_spin_count[arg0, ustack(5)] = count();\n"
3072cd5e41aSRui Paulo " self->mtxspin[arg0] = 0;\n"
3082cd5e41aSRui Paulo " mtx_vain_spin_found = 1;\n"
3092cd5e41aSRui Paulo "}\n"
3102cd5e41aSRui Paulo "plockstat$target:::mutex-blocked\n"
3112cd5e41aSRui Paulo "/self->mtxblock[arg0] && arg1 != 0/\n"
3122cd5e41aSRui Paulo "{\n"
3132cd5e41aSRui Paulo " @mtx_block[arg0, ustack(5)] =\n"
3142cd5e41aSRui Paulo " sum(timestamp - self->mtxblock[arg0]);\n"
3152cd5e41aSRui Paulo " @mtx_block_count[arg0, ustack(5)] = count();\n"
3162cd5e41aSRui Paulo " self->mtxblock[arg0] = 0;\n"
3172cd5e41aSRui Paulo " mtx_block_found = 1;\n"
3182cd5e41aSRui Paulo "}\n"
3192cd5e41aSRui Paulo "plockstat$target:::mutex-blocked\n"
3202cd5e41aSRui Paulo "/self->mtxblock[arg0]/\n"
3212cd5e41aSRui Paulo "{\n"
3222cd5e41aSRui Paulo " self->mtxblock[arg0] = 0;\n"
3232cd5e41aSRui Paulo "}\n"
3242cd5e41aSRui Paulo "\n"
3252cd5e41aSRui Paulo "END\n"
3262cd5e41aSRui Paulo "/mtx_block_found/\n"
3272cd5e41aSRui Paulo "{\n"
3282cd5e41aSRui Paulo " trace(\"Mutex block\");\n"
3292cd5e41aSRui Paulo " printa(@mtx_block, @mtx_block_count);\n"
3302cd5e41aSRui Paulo "}\n"
3312cd5e41aSRui Paulo "END\n"
3322cd5e41aSRui Paulo "/mtx_spin_found/\n"
3332cd5e41aSRui Paulo "{\n"
3342cd5e41aSRui Paulo " trace(\"Mutex spin\");\n"
3352cd5e41aSRui Paulo " printa(@mtx_spin, @mtx_spin_count);\n"
3362cd5e41aSRui Paulo "}\n"
3372cd5e41aSRui Paulo "END\n"
3382cd5e41aSRui Paulo "/mtx_vain_spin_found/\n"
3392cd5e41aSRui Paulo "{\n"
3402cd5e41aSRui Paulo " trace(\"Mutex unsuccessful spin\");\n"
3412cd5e41aSRui Paulo " printa(@mtx_vain_spin, @mtx_vain_spin_count);\n"
3422cd5e41aSRui Paulo "}\n"
3432cd5e41aSRui Paulo "END\n"
3442cd5e41aSRui Paulo "/rw_r_block_found/\n"
3452cd5e41aSRui Paulo "{\n"
3462cd5e41aSRui Paulo " trace(\"R/W reader block\");\n"
3472cd5e41aSRui Paulo " printa(@rw_r_block, @rw_r_block_count);\n"
3482cd5e41aSRui Paulo "}\n"
3492cd5e41aSRui Paulo "END\n"
3502cd5e41aSRui Paulo "/rw_w_block_found/\n"
3512cd5e41aSRui Paulo "{\n"
3522cd5e41aSRui Paulo " trace(\"R/W writer block\");\n"
3532cd5e41aSRui Paulo " printa(@rw_w_block, @rw_w_block_count);\n"
3542cd5e41aSRui Paulo "}\n";
3552cd5e41aSRui Paulo
3562cd5e41aSRui Paulo static char g_prog[4096];
3572cd5e41aSRui Paulo static size_t g_proglen;
3582cd5e41aSRui Paulo static int g_opt_V, g_opt_s;
3592cd5e41aSRui Paulo static int g_intr;
3602cd5e41aSRui Paulo static int g_exited;
3612cd5e41aSRui Paulo static dtrace_optval_t g_nframes;
3622cd5e41aSRui Paulo static ulong_t g_nent = ULONG_MAX;
3632cd5e41aSRui Paulo
3642cd5e41aSRui Paulo #define PLOCKSTAT_OPTSTR "n:ps:e:vx:ACHV"
3652cd5e41aSRui Paulo
3662cd5e41aSRui Paulo static void
usage(void)3672cd5e41aSRui Paulo usage(void)
3682cd5e41aSRui Paulo {
3692cd5e41aSRui Paulo (void) fprintf(stderr, "Usage:\n"
3702cd5e41aSRui Paulo "\t%s [-vACHV] [-n count] [-s depth] [-e secs] [-x opt[=val]]\n"
3712cd5e41aSRui Paulo "\t command [arg...]\n"
3722cd5e41aSRui Paulo "\t%s [-vACHV] [-n count] [-s depth] [-e secs] [-x opt[=val]]\n"
3732cd5e41aSRui Paulo "\t -p pid\n", g_pname, g_pname);
3742cd5e41aSRui Paulo
3752cd5e41aSRui Paulo exit(E_USAGE);
3762cd5e41aSRui Paulo }
3772cd5e41aSRui Paulo
3782cd5e41aSRui Paulo static void
verror(const char * fmt,va_list ap)3792cd5e41aSRui Paulo verror(const char *fmt, va_list ap)
3802cd5e41aSRui Paulo {
3812cd5e41aSRui Paulo int error = errno;
3822cd5e41aSRui Paulo
3832cd5e41aSRui Paulo (void) fprintf(stderr, "%s: ", g_pname);
3842cd5e41aSRui Paulo (void) vfprintf(stderr, fmt, ap);
3852cd5e41aSRui Paulo
3862cd5e41aSRui Paulo if (fmt[strlen(fmt) - 1] != '\n')
3872cd5e41aSRui Paulo (void) fprintf(stderr, ": %s\n", strerror(error));
3882cd5e41aSRui Paulo }
3892cd5e41aSRui Paulo
3902cd5e41aSRui Paulo /*PRINTFLIKE1*/
3912cd5e41aSRui Paulo static void
fatal(const char * fmt,...)3922cd5e41aSRui Paulo fatal(const char *fmt, ...)
3932cd5e41aSRui Paulo {
3942cd5e41aSRui Paulo va_list ap;
3952cd5e41aSRui Paulo
3962cd5e41aSRui Paulo va_start(ap, fmt);
3972cd5e41aSRui Paulo verror(fmt, ap);
3982cd5e41aSRui Paulo va_end(ap);
3992cd5e41aSRui Paulo
4002cd5e41aSRui Paulo if (g_pr != NULL && g_dtp != NULL)
4012cd5e41aSRui Paulo dtrace_proc_release(g_dtp, g_pr);
4022cd5e41aSRui Paulo
4032cd5e41aSRui Paulo exit(E_ERROR);
4042cd5e41aSRui Paulo }
4052cd5e41aSRui Paulo
4062cd5e41aSRui Paulo /*PRINTFLIKE1*/
4072cd5e41aSRui Paulo static void
dfatal(const char * fmt,...)4082cd5e41aSRui Paulo dfatal(const char *fmt, ...)
4092cd5e41aSRui Paulo {
4102cd5e41aSRui Paulo va_list ap;
4112cd5e41aSRui Paulo
4122cd5e41aSRui Paulo va_start(ap, fmt);
4132cd5e41aSRui Paulo
4142cd5e41aSRui Paulo (void) fprintf(stderr, "%s: ", g_pname);
4152cd5e41aSRui Paulo if (fmt != NULL)
4162cd5e41aSRui Paulo (void) vfprintf(stderr, fmt, ap);
4172cd5e41aSRui Paulo
4182cd5e41aSRui Paulo va_end(ap);
4192cd5e41aSRui Paulo
4202cd5e41aSRui Paulo if (fmt != NULL && fmt[strlen(fmt) - 1] != '\n') {
4212cd5e41aSRui Paulo (void) fprintf(stderr, ": %s\n",
4222cd5e41aSRui Paulo dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
4232cd5e41aSRui Paulo } else if (fmt == NULL) {
4242cd5e41aSRui Paulo (void) fprintf(stderr, "%s\n",
4252cd5e41aSRui Paulo dtrace_errmsg(g_dtp, dtrace_errno(g_dtp)));
4262cd5e41aSRui Paulo }
4272cd5e41aSRui Paulo
4282cd5e41aSRui Paulo if (g_pr != NULL) {
4292cd5e41aSRui Paulo dtrace_proc_continue(g_dtp, g_pr);
4302cd5e41aSRui Paulo dtrace_proc_release(g_dtp, g_pr);
4312cd5e41aSRui Paulo }
4322cd5e41aSRui Paulo
4332cd5e41aSRui Paulo exit(E_ERROR);
4342cd5e41aSRui Paulo }
4352cd5e41aSRui Paulo
4362cd5e41aSRui Paulo /*PRINTFLIKE1*/
4372cd5e41aSRui Paulo static void
notice(const char * fmt,...)4382cd5e41aSRui Paulo notice(const char *fmt, ...)
4392cd5e41aSRui Paulo {
4402cd5e41aSRui Paulo va_list ap;
4412cd5e41aSRui Paulo
4422cd5e41aSRui Paulo va_start(ap, fmt);
4432cd5e41aSRui Paulo verror(fmt, ap);
4442cd5e41aSRui Paulo va_end(ap);
4452cd5e41aSRui Paulo }
4462cd5e41aSRui Paulo
4472cd5e41aSRui Paulo static void
dprog_add(const char * prog)4482cd5e41aSRui Paulo dprog_add(const char *prog)
4492cd5e41aSRui Paulo {
4502cd5e41aSRui Paulo size_t len = strlen(prog);
4512cd5e41aSRui Paulo bcopy(prog, g_prog + g_proglen, len + 1);
4522cd5e41aSRui Paulo g_proglen += len;
4532cd5e41aSRui Paulo assert(g_proglen < sizeof (g_prog));
4542cd5e41aSRui Paulo }
4552cd5e41aSRui Paulo
4562cd5e41aSRui Paulo static void
dprog_compile(void)4572cd5e41aSRui Paulo dprog_compile(void)
4582cd5e41aSRui Paulo {
4592cd5e41aSRui Paulo dtrace_prog_t *prog;
4602cd5e41aSRui Paulo dtrace_proginfo_t info;
4612cd5e41aSRui Paulo
4622cd5e41aSRui Paulo if (g_opt_V) {
4632cd5e41aSRui Paulo (void) fprintf(stderr, "%s: vvvv D program vvvv\n", g_pname);
4642cd5e41aSRui Paulo (void) fputs(g_prog, stderr);
4652cd5e41aSRui Paulo (void) fprintf(stderr, "%s: ^^^^ D program ^^^^\n", g_pname);
4662cd5e41aSRui Paulo }
4672cd5e41aSRui Paulo
4682cd5e41aSRui Paulo if ((prog = dtrace_program_strcompile(g_dtp, g_prog,
4692cd5e41aSRui Paulo DTRACE_PROBESPEC_NAME, 0, 0, NULL)) == NULL)
4702cd5e41aSRui Paulo dfatal("failed to compile program");
4712cd5e41aSRui Paulo
4722cd5e41aSRui Paulo if (dtrace_program_exec(g_dtp, prog, &info) == -1)
4732cd5e41aSRui Paulo dfatal("failed to enable probes");
4742cd5e41aSRui Paulo }
4752cd5e41aSRui Paulo
4762cd5e41aSRui Paulo void
print_legend(void)4772cd5e41aSRui Paulo print_legend(void)
4782cd5e41aSRui Paulo {
4792cd5e41aSRui Paulo (void) printf("%5s %8s %-28s %s\n", "Count", "nsec", "Lock", "Caller");
4802cd5e41aSRui Paulo }
4812cd5e41aSRui Paulo
4822cd5e41aSRui Paulo void
print_bar(void)4832cd5e41aSRui Paulo print_bar(void)
4842cd5e41aSRui Paulo {
4852cd5e41aSRui Paulo (void) printf("---------------------------------------"
4862cd5e41aSRui Paulo "----------------------------------------\n");
4872cd5e41aSRui Paulo }
4882cd5e41aSRui Paulo
4892cd5e41aSRui Paulo void
print_histogram_header(void)4902cd5e41aSRui Paulo print_histogram_header(void)
4912cd5e41aSRui Paulo {
4922cd5e41aSRui Paulo (void) printf("\n%10s ---- Time Distribution --- %5s %s\n",
4932cd5e41aSRui Paulo "nsec", "count", "Stack");
4942cd5e41aSRui Paulo }
4952cd5e41aSRui Paulo
4962cd5e41aSRui Paulo /*
4972cd5e41aSRui Paulo * Convert an address to a symbolic string or a numeric string. If nolocks
4982cd5e41aSRui Paulo * is set, we return an error code if this symbol appears to be a mutex- or
4992cd5e41aSRui Paulo * rwlock-related symbol in libc so the caller has a chance to find a more
5002cd5e41aSRui Paulo * helpful symbol.
5012cd5e41aSRui Paulo */
5022cd5e41aSRui Paulo static int
getsym(struct ps_prochandle * P,uintptr_t addr,char * buf,size_t size,int nolocks)5032cd5e41aSRui Paulo getsym(struct ps_prochandle *P, uintptr_t addr, char *buf, size_t size,
5042cd5e41aSRui Paulo int nolocks)
5052cd5e41aSRui Paulo {
5062cd5e41aSRui Paulo char name[256];
5072cd5e41aSRui Paulo GElf_Sym sym;
508bc96366cSSteven Hartland #ifdef illumos
5092cd5e41aSRui Paulo prsyminfo_t info;
5106544c919SRui Paulo #else
5116544c919SRui Paulo prmap_t *map;
5126544c919SRui Paulo int info; /* XXX unused */
5136544c919SRui Paulo #endif
5142cd5e41aSRui Paulo size_t len;
5152cd5e41aSRui Paulo
5162cd5e41aSRui Paulo if (P == NULL || Pxlookup_by_addr(P, addr, name, sizeof (name),
5172cd5e41aSRui Paulo &sym, &info) != 0) {
518*e3c6864eSBryan Drewery (void) snprintf(buf, size, "%#lx", (unsigned long)addr);
5192cd5e41aSRui Paulo return (0);
5202cd5e41aSRui Paulo }
521bc96366cSSteven Hartland #ifdef illumos
5222cd5e41aSRui Paulo if (info.prs_object == NULL)
5232cd5e41aSRui Paulo info.prs_object = "<unknown>";
5242cd5e41aSRui Paulo
5252cd5e41aSRui Paulo if (info.prs_lmid != LM_ID_BASE) {
5262cd5e41aSRui Paulo len = snprintf(buf, size, "LM%lu`", info.prs_lmid);
5272cd5e41aSRui Paulo buf += len;
5282cd5e41aSRui Paulo size -= len;
5292cd5e41aSRui Paulo }
5302cd5e41aSRui Paulo
5312cd5e41aSRui Paulo len = snprintf(buf, size, "%s`%s", info.prs_object, info.prs_name);
5326544c919SRui Paulo #else
5336544c919SRui Paulo map = proc_addr2map(P, addr);
5346544c919SRui Paulo len = snprintf(buf, size, "%s`%s", map->pr_mapname, name);
5356544c919SRui Paulo #endif
5362cd5e41aSRui Paulo buf += len;
5372cd5e41aSRui Paulo size -= len;
5382cd5e41aSRui Paulo
5392cd5e41aSRui Paulo if (sym.st_value != addr)
540*e3c6864eSBryan Drewery len = snprintf(buf, size, "+%#lx", (unsigned long)(addr - sym.st_value));
5412cd5e41aSRui Paulo
5426544c919SRui Paulo if (nolocks && strcmp("libc.so.1", map->pr_mapname) == 0 &&
5436544c919SRui Paulo (strstr("mutex", name) == 0 ||
5446544c919SRui Paulo strstr("rw", name) == 0))
5452cd5e41aSRui Paulo return (-1);
5462cd5e41aSRui Paulo
5472cd5e41aSRui Paulo return (0);
5482cd5e41aSRui Paulo }
5492cd5e41aSRui Paulo
5502cd5e41aSRui Paulo /*ARGSUSED*/
5512cd5e41aSRui Paulo static int
process_aggregate(const dtrace_aggdata_t ** aggsdata,int naggvars,void * arg)5522cd5e41aSRui Paulo process_aggregate(const dtrace_aggdata_t **aggsdata, int naggvars, void *arg)
5532cd5e41aSRui Paulo {
5542cd5e41aSRui Paulo const dtrace_recdesc_t *rec;
5552cd5e41aSRui Paulo uintptr_t lock;
5562cd5e41aSRui Paulo uint64_t *stack;
5572cd5e41aSRui Paulo caddr_t data;
5582cd5e41aSRui Paulo pid_t pid;
5592cd5e41aSRui Paulo struct ps_prochandle *P;
5602cd5e41aSRui Paulo char buf[256];
5612cd5e41aSRui Paulo int i, j;
5622cd5e41aSRui Paulo uint64_t sum, count, avg;
5632cd5e41aSRui Paulo
5642cd5e41aSRui Paulo if ((*(uint_t *)arg)++ >= g_nent)
5652cd5e41aSRui Paulo return (DTRACE_AGGWALK_NEXT);
5662cd5e41aSRui Paulo
5672cd5e41aSRui Paulo rec = aggsdata[0]->dtada_desc->dtagd_rec;
5682cd5e41aSRui Paulo data = aggsdata[0]->dtada_data;
5692cd5e41aSRui Paulo
5702cd5e41aSRui Paulo /*LINTED - alignment*/
5712cd5e41aSRui Paulo lock = (uintptr_t)*(uint64_t *)(data + rec[1].dtrd_offset);
5722cd5e41aSRui Paulo /*LINTED - alignment*/
5732cd5e41aSRui Paulo stack = (uint64_t *)(data + rec[2].dtrd_offset);
5742cd5e41aSRui Paulo
5752cd5e41aSRui Paulo if (!g_opt_s) {
5762cd5e41aSRui Paulo /*LINTED - alignment*/
5772cd5e41aSRui Paulo sum = *(uint64_t *)(aggsdata[1]->dtada_data +
5782cd5e41aSRui Paulo aggsdata[1]->dtada_desc->dtagd_rec[3].dtrd_offset);
5792cd5e41aSRui Paulo /*LINTED - alignment*/
5802cd5e41aSRui Paulo count = *(uint64_t *)(aggsdata[2]->dtada_data +
5812cd5e41aSRui Paulo aggsdata[2]->dtada_desc->dtagd_rec[3].dtrd_offset);
5822cd5e41aSRui Paulo } else {
5832cd5e41aSRui Paulo uint64_t *a;
5842cd5e41aSRui Paulo
5852cd5e41aSRui Paulo /*LINTED - alignment*/
5862cd5e41aSRui Paulo a = (uint64_t *)(aggsdata[1]->dtada_data +
5872cd5e41aSRui Paulo aggsdata[1]->dtada_desc->dtagd_rec[3].dtrd_offset);
5882cd5e41aSRui Paulo
5892cd5e41aSRui Paulo print_bar();
5902cd5e41aSRui Paulo print_legend();
5912cd5e41aSRui Paulo
5922cd5e41aSRui Paulo for (count = sum = 0, i = DTRACE_QUANTIZE_ZEROBUCKET, j = 0;
5932cd5e41aSRui Paulo i < DTRACE_QUANTIZE_NBUCKETS; i++, j++) {
5942cd5e41aSRui Paulo count += a[i];
5952cd5e41aSRui Paulo sum += a[i] << (j - 64);
5962cd5e41aSRui Paulo }
5972cd5e41aSRui Paulo }
5982cd5e41aSRui Paulo
5992cd5e41aSRui Paulo avg = sum / count;
6002cd5e41aSRui Paulo (void) printf("%5llu %8llu ", (u_longlong_t)count, (u_longlong_t)avg);
6012cd5e41aSRui Paulo
6022cd5e41aSRui Paulo pid = stack[0];
6032cd5e41aSRui Paulo P = dtrace_proc_grab(g_dtp, pid, PGRAB_RDONLY);
6042cd5e41aSRui Paulo
6052cd5e41aSRui Paulo (void) getsym(P, lock, buf, sizeof (buf), 0);
6062cd5e41aSRui Paulo (void) printf("%-28s ", buf);
6072cd5e41aSRui Paulo
6082cd5e41aSRui Paulo for (i = 2; i <= 5; i++) {
6092cd5e41aSRui Paulo if (getsym(P, stack[i], buf, sizeof (buf), 1) == 0)
6102cd5e41aSRui Paulo break;
6112cd5e41aSRui Paulo }
6122cd5e41aSRui Paulo (void) printf("%s\n", buf);
6132cd5e41aSRui Paulo
6142cd5e41aSRui Paulo if (g_opt_s) {
6152cd5e41aSRui Paulo int stack_done = 0;
6162cd5e41aSRui Paulo int quant_done = 0;
6172cd5e41aSRui Paulo int first_bin, last_bin;
6182cd5e41aSRui Paulo uint64_t bin_size, *a;
6192cd5e41aSRui Paulo
6202cd5e41aSRui Paulo /*LINTED - alignment*/
6212cd5e41aSRui Paulo a = (uint64_t *)(aggsdata[1]->dtada_data +
6222cd5e41aSRui Paulo aggsdata[1]->dtada_desc->dtagd_rec[3].dtrd_offset);
6232cd5e41aSRui Paulo
6242cd5e41aSRui Paulo print_histogram_header();
6252cd5e41aSRui Paulo
6262cd5e41aSRui Paulo for (first_bin = DTRACE_QUANTIZE_ZEROBUCKET;
6272cd5e41aSRui Paulo a[first_bin] == 0; first_bin++)
6282cd5e41aSRui Paulo continue;
6292cd5e41aSRui Paulo for (last_bin = DTRACE_QUANTIZE_ZEROBUCKET + 63;
6302cd5e41aSRui Paulo a[last_bin] == 0; last_bin--)
6312cd5e41aSRui Paulo continue;
6322cd5e41aSRui Paulo
6332cd5e41aSRui Paulo for (i = 0; !stack_done || !quant_done; i++) {
6342cd5e41aSRui Paulo if (!stack_done) {
6352cd5e41aSRui Paulo (void) getsym(P, stack[i + 2], buf,
6362cd5e41aSRui Paulo sizeof (buf), 0);
6372cd5e41aSRui Paulo } else {
6382cd5e41aSRui Paulo buf[0] = '\0';
6392cd5e41aSRui Paulo }
6402cd5e41aSRui Paulo
6412cd5e41aSRui Paulo if (!quant_done) {
6422cd5e41aSRui Paulo bin_size = a[first_bin];
6432cd5e41aSRui Paulo
6442cd5e41aSRui Paulo (void) printf("%10llu |%-24.*s| %5llu %s\n",
6452cd5e41aSRui Paulo 1ULL <<
6462cd5e41aSRui Paulo (first_bin - DTRACE_QUANTIZE_ZEROBUCKET),
6472cd5e41aSRui Paulo (int)(24.0 * bin_size / count),
6482cd5e41aSRui Paulo "@@@@@@@@@@@@@@@@@@@@@@@@@@",
6492cd5e41aSRui Paulo (u_longlong_t)bin_size, buf);
6502cd5e41aSRui Paulo } else {
6512cd5e41aSRui Paulo (void) printf("%43s %s\n", "", buf);
6522cd5e41aSRui Paulo }
6532cd5e41aSRui Paulo
6542cd5e41aSRui Paulo if (i + 1 >= g_nframes || stack[i + 3] == 0)
6552cd5e41aSRui Paulo stack_done = 1;
6562cd5e41aSRui Paulo
6572cd5e41aSRui Paulo if (first_bin++ == last_bin)
6582cd5e41aSRui Paulo quant_done = 1;
6592cd5e41aSRui Paulo }
6602cd5e41aSRui Paulo }
6612cd5e41aSRui Paulo
6622cd5e41aSRui Paulo dtrace_proc_release(g_dtp, P);
6632cd5e41aSRui Paulo
6642cd5e41aSRui Paulo return (DTRACE_AGGWALK_NEXT);
6652cd5e41aSRui Paulo }
6662cd5e41aSRui Paulo
6672cd5e41aSRui Paulo /*ARGSUSED*/
6682cd5e41aSRui Paulo static void
prochandler(struct ps_prochandle * P,const char * msg,void * arg)6692cd5e41aSRui Paulo prochandler(struct ps_prochandle *P, const char *msg, void *arg)
6702cd5e41aSRui Paulo {
671bc96366cSSteven Hartland #ifdef illumos
6722cd5e41aSRui Paulo const psinfo_t *prp = Ppsinfo(P);
6732cd5e41aSRui Paulo int pid = Pstatus(P)->pr_pid;
6746544c919SRui Paulo #else
6756544c919SRui Paulo int pid = proc_getpid(P);
6766544c919SRui Paulo int wstat = proc_getwstat(P);
6776544c919SRui Paulo #endif
6782cd5e41aSRui Paulo char name[SIG2STR_MAX];
6792cd5e41aSRui Paulo
6802cd5e41aSRui Paulo if (msg != NULL) {
6812cd5e41aSRui Paulo notice("pid %d: %s\n", pid, msg);
6822cd5e41aSRui Paulo return;
6832cd5e41aSRui Paulo }
6842cd5e41aSRui Paulo
6852cd5e41aSRui Paulo switch (Pstate(P)) {
6862cd5e41aSRui Paulo case PS_UNDEAD:
6872cd5e41aSRui Paulo /*
6882cd5e41aSRui Paulo * Ideally we would like to always report pr_wstat here, but it
6892cd5e41aSRui Paulo * isn't possible given current /proc semantics. If we grabbed
6902cd5e41aSRui Paulo * the process, Ppsinfo() will either fail or return a zeroed
6912cd5e41aSRui Paulo * psinfo_t depending on how far the parent is in reaping it.
6922cd5e41aSRui Paulo * When /proc provides a stable pr_wstat in the status file,
6932cd5e41aSRui Paulo * this code can be improved by examining this new pr_wstat.
6942cd5e41aSRui Paulo */
6956544c919SRui Paulo if (WIFSIGNALED(wstat)) {
6962cd5e41aSRui Paulo notice("pid %d terminated by %s\n", pid,
6976544c919SRui Paulo proc_signame(WTERMSIG(wstat),
6982cd5e41aSRui Paulo name, sizeof (name)));
6996544c919SRui Paulo } else if (WEXITSTATUS(wstat) != 0) {
7002cd5e41aSRui Paulo notice("pid %d exited with status %d\n",
7016544c919SRui Paulo pid, WEXITSTATUS(wstat));
7022cd5e41aSRui Paulo } else {
7032cd5e41aSRui Paulo notice("pid %d has exited\n", pid);
7042cd5e41aSRui Paulo }
7052cd5e41aSRui Paulo g_exited = 1;
7062cd5e41aSRui Paulo break;
7072cd5e41aSRui Paulo
7082cd5e41aSRui Paulo case PS_LOST:
7092cd5e41aSRui Paulo notice("pid %d exec'd a set-id or unobservable program\n", pid);
7102cd5e41aSRui Paulo g_exited = 1;
7112cd5e41aSRui Paulo break;
7122cd5e41aSRui Paulo }
7132cd5e41aSRui Paulo }
7142cd5e41aSRui Paulo
7152cd5e41aSRui Paulo /*ARGSUSED*/
7162cd5e41aSRui Paulo static int
chewrec(const dtrace_probedata_t * data,const dtrace_recdesc_t * rec,void * arg)7172cd5e41aSRui Paulo chewrec(const dtrace_probedata_t *data, const dtrace_recdesc_t *rec, void *arg)
7182cd5e41aSRui Paulo {
7192cd5e41aSRui Paulo dtrace_eprobedesc_t *epd = data->dtpda_edesc;
7202cd5e41aSRui Paulo dtrace_aggvarid_t aggvars[2];
7212cd5e41aSRui Paulo const void *buf;
7222cd5e41aSRui Paulo int i, nagv;
7232cd5e41aSRui Paulo
7242cd5e41aSRui Paulo /*
7252cd5e41aSRui Paulo * A NULL rec indicates that we've processed the last record.
7262cd5e41aSRui Paulo */
7272cd5e41aSRui Paulo if (rec == NULL)
7282cd5e41aSRui Paulo return (DTRACE_CONSUME_NEXT);
7292cd5e41aSRui Paulo
7302cd5e41aSRui Paulo buf = data->dtpda_data - rec->dtrd_offset;
7312cd5e41aSRui Paulo
7322cd5e41aSRui Paulo switch (rec->dtrd_action) {
7332cd5e41aSRui Paulo case DTRACEACT_DIFEXPR:
7342cd5e41aSRui Paulo (void) printf("\n%s\n\n", (char *)buf + rec->dtrd_offset);
7352cd5e41aSRui Paulo if (!g_opt_s) {
7362cd5e41aSRui Paulo print_legend();
7372cd5e41aSRui Paulo print_bar();
7382cd5e41aSRui Paulo }
7392cd5e41aSRui Paulo return (DTRACE_CONSUME_NEXT);
7402cd5e41aSRui Paulo
7412cd5e41aSRui Paulo case DTRACEACT_PRINTA:
7422cd5e41aSRui Paulo for (nagv = 0, i = 0; i < epd->dtepd_nrecs - 1; i++) {
7432cd5e41aSRui Paulo const dtrace_recdesc_t *nrec = &rec[i];
7442cd5e41aSRui Paulo
7452cd5e41aSRui Paulo if (nrec->dtrd_uarg != rec->dtrd_uarg)
7462cd5e41aSRui Paulo break;
7472cd5e41aSRui Paulo
7482cd5e41aSRui Paulo /*LINTED - alignment*/
7492cd5e41aSRui Paulo aggvars[nagv++] = *(dtrace_aggvarid_t *)((caddr_t)buf +
7502cd5e41aSRui Paulo nrec->dtrd_offset);
7512cd5e41aSRui Paulo }
7522cd5e41aSRui Paulo
7532cd5e41aSRui Paulo if (nagv == (g_opt_s ? 1 : 2)) {
7542cd5e41aSRui Paulo uint_t nent = 0;
7552cd5e41aSRui Paulo if (dtrace_aggregate_walk_joined(g_dtp, aggvars, nagv,
7562cd5e41aSRui Paulo process_aggregate, &nent) != 0)
7572cd5e41aSRui Paulo dfatal("failed to walk aggregate");
7582cd5e41aSRui Paulo }
7592cd5e41aSRui Paulo
7602cd5e41aSRui Paulo return (DTRACE_CONSUME_NEXT);
7612cd5e41aSRui Paulo }
7622cd5e41aSRui Paulo
7632cd5e41aSRui Paulo return (DTRACE_CONSUME_THIS);
7642cd5e41aSRui Paulo }
7652cd5e41aSRui Paulo
7662cd5e41aSRui Paulo /*ARGSUSED*/
7672cd5e41aSRui Paulo static void
intr(int signo)7682cd5e41aSRui Paulo intr(int signo)
7692cd5e41aSRui Paulo {
7702cd5e41aSRui Paulo g_intr = 1;
7712cd5e41aSRui Paulo }
7722cd5e41aSRui Paulo
7732cd5e41aSRui Paulo int
main(int argc,char ** argv)7742cd5e41aSRui Paulo main(int argc, char **argv)
7752cd5e41aSRui Paulo {
776bc96366cSSteven Hartland #ifdef illumos
7772cd5e41aSRui Paulo ucred_t *ucp;
7786544c919SRui Paulo #endif
7792cd5e41aSRui Paulo int err;
7802cd5e41aSRui Paulo int opt_C = 0, opt_H = 0, opt_p = 0, opt_v = 0;
78159d74a35SJustin Hibbits int c;
78259d74a35SJustin Hibbits char *p, *end;
7832cd5e41aSRui Paulo struct sigaction act;
7842cd5e41aSRui Paulo int done = 0;
7852cd5e41aSRui Paulo
7862cd5e41aSRui Paulo g_pname = basename(argv[0]);
7872cd5e41aSRui Paulo argv[0] = g_pname; /* rewrite argv[0] for getopt errors */
788bc96366cSSteven Hartland #ifdef illumos
7892cd5e41aSRui Paulo /*
7902cd5e41aSRui Paulo * Make sure we have the required dtrace_proc privilege.
7912cd5e41aSRui Paulo */
7922cd5e41aSRui Paulo if ((ucp = ucred_get(getpid())) != NULL) {
7932cd5e41aSRui Paulo const priv_set_t *psp;
7942cd5e41aSRui Paulo if ((psp = ucred_getprivset(ucp, PRIV_EFFECTIVE)) != NULL &&
7952cd5e41aSRui Paulo !priv_ismember(psp, PRIV_DTRACE_PROC)) {
7962cd5e41aSRui Paulo fatal("dtrace_proc privilege required\n");
7972cd5e41aSRui Paulo }
7982cd5e41aSRui Paulo
7992cd5e41aSRui Paulo ucred_free(ucp);
8002cd5e41aSRui Paulo }
8016544c919SRui Paulo #endif
8022cd5e41aSRui Paulo
8032cd5e41aSRui Paulo while ((c = getopt(argc, argv, PLOCKSTAT_OPTSTR)) != EOF) {
8042cd5e41aSRui Paulo switch (c) {
8052cd5e41aSRui Paulo case 'n':
8062cd5e41aSRui Paulo errno = 0;
8072cd5e41aSRui Paulo g_nent = strtoul(optarg, &end, 10);
8082cd5e41aSRui Paulo if (*end != '\0' || errno != 0) {
8092cd5e41aSRui Paulo (void) fprintf(stderr, "%s: invalid count "
8102cd5e41aSRui Paulo "'%s'\n", g_pname, optarg);
8112cd5e41aSRui Paulo usage();
8122cd5e41aSRui Paulo }
8132cd5e41aSRui Paulo break;
8142cd5e41aSRui Paulo
8152cd5e41aSRui Paulo case 'p':
8162cd5e41aSRui Paulo opt_p = 1;
8172cd5e41aSRui Paulo break;
8182cd5e41aSRui Paulo
8192cd5e41aSRui Paulo case 'v':
8202cd5e41aSRui Paulo opt_v = 1;
8212cd5e41aSRui Paulo break;
8222cd5e41aSRui Paulo
8232cd5e41aSRui Paulo case 'A':
8242cd5e41aSRui Paulo opt_C = opt_H = 1;
8252cd5e41aSRui Paulo break;
8262cd5e41aSRui Paulo
8272cd5e41aSRui Paulo case 'C':
8282cd5e41aSRui Paulo opt_C = 1;
8292cd5e41aSRui Paulo break;
8302cd5e41aSRui Paulo
8312cd5e41aSRui Paulo case 'H':
8322cd5e41aSRui Paulo opt_H = 1;
8332cd5e41aSRui Paulo break;
8342cd5e41aSRui Paulo
8352cd5e41aSRui Paulo case 'V':
8362cd5e41aSRui Paulo g_opt_V = 1;
8372cd5e41aSRui Paulo break;
8382cd5e41aSRui Paulo
8392cd5e41aSRui Paulo default:
8402cd5e41aSRui Paulo if (strchr(PLOCKSTAT_OPTSTR, c) == NULL)
8412cd5e41aSRui Paulo usage();
8422cd5e41aSRui Paulo }
8432cd5e41aSRui Paulo }
8442cd5e41aSRui Paulo
8452cd5e41aSRui Paulo /*
8462cd5e41aSRui Paulo * We need a command or at least one pid.
8472cd5e41aSRui Paulo */
8482cd5e41aSRui Paulo if (argc == optind)
8492cd5e41aSRui Paulo usage();
8502cd5e41aSRui Paulo
8512cd5e41aSRui Paulo if (opt_C == 0 && opt_H == 0)
8522cd5e41aSRui Paulo opt_C = 1;
8532cd5e41aSRui Paulo
8542cd5e41aSRui Paulo if ((g_dtp = dtrace_open(DTRACE_VERSION, 0, &err)) == NULL)
8552cd5e41aSRui Paulo fatal("failed to initialize dtrace: %s\n",
8562cd5e41aSRui Paulo dtrace_errmsg(NULL, err));
8572cd5e41aSRui Paulo
8582cd5e41aSRui Paulo /*
8592cd5e41aSRui Paulo * The longest string we trace is 23 bytes long -- so 32 is plenty.
8602cd5e41aSRui Paulo */
8612cd5e41aSRui Paulo if (dtrace_setopt(g_dtp, "strsize", "32") == -1)
8622cd5e41aSRui Paulo dfatal("failed to set 'strsize'");
8632cd5e41aSRui Paulo
8642cd5e41aSRui Paulo /*
8652cd5e41aSRui Paulo * 1k should be more than enough for all trace() and printa() actions.
8662cd5e41aSRui Paulo */
8672cd5e41aSRui Paulo if (dtrace_setopt(g_dtp, "bufsize", "1k") == -1)
8682cd5e41aSRui Paulo dfatal("failed to set 'bufsize'");
8692cd5e41aSRui Paulo
8702cd5e41aSRui Paulo /*
8712cd5e41aSRui Paulo * The table we produce has the hottest locks at the top.
8722cd5e41aSRui Paulo */
8732cd5e41aSRui Paulo if (dtrace_setopt(g_dtp, "aggsortrev", NULL) == -1)
8742cd5e41aSRui Paulo dfatal("failed to set 'aggsortrev'");
8752cd5e41aSRui Paulo
8762cd5e41aSRui Paulo /*
8772cd5e41aSRui Paulo * These are two reasonable defaults which should suffice.
8782cd5e41aSRui Paulo */
8792cd5e41aSRui Paulo if (dtrace_setopt(g_dtp, "aggsize", "256k") == -1)
8802cd5e41aSRui Paulo dfatal("failed to set 'aggsize'");
8812cd5e41aSRui Paulo if (dtrace_setopt(g_dtp, "aggrate", "1sec") == -1)
8822cd5e41aSRui Paulo dfatal("failed to set 'aggrate'");
8832cd5e41aSRui Paulo
8842cd5e41aSRui Paulo /*
8852cd5e41aSRui Paulo * Take a second pass through to look for options that set options now
8862cd5e41aSRui Paulo * that we have an open dtrace handle.
8872cd5e41aSRui Paulo */
8882cd5e41aSRui Paulo optind = 1;
8892cd5e41aSRui Paulo while ((c = getopt(argc, argv, PLOCKSTAT_OPTSTR)) != EOF) {
8902cd5e41aSRui Paulo switch (c) {
8912cd5e41aSRui Paulo case 's':
8922cd5e41aSRui Paulo g_opt_s = 1;
8932cd5e41aSRui Paulo if (dtrace_setopt(g_dtp, "ustackframes", optarg) == -1)
8942cd5e41aSRui Paulo dfatal("failed to set 'ustackframes'");
8952cd5e41aSRui Paulo break;
8962cd5e41aSRui Paulo
8972cd5e41aSRui Paulo case 'x':
8982cd5e41aSRui Paulo if ((p = strchr(optarg, '=')) != NULL)
8992cd5e41aSRui Paulo *p++ = '\0';
9002cd5e41aSRui Paulo
9012cd5e41aSRui Paulo if (dtrace_setopt(g_dtp, optarg, p) != 0)
9022cd5e41aSRui Paulo dfatal("failed to set -x %s", optarg);
9032cd5e41aSRui Paulo break;
9042cd5e41aSRui Paulo
9052cd5e41aSRui Paulo case 'e':
9062cd5e41aSRui Paulo errno = 0;
9072cd5e41aSRui Paulo (void) strtoul(optarg, &end, 10);
9082cd5e41aSRui Paulo if (*optarg == '-' || *end != '\0' || errno != 0) {
9092cd5e41aSRui Paulo (void) fprintf(stderr, "%s: invalid timeout "
9102cd5e41aSRui Paulo "'%s'\n", g_pname, optarg);
9112cd5e41aSRui Paulo usage();
9122cd5e41aSRui Paulo }
9132cd5e41aSRui Paulo
9142cd5e41aSRui Paulo /*
9152cd5e41aSRui Paulo * Construct a DTrace enabling that will exit after
9162cd5e41aSRui Paulo * the specified number of seconds.
9172cd5e41aSRui Paulo */
9182cd5e41aSRui Paulo dprog_add("BEGIN\n{\n\tend = timestamp + ");
9192cd5e41aSRui Paulo dprog_add(optarg);
9202cd5e41aSRui Paulo dprog_add(" * 1000000000;\n}\n");
9212cd5e41aSRui Paulo dprog_add("tick-10hz\n/timestamp >= end/\n");
9222cd5e41aSRui Paulo dprog_add("{\n\texit(0);\n}\n");
9232cd5e41aSRui Paulo break;
9242cd5e41aSRui Paulo }
9252cd5e41aSRui Paulo }
9262cd5e41aSRui Paulo
9272cd5e41aSRui Paulo argc -= optind;
9282cd5e41aSRui Paulo argv += optind;
9292cd5e41aSRui Paulo
9302cd5e41aSRui Paulo if (opt_H) {
9312cd5e41aSRui Paulo dprog_add(g_hold_init);
9326544c919SRui Paulo if (!g_opt_s)
9332cd5e41aSRui Paulo dprog_add(g_hold_times);
9342cd5e41aSRui Paulo else
9352cd5e41aSRui Paulo dprog_add(g_hold_histogram);
9362cd5e41aSRui Paulo }
9372cd5e41aSRui Paulo
9382cd5e41aSRui Paulo if (opt_C) {
9392cd5e41aSRui Paulo dprog_add(g_ctnd_init);
9406544c919SRui Paulo if (!g_opt_s)
9412cd5e41aSRui Paulo dprog_add(g_ctnd_times);
9422cd5e41aSRui Paulo else
9432cd5e41aSRui Paulo dprog_add(g_ctnd_histogram);
9442cd5e41aSRui Paulo }
9452cd5e41aSRui Paulo
9462cd5e41aSRui Paulo if (opt_p) {
9472cd5e41aSRui Paulo ulong_t pid;
9482cd5e41aSRui Paulo
9492cd5e41aSRui Paulo if (argc > 1) {
9502cd5e41aSRui Paulo (void) fprintf(stderr, "%s: only one pid is allowed\n",
9512cd5e41aSRui Paulo g_pname);
9522cd5e41aSRui Paulo usage();
9532cd5e41aSRui Paulo }
9542cd5e41aSRui Paulo
9552cd5e41aSRui Paulo errno = 0;
9562cd5e41aSRui Paulo pid = strtoul(argv[0], &end, 10);
9572cd5e41aSRui Paulo if (*end != '\0' || errno != 0 || (pid_t)pid != pid) {
9582cd5e41aSRui Paulo (void) fprintf(stderr, "%s: invalid pid '%s'\n",
9592cd5e41aSRui Paulo g_pname, argv[0]);
9602cd5e41aSRui Paulo usage();
9612cd5e41aSRui Paulo }
9622cd5e41aSRui Paulo
9632cd5e41aSRui Paulo if ((g_pr = dtrace_proc_grab(g_dtp, (pid_t)pid, 0)) == NULL)
9642cd5e41aSRui Paulo dfatal(NULL);
9652cd5e41aSRui Paulo } else {
9666544c919SRui Paulo if ((g_pr = dtrace_proc_create(g_dtp, argv[0], argv, NULL, NULL)) == NULL)
9672cd5e41aSRui Paulo dfatal(NULL);
9682cd5e41aSRui Paulo }
9692cd5e41aSRui Paulo
9702cd5e41aSRui Paulo dprog_compile();
9712cd5e41aSRui Paulo
9722cd5e41aSRui Paulo if (dtrace_handle_proc(g_dtp, &prochandler, NULL) == -1)
9732cd5e41aSRui Paulo dfatal("failed to establish proc handler");
9742cd5e41aSRui Paulo
9752cd5e41aSRui Paulo (void) sigemptyset(&act.sa_mask);
9762cd5e41aSRui Paulo act.sa_flags = 0;
9772cd5e41aSRui Paulo act.sa_handler = intr;
9782cd5e41aSRui Paulo (void) sigaction(SIGINT, &act, NULL);
9792cd5e41aSRui Paulo (void) sigaction(SIGTERM, &act, NULL);
9802cd5e41aSRui Paulo
9812cd5e41aSRui Paulo if (dtrace_go(g_dtp) != 0)
9822cd5e41aSRui Paulo dfatal("dtrace_go()");
9832cd5e41aSRui Paulo
9842cd5e41aSRui Paulo if (dtrace_getopt(g_dtp, "ustackframes", &g_nframes) != 0)
9852cd5e41aSRui Paulo dfatal("failed to get 'ustackframes'");
9862cd5e41aSRui Paulo
9872cd5e41aSRui Paulo dtrace_proc_continue(g_dtp, g_pr);
9882cd5e41aSRui Paulo
9892cd5e41aSRui Paulo if (opt_v)
9902cd5e41aSRui Paulo (void) printf("%s: tracing enabled for pid %d\n", g_pname,
991bc96366cSSteven Hartland #ifdef illumos
9922cd5e41aSRui Paulo (int)Pstatus(g_pr)->pr_pid);
9936544c919SRui Paulo #else
9946544c919SRui Paulo (int)proc_getpid(g_pr));
9956544c919SRui Paulo #endif
9962cd5e41aSRui Paulo
9972cd5e41aSRui Paulo do {
9982cd5e41aSRui Paulo if (!g_intr && !done)
9992cd5e41aSRui Paulo dtrace_sleep(g_dtp);
10002cd5e41aSRui Paulo
10012cd5e41aSRui Paulo if (done || g_intr || g_exited) {
10022cd5e41aSRui Paulo done = 1;
10032cd5e41aSRui Paulo if (dtrace_stop(g_dtp) == -1)
10042cd5e41aSRui Paulo dfatal("couldn't stop tracing");
10052cd5e41aSRui Paulo }
10062cd5e41aSRui Paulo
10072cd5e41aSRui Paulo switch (dtrace_work(g_dtp, stdout, NULL, chewrec, NULL)) {
10082cd5e41aSRui Paulo case DTRACE_WORKSTATUS_DONE:
10092cd5e41aSRui Paulo done = 1;
10102cd5e41aSRui Paulo break;
10112cd5e41aSRui Paulo case DTRACE_WORKSTATUS_OKAY:
10122cd5e41aSRui Paulo break;
10132cd5e41aSRui Paulo default:
10142cd5e41aSRui Paulo dfatal("processing aborted");
10152cd5e41aSRui Paulo }
10162cd5e41aSRui Paulo
10172cd5e41aSRui Paulo } while (!done);
10182cd5e41aSRui Paulo
10192cd5e41aSRui Paulo dtrace_close(g_dtp);
10202cd5e41aSRui Paulo
10212cd5e41aSRui Paulo return (0);
10222cd5e41aSRui Paulo }
1023