From nobody Wed Jan 10 23:32:51 2024 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4T9PH76FsKz56TBC; Wed, 10 Jan 2024 23:32:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4T9PH75PnNz45h7; Wed, 10 Jan 2024 23:32:51 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1704929571; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=AJJ12TdM7aYOtNBe8a9+DntvY9Fy7GXzBlPMH6akHJo=; b=LDkz0zU9dCrTbpWce4RplJXyyhST+sI/mrRg+6effeDpFh3f7FTmpHGWVJMngPPAeHvoKk Drujaz0Xn0P5WgariO8UfkIlLm4hMIG2VUTE87fNjw8GYfoYHprJsyoX3kOsDPop/tH/YL sxTsoFRxrgn/g/fTyieLcu3Kxh7PYxs4ast1j1C1e/HY7V36TjIQ3k3bTnHTcBTuV1+dZ8 RT0A4tcDGg8zhbGY/olXiPoraV1d8ZMWZEIVrPQ7ZSPZNhf382Qcqo1+i1Sbn785MOqPbH +NX9JhQQUaHcOXQeH3+BWrOxLBZNiH7JJ87vlBDx0eYx3VeX1G8lHiRE2ZYOVA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1704929571; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=AJJ12TdM7aYOtNBe8a9+DntvY9Fy7GXzBlPMH6akHJo=; b=M9g80cwfLG7zH6nsrnjtpM5tG0j369gfhbWfSidl1rbJXhBiwDTBy5Z0Yo/Mj1ikTXX/0k kowlCv1GV3KKtmgt//J5/BZqVXOWnx9D5SvhLN3+qLLfJVJkKPmJ9Hwb9K9E76Dv1ZEUYO CyS+NMoOLcgsT2KqKpVrdZhNLxmu377aqYTpAn2G+i87iGUJ1eoM3g9vJ2SeUdxLWavWRe L647BYzLX3dEsrjqJDcanUgCxBvtFQbEUqvHTiUEcWnaAI7q9Q6oVWUBVJ3BQCKNygZFxj Gbmy7HL9oFRRc1/YmFiZnHqYF5ERxVDgheR5lilMKecHAtl6CHimb82MUNanXA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1704929571; a=rsa-sha256; cv=none; b=Cy3t1lo1kEZy3JdtB6/pPTUgwo2qKKVN1TA5UzDMqOQYjTwPKggVnXJEItzDdWg1VpIZQ9 +N9AGL18xCYCPN1bR8TFg4y0xb4x3eP6WlOOE2C+/xYlcO/fyr2tyG0qItLmq36hXyz9IU 0l0AAMwNmQX2MeI99ChaB0raOP1aQnMPYaNw0ddxb8Slf+y1DahJPw0ufUbw64ZcH/zbC9 vQmByy1WxU5eO3AXr7EPUZDLGtKbjgkPq5BoNh0JbXsmmwOCUSwx8/P9w7s7V2KzQ4+JeH 9y9inVG2/U5sjYM7r31CgXo6mi/ZkM0oLLCdr+gKgp+Tes8Z9r1WyjwqiLZ4SQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4T9PH74TGRzvv1; Wed, 10 Jan 2024 23:32:51 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 40ANWpKH097862; Wed, 10 Jan 2024 23:32:51 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 40ANWpYp097859; Wed, 10 Jan 2024 23:32:51 GMT (envelope-from git) Date: Wed, 10 Jan 2024 23:32:51 GMT Message-Id: <202401102332.40ANWpYp097859@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Mark Johnston Subject: git: 93f27766a7e1 - main - dtrace: Add the 'oformat' libdtrace option List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 93f27766a7e1af009c5b1e4ca538632857c91aa1 Auto-Submitted: auto-generated The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=93f27766a7e1af009c5b1e4ca538632857c91aa1 commit 93f27766a7e1af009c5b1e4ca538632857c91aa1 Author: Domagoj Stolfa AuthorDate: 2024-01-03 14:58:01 +0000 Commit: Mark Johnston CommitDate: 2024-01-10 23:14:26 +0000 dtrace: Add the 'oformat' libdtrace option This option can be used to specify a format to use in DTrace output. The following formats are supported: - json - xml - html - none (default DTrace output) This is implemented using libxo and integrated into libdtrace. Client code only works with the following API: - dtrace_oformat_setup(dtrace_hdl_t *) -- to be called when output is starting. - dtrace_oformat_teardown(dtrace_hdl_t *) -- to be called when output is finished - dtrace_oformat(dtrace_hdl_t *) -- check if oformat is enabled. - dtrace_set_outfp(FILE *) -- sets the output file for oformat. - Ensure that oformat is correctly checked in the drop handler and record processing callbacks. This commit also adds tests which check if the generated output is valid (JSON, XML) and extends the dtrace(1) describing the structured output. Reviewed by: markj Discussed with: phil MFC after: 2 months Sponsored by: Innovate UK Differential Revision: https://reviews.freebsd.org/D41745 --- Makefile.inc1 | 3 + cddl/contrib/opensolaris/cmd/dtrace/dtrace.1 | 416 +++++- cddl/contrib/opensolaris/cmd/dtrace/dtrace.c | 72 +- .../dtrace/test/tst/common/oformat/tst.agg.avg.ksh | 66 + .../test/tst/common/oformat/tst.agg.count.ksh | 66 + .../test/tst/common/oformat/tst.agg.llquantize.ksh | 73 + .../test/tst/common/oformat/tst.agg.lquantize.ksh | 73 + .../dtrace/test/tst/common/oformat/tst.agg.max.ksh | 66 + .../dtrace/test/tst/common/oformat/tst.agg.min.ksh | 66 + .../test/tst/common/oformat/tst.agg.quantize.ksh | 73 + .../test/tst/common/oformat/tst.agg.stddev.ksh | 66 + .../dtrace/test/tst/common/oformat/tst.agg.sum.ksh | 66 + .../dtrace/test/tst/common/oformat/tst.aggmod.ksh | 66 + .../test/tst/common/oformat/tst.aggstack.ksh | 66 + .../dtrace/test/tst/common/oformat/tst.aggsym.ksh | 66 + .../test/tst/common/oformat/tst.aggustack.ksh | 66 + .../dtrace/test/tst/common/oformat/tst.aggusym.ksh | 66 + .../dtrace/test/tst/common/oformat/tst.drop.ksh | 61 + .../cmd/dtrace/test/tst/common/oformat/tst.mod.ksh | 57 + .../dtrace/test/tst/common/oformat/tst.print.ksh | 60 + .../dtrace/test/tst/common/oformat/tst.printf.ksh | 57 + .../dtrace/test/tst/common/oformat/tst.printm.ksh | 57 + .../dtrace/test/tst/common/oformat/tst.stack.ksh | 61 + .../cmd/dtrace/test/tst/common/oformat/tst.sym.ksh | 57 + .../dtrace/test/tst/common/oformat/tst.trace.ksh | 66 + .../test/tst/common/oformat/tst.tracemem.ksh | 57 + .../dtrace/test/tst/common/oformat/tst.umod.ksh | 57 + .../dtrace/test/tst/common/oformat/tst.ustack.ksh | 61 + .../dtrace/test/tst/common/oformat/tst.usym.ksh | 57 + .../lib/libdtrace/common/dt_aggregate.c | 17 +- .../opensolaris/lib/libdtrace/common/dt_consume.c | 1540 +++++++++++++++++--- .../opensolaris/lib/libdtrace/common/dt_handle.c | 37 +- .../opensolaris/lib/libdtrace/common/dt_impl.h | 7 + .../opensolaris/lib/libdtrace/common/dt_oformat.h | 34 + .../opensolaris/lib/libdtrace/common/dt_open.c | 3 + .../opensolaris/lib/libdtrace/common/dt_options.c | 14 + .../opensolaris/lib/libdtrace/common/dt_print.c | 266 +++- .../opensolaris/lib/libdtrace/common/dt_printf.h | 6 + .../opensolaris/lib/libdtrace/common/dt_subr.c | 42 + .../opensolaris/lib/libdtrace/common/dtrace.h | 22 + cddl/lib/libdtrace/Makefile | 2 +- cddl/usr.sbin/dtrace/Makefile | 2 +- cddl/usr.sbin/dtrace/tests/common/Makefile | 1 + cddl/usr.sbin/dtrace/tests/common/oformat/Makefile | 42 + cddl/usr.sbin/dtrace/tests/dtrace.test.mk | 2 +- etc/mtree/BSD.tests.dist | 2 + share/mk/src.libnames.mk | 2 +- 47 files changed, 3906 insertions(+), 279 deletions(-) diff --git a/Makefile.inc1 b/Makefile.inc1 index e6a6e9d479d3..34b49ee319ec 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -3139,6 +3139,7 @@ _prebuild_libs= ${_kerberos5_lib_libasn1} \ ${_cddl_lib_libctf} ${_cddl_lib_libzfsbootenv} \ lib/libufs \ lib/libutil lib/libpjdlog ${_lib_libypclnt} lib/libz lib/msun \ + lib/libxo \ ${_secure_lib_libcrypto} ${_secure_lib_libssl} \ ${_lib_libldns} ${_secure_lib_libssh} @@ -3194,6 +3195,7 @@ _generic_libs+= ${_DIR} .endfor lib/libtacplus__L: lib/libmd__L lib/libpam/libpam__L +lib/libxo__L: lib/libutil__L .if ${MK_CDDL} != "no" _cddl_lib_libumem= cddl/lib/libumem @@ -3234,6 +3236,7 @@ lib/libbe__L: cddl/lib/libzfs__L cddl/lib/libzfsbootenv__L _cddl_lib_libctf= cddl/lib/libctf _cddl_lib= cddl/lib cddl/lib/libctf__L: lib/libz__L cddl/lib/libspl__L +cddl/lib/libdtrace__L: lib/libxo__L .endif # cddl/lib/libdtrace requires lib/libproc and lib/librtld_db _prebuild_libs+= lib/libprocstat lib/libproc lib/librtld_db diff --git a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1 b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1 index 1745519c2c1a..ab8c672a95a1 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1 +++ b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1 @@ -18,7 +18,9 @@ .\" CDDL HEADER END .\" Copyright (c) 2006, Sun Microsystems, Inc. All Rights Reserved. .\" -.Dd February 24, 2023 +.\" $FreeBSD$ +.\" +.Dd September 8, 2023 .Dt DTRACE 1 .Os .Sh NAME @@ -27,7 +29,8 @@ .Sh SYNOPSIS .Nm .Op Fl 32 | Fl 64 -.Op Fl aACdeFGhHlqSvVwZ +.Op Fl aACdeFGhHlOqSvVwZ +.Op Fl -libxo .Op Fl b Ar bufsz .Op Fl c Ar cmd .Op Fl D Ar name Op Ns = Ns value @@ -355,6 +358,11 @@ writing D programs. The specified .Ar path is added after the default library search path. +.It Fl -libxo +Generate output via +.Xr libxo 3 . +This option is the same as specifying +.Sy oformat . .It Fl m Oo Ar provider : Oc Ar module Oo Oo Ar predicate Oc Ar action Oc Specify module name to trace or list .Fl ( l @@ -398,6 +406,14 @@ argument can be suffixed with an optional D probe clause. More than one .Fl n option can be specified on the command line at a time. +.It Fl O +This option causes +.Nm +to print all the aggregations upon exiting if +.Sy oformat +or +.Fl -libxo +are specified. .It Fl o Ar output Specify the .Ar output @@ -650,6 +666,32 @@ Number of whitespace characters to use when indenting and .Fn ustack output. +.It Sy oformat Ns = Ns Ar format +Specify the format to use for output. +Setting +.Sy oformat +to +.Ql text +makes +.Nm +use regular human-readable output which is its default behavior. +The options passed to +.Sy oformat +are directly forwarded to +.Xr libxo 3 . +Some of the supported formatters include +.Ql json , +.Ql xml +and +.Ql html . +Note that this option will cause +.Nm +to not produce any output unless printing functions are explicitly called, +or the +.Fl O +flag is specified. +For more information see +.Sx STRUCTURED OUTPUT . .It Sy statusrate Ns = Ns Ar time Rate of status checking. .It Sy switchrate Ns = Ns Ar time @@ -776,6 +818,376 @@ or .Fl i options) contain descriptions that do not match any known probes. .El +.Sh STRUCTURED OUTPUT +.Nm +supports structured output using +.Xr libxo 3 . +The output will always have a top-level object called +.Dq dtrace , +followed by a list of objects +.Dq probes . +Each of the probe objects will to have a timestamp which is generated at +output time rather than probe firing time, an identifier for the CPU on +which the probe was executed, and the probe's full specification: +.Bd -literal +{ + "dtrace": { + "probes": [ + { + "timestamp": ..., + "cpu": ..., + "id": ..., + "provider": ..., + "module": ..., + "function": ..., + "name": ..., + "output": [ + ... (script-specific output) + ] + } + ] + } +} + + + + + ... + ... + ... + ... + ... + ... + ... + + ... (script-specific output) + + + +.Ed +.Pp +It is also possible for XML output to take the following form if some +of the fields are empty (in this example, module and function values +are absent): +.Bd -literal + + + + ... + + + ... + + ... (script-specific output) + + + +.Ed +.Pp +Similarly, +.Sy oformat +can be used to generate HTML: +.Bd -literal +
+
...
+
+
...
+
+
...
+
+
...
+
+
...
+
+
...
+
+
...
+
...
+
+.Ed +.Pp +Unlike JSON and XML, the +.Dq output +array is not present. +Instead, data is simply formatted into a div of class +.Dq data +and a data-tag is associated with each of the keys. +.Pp +The +.Dq output +array's contents depend on the probes' actions and is explained below. +The examples here are presented in JSON form as opposed to XML or HTML, +however the conversion explained above applies for all output formats. +.Pp +Any scalar output, such as output produced by the +.Fn trace +action is of form: +.Bd -literal +{ + "value": ... +} +.Ed +.Pp +The +.Fn printf +action begins with an object containing the formatted output of the +.Fn printf +action. +Subsequent objects contains the value of each of the arguments to +.Fn printf +in its raw form as if the +.Fn trace +action was used instead. +A +.Fn printf +statement which contains no arguments other than the message will only have +one object following the message object and its value will always be 0. +This is an artefact of the implementation and can safely be ignored. +.Bd -literal +# dtrace --libxo json,pretty -n 'BEGIN { printf("... %Y, ..", walltimestamp); }' + +{ + "message": "... 2023 Sep 7 16:49:02, .." +}, +{ + "value": 1694105342633402400 +}, +{ + ... +} +.Ed +.Pp +Scalar aggregations are aggregations which produce a single value for a given +key. +These aggregations include +.Fn count , +.Fn min , +.Fn max , +.Fn stddev +and +.Fn sum . +Each one of them is represented by the key containing their name. +For example, the output of a +.Fn stddev +aggregation will contain a key +.Dq stddev +inside an +.Dq aggregation-data +object: +.Bd -literal +{ + "aggregation-data": [ + { + "keys": [ + ... + ], + "stddev": ... + } + ], + "aggregation-name": ... +} +.Ed +.Pp +The +.Dq keys +field remains consistent across all aggregations, however +.Fn quantize , +.Fn lquantize +and +.Fn llquantize +need to be treated differently. +.Sy oformat +will create a new array of objects called +.Dq buckets . +Each of the objects contains a +.Dq value +and a +.Dq count +field which are +the left-hand side and the right-hand side of human-readable +.Nm +output respectively. +The full object has the following format: +.Bd -literal +{ + "aggregation-data": [ + ... + { + "keys": [ + ... + ], + "buckets": [ + { + "value": 32, + "count": 0 + }, + { + "value": 64, + "count": 17 + }, + ... + ], + }, + ... + ] + "aggregation-name": ... +} +.Ed +.Pp +Similar to scalar aggregations, named scalar actions such as +.Fn mod , +.Fn umod , +.Fn usym , +.Fn tracemem +and +.Fn printm +will output an object with the key being equal to the +name of the action. +For example, +.Fn printm +output would produce the following object: +.Bd -literal +{ + "printm": "0x4054171100" +} +.Ed +.Pp +.Fn sym +is slightly different. +While it will create a +.Dq sym +field which contains its value, in some cases it will also create additional +fields +.Dq object , +.Dq name +and +.Dq offset : +.Bd -literal +# dtrace -x oformat=json,pretty -On 'BEGIN { sym((uintptr_t)&`prison0); }' + +{ + "sym": "kernel`prison0", + "object": "kernel", + "name": "prison0" +} + +# dtrace --libxo json,pretty -On 'BEGIN { sym((uintptr_t)curthread); }' + +{ + "sym": "0xfffffe00c18d2000", + "offset": "0xfffffe00c18d2000" +} +.Ed +.Pp +.Fn stack +and +.Fn ustack +actions unroll each of the stack frames into its own object in an array. +The only real difference between them is that the +.Fn stack +action will produce a list called +.Dq stack-frames +while +.Fn ustack +will produce one called +.Dq ustack-frames . +The following is an example of their +.Sy oformat +output: +.Bd -literal +{ + "stack-frames": [ + { + "symbol": "dtrace.ko`dtrace_dof_create+0x35", + "module": "dtrace.ko", + "name": "dtrace_dof_create", + "offset": "0x35" + }, + { + "symbol": "dtrace.ko`dtrace_ioctl+0x81c", + "module": "dtrace.ko", + "name": "dtrace_ioctl", + "offset": "0x81c" + }, + ... + ] +} + +{ + "ustack-frames": [ + { + "symbol": "libc.so.7`ioctl+0xa", + "module": "libc.so.7", + "name": "ioctl", + "offset": "0xa" + }, + { + "symbol": "libdtrace.so.2`dtrace_go+0xf3", + "module": "libdtrace.so.2", + "name": "dtrace_go", + "offset": "0xf3" + }, + ... + ] +} +.Ed +.Pp +The +.Fn print +action produces a +.Dq type +list in the following form: +.Bd -literal +{ + "type": [ + { + "object-name": "kernel", + "name": "struct thread", + "ctfid": 2372 + }, + { + "member-name": "td_lock", + "name": "struct mtx *volatile", + "ctfid": 2035, + "value": "0xffffffff82158440" + }, + ... +} +.Ed +.Pp +If the type is invalid, a +.Dq warning +object will be produced containing the diagnostic message as well as two +possible optional fields: +.Dq type-identifier +which contains the CTF identifier of the type and +.Dq size containing the size of an integer, enum or float. +The fields generated will depend on the kind of error that was encountered +while processing the trace data. +.Pp +Finally, +.Sy oformat +provides a special pseudo-probe to represent drops. +As +.Nm +polls for various kinds of drops +.Sy oformat +will produce output similar to the following in order to represent drops: +.Bd -literal +{ + "cpu": -1, + "id": -1, + "provider": "dtrace", + "module": "INTERNAL", + "function": "INTERNAL", + "name": "DROP", + "timestamp": ..., + "count": ..., + "total": ..., + "kind": 2, + "msg": "... dynamic variable drops\n" +} +.Ed .Sh OPERANDS You can specify zero or more additional arguments on the .Nm diff --git a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c index cdc476a43b08..dc68c6ef5f72 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c +++ b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.c @@ -26,6 +26,7 @@ /* * Copyright (c) 2012 by Delphix. All rights reserved. * Copyright (c) 2013, Joyent, Inc. All rights reserved. + * Copyright (c) 2023, Domagoj Stolfa. All rights reserved. */ #include @@ -55,6 +56,9 @@ #include #endif +#undef NORETURN /* needed because libxo redefines it */ +#include + typedef struct dtrace_cmd { void (*dc_func)(struct dtrace_cmd *); /* function to compile arg */ dtrace_probespec_t dc_spec; /* probe specifier context */ @@ -77,7 +81,7 @@ typedef struct dtrace_cmd { #define E_USAGE 2 static const char DTRACE_OPTSTR[] = - "3:6:aAb:Bc:CdD:ef:FGhHi:I:lL:m:n:o:p:P:qs:SU:vVwx:X:Z"; + "3:6:aAb:Bc:CdD:ef:FGhHi:I:lL:m:n:o:Op:P:qs:SU:vVwx:X:Z"; static char **g_argv; static int g_argc; @@ -167,6 +171,7 @@ usage(FILE *fp) "\t-m enable or list probes matching the specified module name\n" "\t-n enable or list probes matching the specified probe name\n" "\t-o set output file\n" + "\t-O print output upon exiting (specific to oformat)\n" "\t-p grab specified process-ID and cache its symbol tables\n" "\t-P enable or list probes matching the specified provider name\n" "\t-q set quiet mode (only output explicitly traced data)\n" @@ -907,7 +912,10 @@ errhandler(const dtrace_errdata_t *data, void *arg) static int drophandler(const dtrace_dropdata_t *data, void *arg) { - error(data->dtdda_msg); + if (!dtrace_oformat(g_dtp)) { + error(data->dtdda_msg); + } + return (DTRACE_HANDLE_OK); } @@ -1126,7 +1134,9 @@ chew(const dtrace_probedata_t *data, void *arg) } if (!g_flowindent) { - if (!g_quiet) { + if (dtrace_oformat(g_dtp)) { + dtrace_oformat_probe(g_dtp, data, cpu, pd); + } else if (!g_quiet) { char name[DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 2]; (void) snprintf(name, sizeof (name), "%s:%s", @@ -1313,7 +1323,8 @@ main(int argc, char *argv[]) g_ofp = stdout; int done = 0, mode = 0; - int err, i, c; + int err, i, c, new_argc, libxo_specified; + int print_upon_exit = 0; char *p, **v; struct ps_prochandle *P; pid_t pid; @@ -1336,6 +1347,15 @@ main(int argc, char *argv[]) (g_psv = malloc(sizeof (struct ps_prochandle *) * argc)) == NULL) fatal("failed to allocate memory for arguments"); + new_argc = xo_parse_args(argc, argv); + if (new_argc < 0) + return (usage(stderr)); + + if (new_argc != argc) + libxo_specified = 1; + + argc = new_argc; + g_argv[g_argc++] = argv[0]; /* propagate argv[0] to D as $0/$$0 */ argv[0] = g_pname; /* rewrite argv[0] for getopt errors */ @@ -1532,6 +1552,10 @@ main(int argc, char *argv[]) } else if (g_mode == DMODE_ANON) (void) dtrace_setopt(g_dtp, "linkmode", "primary"); + + if (libxo_specified) + dtrace_oformat_configure(g_dtp); + /* * Now that we have libdtrace open, make a second pass through argv[] * to perform any dtrace_setopt() calls and change any compiler flags. @@ -1624,6 +1648,10 @@ main(int argc, char *argv[]) dcp->dc_arg = optarg; break; + case 'O': + print_upon_exit = 1; + break; + case 'q': if (dtrace_setopt(g_dtp, "quiet", 0) != 0) dfatal("failed to set -q"); @@ -1765,6 +1793,11 @@ main(int argc, char *argv[]) (void) dtrace_getopt(g_dtp, "quiet", &opt); g_quiet = opt != DTRACEOPT_UNSET; + if (dtrace_oformat(g_dtp)) { + if (dtrace_setopt(g_dtp, "quiet", 0) != 0) + dfatal("failed to set quiet (caused by oformat)"); + } + /* * Now make a fifth and final pass over the options that have been * turned into programs and saved in g_cmdv[], performing any mode- @@ -1777,6 +1810,9 @@ main(int argc, char *argv[]) if (g_ofile != NULL && (g_ofp = fopen(g_ofile, "a")) == NULL) fatal("failed to open output file '%s'", g_ofile); + if (dtrace_oformat(g_dtp)) + dtrace_set_outfp(g_ofp); + for (i = 0; i < g_cmdc; i++) exec_prog(&g_cmdv[i]); @@ -1811,6 +1847,9 @@ main(int argc, char *argv[]) if ((g_ofp = fopen(g_ofile, "a")) == NULL) fatal("failed to open output file '%s'", g_ofile); + if (dtrace_oformat(g_dtp)) + dtrace_set_outfp(g_ofp); + for (i = 0; i < g_cmdc; i++) { anon_prog(&g_cmdv[i], dtrace_dof_create(g_dtp, g_cmdv[i].dc_prog, 0), i); @@ -1971,12 +2010,21 @@ main(int argc, char *argv[]) g_pslive = g_psc; /* count for prochandler() */ + dtrace_oformat_setup(g_dtp); do { if (!g_intr && !done) dtrace_sleep(g_dtp); #ifdef __FreeBSD__ - if (g_siginfo) { + /* + * XXX: Supporting SIGINFO with oformat makes little sense, as + * it can't really produce sensible DTrace output. + * + * If needed, we could support it by having an imaginary + * "SIGINFO" probe that we can construct in the output but leave + * it out for now. + */ + if (g_siginfo && !dtrace_oformat(g_dtp)) { (void)dtrace_aggregate_print(g_dtp, g_ofp, NULL); g_siginfo = 0; } @@ -2013,14 +2061,24 @@ main(int argc, char *argv[]) clearerr(g_ofp); } while (!done); - oprintf("\n"); + if (!dtrace_oformat(g_dtp)) + oprintf("\n"); - if (!g_impatient) { + /* + * Since there is no way to format a probe here and machine-readable + * output makes little sense without explicitly asking for it, we print + * nothing upon Ctrl-C if oformat is specified. If the user wishes to + * get output upon exit, they must write an explicit dtrace:::END probe + * to do so. + */ + if ((!g_impatient && !dtrace_oformat(g_dtp)) || + (!g_impatient && print_upon_exit)) { if (dtrace_aggregate_print(g_dtp, g_ofp, NULL) == -1 && dtrace_errno(g_dtp) != EINTR) dfatal("failed to print aggregations"); } + dtrace_oformat_teardown(g_dtp); dtrace_close(g_dtp); return (g_status); } diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.avg.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.avg.ksh new file mode 100644 index 000000000000..daf5c7f4e9bb --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.avg.ksh @@ -0,0 +1,66 @@ +#!/usr/bin/ksh +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2023 Domagoj Stolfa +# + +bname=`basename $0` +dtraceout=/tmp/dtrace.$bname + +script() +{ + $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__ +syscall:::entry +{ + @[probefunc] = avg(tid); +} + +tick-5s +{ + exit(0); +} + +END +{ + printa(@); +} +__EOF__ +} + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +script json +jq . $dtraceout.json + +if [ $? != 0 ]; then + echo $bname: failed to produce valid JSON. see $dtraceout.json + exit 1 +fi + +script xml +xmllint $dtraceout.xml + +if [ $? != 0 ]; then + echo $bname: failed to produce valid XML. see $dtraceout.xml + exit 1 +fi + +rm $dtraceout.json +rm $dtraceout.xml + +exit 0 diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.count.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.count.ksh new file mode 100644 index 000000000000..ab7c5fa28471 --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.count.ksh @@ -0,0 +1,66 @@ +#!/usr/bin/ksh +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2023 Domagoj Stolfa +# + +bname=`basename $0` +dtraceout=/tmp/dtrace.$bname + +script() +{ + $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__ +syscall:::entry +{ + @[execname] = count(); +} + +tick-5s +{ + exit(0); +} + +END +{ + printa(@); +} +__EOF__ +} + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +script json +jq . $dtraceout.json + +if [ $? != 0 ]; then + echo $bname: failed to produce valid JSON. see $dtraceout.json + exit 1 +fi + +script xml +xmllint $dtraceout.xml + +if [ $? != 0 ]; then + echo $bname: failed to produce valid XML. see $dtraceout.xml + exit 1 +fi + +rm $dtraceout.json +rm $dtraceout.xml + +exit 0 diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.llquantize.ksh b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.llquantize.ksh new file mode 100644 index 000000000000..380335de000a --- /dev/null +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/oformat/tst.agg.llquantize.ksh @@ -0,0 +1,73 @@ +#!/usr/bin/ksh +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright (c) 2023 Domagoj Stolfa +# + +bname=`basename $0` +dtraceout=/tmp/dtrace.$bname + +script() +{ + $dtrace -o $dtraceout.$1 -x oformat=$1 -s /dev/stdin <<__EOF__ +syscall:::entry +{ + self->ts = timestamp; +} + +syscall:::return +/self->ts/ +{ + @[probefunc] = llquantize(timestamp - self->ts, 2, 1, 32, 32); + self->ts = 0; +} + +tick-5s +{ + exit(0); +} + +END +{ + printa(@); +} +__EOF__ +} + +if [ $# != 1 ]; then + echo expected one argument: '<'dtrace-path'>' + exit 2 +fi + +dtrace=$1 + +script json +jq . $dtraceout.json + +if [ $? != 0 ]; then + echo $bname: failed to produce valid JSON. see $dtraceout.json + exit 1 +fi + +script xml +xmllint $dtraceout.xml + +if [ $? != 0 ]; then + echo $bname: failed to produce valid XML. see $dtraceout.xml + exit 1 *** 4641 LINES SKIPPED ***