[DTrace-devel] [PATCH REVIEW 4/4] consume, cg: implement speculations
Nick Alcock
nick.alcock at oracle.com
Thu Sep 9 04:13:23 PDT 2021
This works by tracking live speculations in a specs map containing
dt_bpf_specs_t, each of which tracks the number of buffers written and
whether a commit/discard has been called on it. (bpf/speculation.c,
which finds free speculations, is limited to 16 speculations and needs
adjusting when BPF loops work). Successful speculate()s record the ID
of the active speculation in the clause header. When a commit happens,
a COMMIT/DISCARD record is written.
At consume time, buffers with active speculate()s are hived off into a
list of dt_spec_bufs_t under a dt_spec_bufs_head_t (when peeking, this
is only done on the first peek, identified via the CONSUME_PEEK_START
peekflag); when a commit/discard hits for a given speculation, the efunc
invocation etc is suppressed if need be (discards can be followed by
data-recording actions, in which case the efunc is not suppressed), and
the specs map entry for this speculation is sucked into the
dt_spec_bufs_head and the head chained into the dt_spec_bufs_draining
list. This list is traversed on every consume, and any new spec bufs
committed (as if just received from the ring buffer) or discarded
appropriately.
Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
---
bpf/Build | 3 +
bpf/speculation.c | 63 +++
bpf/speculation_set_drainable.c | 43 ++
bpf/speculation_speculate.c | 47 ++
libdtrace/dt_bpf.c | 22 +
libdtrace/dt_bpf.h | 2 +
libdtrace/dt_bpf_maps.h | 9 +
libdtrace/dt_cc.c | 3 +
libdtrace/dt_cg.c | 182 +++++--
libdtrace/dt_consume.c | 513 ++++++++++++++++--
libdtrace/dt_dlibs.c | 5 +
libdtrace/dt_errtags.h | 2 +-
libdtrace/dt_impl.h | 32 ++
libdtrace/dt_open.c | 19 +-
libdtrace/dt_peb.h | 1 +
libdtrace/dtrace.h | 13 +-
.../speculation/err.CommitWithInvalid.d | 40 ++
.../speculation/err.CommitWithInvalid.r | 3 +
.../err.D_ACT_SPEC.SpeculateWithCopyOut.d | 2 +-
.../err.D_ACT_SPEC.SpeculateWithCopyOutStr.d | 2 +-
.../err.D_COMM_COMM.CommitAftCommit.d | 61 ---
.../err.D_COMM_COMM.CommitAftCommit.r | 2 -
.../err.D_COMM_COMM.DisjointCommit.d | 81 ---
.../err.D_COMM_COMM.DisjointCommit.r | 2 -
...tAftDiscard.d => err.DiscardWithInvalid.d} | 26 +-
.../speculation/err.DiscardWithInvalid.r | 3 +
.../speculation/err.SpecSizeVariations1.d | 59 --
.../speculation/err.SpecSizeVariations1.r | 2 -
.../speculation/err.SpecSizeVariations2.d | 59 --
.../speculation/err.SpecSizeVariations2.r | 2 -
.../speculation/tst.CommitAfterDiscard.d | 9 +-
.../speculation/tst.CommitAfterDiscard.r | 2 +-
.../speculation/tst.CommitCommitCommit.d | 58 ++
.../speculation/tst.CommitCommitCommit.r | 5 +
.../speculation/tst.CommitDiscard4x.d | 99 ++++
.../speculation/tst.CommitDiscard4x.r | 6 +
.../speculation/tst.CommitWithInactive.d | 38 ++
.../speculation/tst.CommitWithInactive.r | 1 +
.../unittest/speculation/tst.CommitWithZero.d | 11 +-
.../unittest/speculation/tst.CommitWithZero.r | 4 -
.../speculation/tst.DataRecAftDiscard.d | 5 +-
.../speculation/tst.DiscardAftCommit.d | 12 +-
.../speculation/tst.DiscardAftCommit.r | 2 +-
.../speculation/tst.DiscardAftDataRec.d | 3 +-
.../speculation/tst.DiscardAftDiscard.d | 7 +-
...AftDiscard.d => tst.DiscardWithInactive.d} | 26 +-
.../speculation/tst.DiscardWithInactive.r | 1 +
.../speculation/tst.DiscardWithZero.d | 12 +-
.../speculation/tst.DiscardWithZero.r | 4 -
.../unittest/speculation/tst.ExitAftDiscard.d | 1 -
test/unittest/speculation/tst.NoSpecBuffer.d | 6 +-
test/unittest/speculation/tst.NoSpecBuffer.r | 2 -
test/unittest/speculation/tst.SingleCPU.d | 69 +++
test/unittest/speculation/tst.SingleCPU.r | 17 +
.../speculation/tst.SpecSizeVariations3.d | 59 --
.../speculation/tst.SpecSizeVariations3.r | 3 -
.../speculation/tst.SpecSizeVariations4.d | 16 +-
.../speculation/tst.SpecSizeVariations4.r | 2 +-
.../speculation/tst.SpecSizeVariations5.d | 12 +-
.../speculation/tst.SpecSizeVariations5.r | 8 +-
.../speculation/tst.SpeculationCommit.d | 5 +-
...mmit.d => tst.SpeculationCommitNotQuiet.d} | 11 +-
.../tst.SpeculationCommitNotQuiet.r | 10 +
.../speculation/tst.SpeculationDefault.d | 31 ++
.../speculation/tst.SpeculationDefault.r | 5 +
.../tst.SpeculationDefaultCommit.d | 38 ++
.../tst.SpeculationDefaultCommit.r | 6 +
.../tst.SpeculationDefaultDiscard.d | 37 ++
.../tst.SpeculationDefaultDiscard.r | 5 +
.../speculation/tst.SpeculationDiscard.d | 7 +-
.../speculation/tst.SpeculationDiscard.r | 2 +-
...ard.d => tst.SpeculationDiscardNotQuiet.d} | 10 +-
.../tst.SpeculationDiscardNotQuiet.r | 8 +
test/unittest/speculation/tst.SpeculationID.d | 1 -
.../speculation/tst.SpeculationWithZero.d | 6 +-
.../speculation/tst.SpeculationWithZero.r | 3 -
.../unittest/speculation/tst.TwoSpecBuffers.d | 8 +-
.../unittest/speculation/tst.TwoSpecBuffers.r | 4 +-
test/unittest/speculation/tst.negcommit.d | 1 -
test/unittest/speculation/tst.negcommit.r | 2 +-
test/unittest/speculation/tst.zerosize.d | 1 +
81 files changed, 1447 insertions(+), 557 deletions(-)
create mode 100644 bpf/speculation.c
create mode 100644 bpf/speculation_set_drainable.c
create mode 100644 bpf/speculation_speculate.c
create mode 100644 test/unittest/speculation/err.CommitWithInvalid.d
create mode 100644 test/unittest/speculation/err.CommitWithInvalid.r
delete mode 100644 test/unittest/speculation/err.D_COMM_COMM.CommitAftCommit.d
delete mode 100644 test/unittest/speculation/err.D_COMM_COMM.CommitAftCommit.r
delete mode 100644 test/unittest/speculation/err.D_COMM_COMM.DisjointCommit.d
delete mode 100644 test/unittest/speculation/err.D_COMM_COMM.DisjointCommit.r
copy test/unittest/speculation/{tst.ExitAftDiscard.d => err.DiscardWithInvalid.d} (51%)
create mode 100644 test/unittest/speculation/err.DiscardWithInvalid.r
delete mode 100644 test/unittest/speculation/err.SpecSizeVariations1.d
delete mode 100644 test/unittest/speculation/err.SpecSizeVariations1.r
delete mode 100644 test/unittest/speculation/err.SpecSizeVariations2.d
delete mode 100644 test/unittest/speculation/err.SpecSizeVariations2.r
create mode 100644 test/unittest/speculation/tst.CommitCommitCommit.d
create mode 100644 test/unittest/speculation/tst.CommitCommitCommit.r
create mode 100644 test/unittest/speculation/tst.CommitDiscard4x.d
create mode 100644 test/unittest/speculation/tst.CommitDiscard4x.r
create mode 100644 test/unittest/speculation/tst.CommitWithInactive.d
create mode 100644 test/unittest/speculation/tst.CommitWithInactive.r
copy test/unittest/speculation/{tst.ExitAftDiscard.d => tst.DiscardWithInactive.d} (51%)
create mode 100644 test/unittest/speculation/tst.DiscardWithInactive.r
create mode 100644 test/unittest/speculation/tst.SingleCPU.d
create mode 100644 test/unittest/speculation/tst.SingleCPU.r
delete mode 100644 test/unittest/speculation/tst.SpecSizeVariations3.d
delete mode 100644 test/unittest/speculation/tst.SpecSizeVariations3.r
copy test/unittest/speculation/{tst.SpeculationCommit.d => tst.SpeculationCommitNotQuiet.d} (78%)
create mode 100644 test/unittest/speculation/tst.SpeculationCommitNotQuiet.r
create mode 100644 test/unittest/speculation/tst.SpeculationDefault.d
create mode 100644 test/unittest/speculation/tst.SpeculationDefault.r
create mode 100644 test/unittest/speculation/tst.SpeculationDefaultCommit.d
create mode 100644 test/unittest/speculation/tst.SpeculationDefaultCommit.r
create mode 100644 test/unittest/speculation/tst.SpeculationDefaultDiscard.d
create mode 100644 test/unittest/speculation/tst.SpeculationDefaultDiscard.r
copy test/unittest/speculation/{tst.SpeculationDiscard.d => tst.SpeculationDiscardNotQuiet.d} (71%)
create mode 100644 test/unittest/speculation/tst.SpeculationDiscardNotQuiet.r
This is the majority of the work: it could possibly be split into two
pieces (speculations cg+consume, peek_only revamp) but they are
entwined enough that it felt too annoying to do that.
diff --git a/bpf/Build b/bpf/Build
index e08a28b67771..46d90733bbda 100644
--- a/bpf/Build
+++ b/bpf/Build
@@ -26,6 +26,9 @@ bpf_dlib_SOURCES = \
get_bvar.c \
get_tvar.c set_tvar.c \
probe_error.c \
+ speculation.c \
+ speculation_speculate.c \
+ speculation_set_drainable.c \
strnlen.c \
varint.c
diff --git a/bpf/speculation.c b/bpf/speculation.c
new file mode 100644
index 000000000000..d42152d8075d
--- /dev/null
+++ b/bpf/speculation.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf-helpers.h>
+#include <dt_bpf_maps.h>
+
+#ifndef noinline
+# define noinline __attribute__((noinline))
+#endif
+
+extern struct bpf_map_def specs;
+extern uint64_t NSPEC;
+
+noinline uint32_t dt_speculation(void)
+{
+ uint32_t id;
+ dt_bpf_specs_t zero;
+
+ __builtin_memset(&zero, 0, sizeof (dt_bpf_specs_t));
+
+#if 1 /* Loops are broken in BPF right now */
+#define SEARCH(n) \
+ do { \
+ if (n > (uint64_t) &NSPEC) \
+ return 0; \
+ id = (n); \
+ if (bpf_map_update_elem(&specs, &id, &zero, \
+ BPF_NOEXIST) == 0) \
+ return id; \
+ } while (0);
+
+ SEARCH(1);
+ SEARCH(2);
+ SEARCH(3);
+ SEARCH(4);
+ SEARCH(5);
+ SEARCH(6);
+ SEARCH(7);
+ SEARCH(8);
+ SEARCH(9);
+ SEARCH(10);
+ SEARCH(11);
+ SEARCH(12);
+ SEARCH(13);
+ SEARCH(14);
+ SEARCH(15);
+ SEARCH(16);
+#else
+ /*
+ * Waiting on a verifier that can handle loops
+ */
+ for (id = 1; id <= (uint64_t) &NSPEC; id++) {
+ if (bpf_map_update_elem(&specs, &id, &zero,
+ BPF_NOEXIST) == 0)
+ return id;
+ }
+#endif
+
+ return 0;
+}
diff --git a/bpf/speculation_set_drainable.c b/bpf/speculation_set_drainable.c
new file mode 100644
index 000000000000..55bb5ce45d14
--- /dev/null
+++ b/bpf/speculation_set_drainable.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <linux/bpf.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <bpf-helpers.h>
+#include <dt_bpf_maps.h>
+#include <dtrace/faults_defines.h>
+#include <asm/errno.h>
+#include <stdatomic.h>
+
+#include "probe_error.h"
+
+#ifndef noinline
+# define noinline __attribute__((noinline))
+#endif
+
+extern struct bpf_map_def specs;
+extern uint64_t NSPEC;
+
+/* Returns -1 on error. */
+
+noinline int32_t
+dt_speculation_set_drainable(dt_dctx_t *dctx, uint32_t id)
+{
+ dt_bpf_specs_t *spec;
+
+ /*
+ * Arguably redundant to BPF_EXIST, but that doesn't seem to return
+ * -EEXIST as one might hope.
+ */
+ if ((spec = bpf_map_lookup_elem(&specs, &id)) == NULL) {
+ if (id <= (uint64_t) &NSPEC)
+ return 0;
+ dt_probe_error(dctx, -1, DTRACEFLT_ILLOP, 0);
+ return -1;
+ }
+ spec->draining = 1;
+
+ return 0;
+}
diff --git a/bpf/speculation_speculate.c b/bpf/speculation_speculate.c
new file mode 100644
index 000000000000..2cb8feefef79
--- /dev/null
+++ b/bpf/speculation_speculate.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <linux/bpf.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <bpf-helpers.h>
+#include <dt_bpf_maps.h>
+#include <dtrace/faults_defines.h>
+#include <asm/errno.h>
+#include <stdatomic.h>
+
+#include "probe_error.h"
+
+#ifndef noinline
+# define noinline __attribute__((noinline))
+#endif
+
+extern struct bpf_map_def specs;
+
+/*
+ * We consider a speculation ID usable only if it exists in the speculation map
+ * (indicating that speculation() has returned it) with a a zero read value
+ * (indicating that neither commit() nor discard() have been called for it).
+ * We bump the written value by one to indicate that another speculative buffer
+ * is (or will soon be, once this clause terminates and its epilogue runs)
+ * available for draining.
+ */
+noinline int32_t
+dt_speculation_speculate(uint32_t id)
+{
+ dt_bpf_specs_t *spec;
+
+ if ((spec = bpf_map_lookup_elem(&specs, &id)) == NULL)
+ return -1;
+
+ /*
+ * Spec already being drained: do not continue to emit new
+ * data into it.
+ */
+ if (spec->draining)
+ return -1;
+
+ __atomic_add_fetch(&spec->written, 1, __ATOMIC_RELAXED);
+ return 0;
+}
diff --git a/libdtrace/dt_bpf.c b/libdtrace/dt_bpf.c
index 8195cd07aac3..bd5e55acd9e2 100644
--- a/libdtrace/dt_bpf.c
+++ b/libdtrace/dt_bpf.c
@@ -71,6 +71,20 @@ int dt_bpf_map_lookup(int fd, const void *key, void *val)
return bpf(BPF_MAP_LOOKUP_ELEM, &attr);
}
+/*
+ * Delete the given key from the map referenced by the given fd.
+ */
+int dt_bpf_map_delete(int fd, const void *key)
+{
+ union bpf_attr attr;
+
+ memset(&attr, 0, sizeof(attr));
+ attr.map_fd = fd;
+ attr.key = (uint64_t)(unsigned long)key;
+
+ return bpf(BPF_MAP_DELETE_ELEM, &attr);
+}
+
/*
* Store the (key, value) pair in the map referenced by the given fd.
*/
@@ -170,6 +184,9 @@ populate_probes_map(dtrace_hdl_t *dtp, int fd)
* element (key 0). Every aggregation is stored with two copies
* of its data to provide a lockless latch-based mechanism for
* atomic reading and writing.
+ * - specs: Map associating speculation IDs with a dt_bpf_specs_t struct
+ * giving the number of buffers speculated into for this
+ * speculation, and the number drained by userspace.
* - buffers: Perf event output buffer map, associating a perf event output
* buffer with each CPU. The map is indexed by CPU id.
* - cpuinfo: CPU information map, associating a cpuinfo_t structure with
@@ -264,6 +281,11 @@ dt_bpf_gmap_create(dtrace_hdl_t *dtp)
return -1; /* dt_errno is set for us */
}
+ if (create_gmap(dtp, "specs", BPF_MAP_TYPE_HASH,
+ sizeof(uint32_t), sizeof(dt_bpf_specs_t),
+ dtp->dt_options[DTRACEOPT_NSPEC]) == -1)
+ return -1; /* dt_errno is set for us */
+
if (create_gmap(dtp, "buffers", BPF_MAP_TYPE_PERF_EVENT_ARRAY,
sizeof(uint32_t), sizeof(uint32_t),
dtp->dt_conf.num_online_cpus) == -1)
diff --git a/libdtrace/dt_bpf.h b/libdtrace/dt_bpf.h
index 2882520fd701..287178c11d9b 100644
--- a/libdtrace/dt_bpf.h
+++ b/libdtrace/dt_bpf.h
@@ -26,6 +26,7 @@ extern "C" {
#define DT_CONST_STRSZ 6
#define DT_CONST_STKSIZ 7
#define DT_CONST_BOOTTM 8
+#define DT_CONST_NSPEC 9
extern int perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu,
int group_fd, unsigned long flags);
@@ -34,6 +35,7 @@ extern int bpf(enum bpf_cmd cmd, union bpf_attr *attr);
extern int dt_bpf_gmap_create(struct dtrace_hdl *);
extern int dt_bpf_map_lookup(int fd, const void *key, void *val);
extern int dt_bpf_map_update(int fd, const void *key, const void *val);
+extern int dt_bpf_map_delete(int fd, const void *key);
extern int dt_bpf_load_progs(struct dtrace_hdl *, uint_t);
#ifdef __cplusplus
diff --git a/libdtrace/dt_bpf_maps.h b/libdtrace/dt_bpf_maps.h
index aa088ce8ee80..e33748b7aa50 100644
--- a/libdtrace/dt_bpf_maps.h
+++ b/libdtrace/dt_bpf_maps.h
@@ -12,6 +12,8 @@
extern "C" {
#endif
+#include <stddef.h>
+
typedef struct dt_bpf_probe dt_bpf_probe_t;
struct dt_bpf_probe {
size_t prv; /* probeprov string offset in strtab */
@@ -20,6 +22,13 @@ struct dt_bpf_probe {
size_t prb; /* probename string offset in strtab */
};
+typedef struct dt_bpf_specs dt_bpf_specs_t;
+struct dt_bpf_specs {
+ uint64_t written; /* number of spec buffers written */
+ uint32_t draining; /* 1 if userspace has been asked to
+ * drain this buffer */
+};
+
#ifdef __cplusplus
}
#endif
diff --git a/libdtrace/dt_cc.c b/libdtrace/dt_cc.c
index 97c7d5e2a0a1..a25f354815dc 100644
--- a/libdtrace/dt_cc.c
+++ b/libdtrace/dt_cc.c
@@ -2352,6 +2352,9 @@ dt_link_construct(dtrace_hdl_t *dtp, const dt_probe_t *prp, dtrace_difo_t *dp,
nrp->dofr_data =
dtp->dt_options[DTRACEOPT_STRSIZE];
continue;
+ case DT_CONST_NSPEC:
+ nrp->dofr_data = dtp->dt_options[DTRACEOPT_NSPEC];
+ continue;
case DT_CONST_STKSIZ:
nrp->dofr_data = sizeof(uint64_t)
* dtp->dt_options[DTRACEOPT_MAXFRAMES];
diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index b94f4485f295..43ed2351d51c 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -488,8 +488,9 @@ dt_cg_tramp_error(dt_pcb_t *pcb)
*
* 1. Store the base pointer to the output data buffer in %r9.
* 2. Initialize the machine state (dctx->mst).
- * 3. Store the epid and tag at [%r9 + 0] and [%r9 + 4] respectively.
- * 4. Evaluate the predicate expression and return if false.
+ * 3. Store the epid at [%r9 + 0].
+ * 4. Store 0 to indicate no active speculation at [%r9 + 4].
+ * 5. Evaluate the predicate expression and return if false.
*
* The dt_program() function will always return 0.
*/
@@ -539,11 +540,11 @@ dt_cg_prologue(dt_pcb_t *pcb, dt_node_t *pred)
emite(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, 0, -1), epid);
/*
- * dctx->mst->tag = 0; // stw [%r0 + DMST_TAG], 0
+ * Set the speculation ID field to zero to indicate no active
+ * speculation.
* *((uint32_t *)&buf[4]) = 0;
* // stw [%r9 + 4], 0
*/
- emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_0, DMST_TAG, 0));
emit(dlp, BPF_STORE_IMM(BPF_W, BPF_REG_9, 4, 0));
/*
@@ -587,8 +588,10 @@ dt_cg_epilogue(dt_pcb_t *pcb)
* Output the buffer if:
* - data-recording action, or
* - default action (no clause specified)
+ * - committing or discarding a speculation
*/
- if (pcb->pcb_stmt->dtsd_clauseflags & DT_CLSFLAG_DATAREC) {
+ if (pcb->pcb_stmt->dtsd_clauseflags & DT_CLSFLAG_DATAREC ||
+ pcb->pcb_stmt->dtsd_clauseflags & DT_CLSFLAG_COMMIT_DISCARD) {
dt_ident_t *buffers = dt_dlib_get_map(pcb->pcb_hdl, "buffers");
assert(buffers != NULL);
@@ -923,14 +926,16 @@ dt_cg_clsflags(dt_pcb_t *pcb, dtrace_actkind_t kind, const dt_node_t *dnp)
*cfp |= DT_CLSFLAG_DESTRUCT;
if (kind == DTRACEACT_COMMIT) {
- if (*cfp & DT_CLSFLAG_COMMIT)
- dnerror(dnp, D_COMM_COMM,
- "commit( ) may not follow commit( )\n");
if (*cfp & (DT_CLSFLAG_DATAREC | DT_CLSFLAG_AGGREGATION))
dnerror(dnp, D_COMM_DREC, "commit( ) may "
"not follow data-recording action(s)\n");
- *cfp |= DT_CLSFLAG_COMMIT;
+ *cfp |= DT_CLSFLAG_COMMIT | DT_CLSFLAG_COMMIT_DISCARD;
+ return;
+ }
+
+ if (kind == DTRACEACT_DISCARD) {
+ *cfp |= DT_CLSFLAG_COMMIT_DISCARD;
return;
}
@@ -987,8 +992,7 @@ dt_cg_clsflags(dt_pcb_t *pcb, dtrace_actkind_t kind, const dt_node_t *dnp)
dnerror(dnp, D_DREC_COMM,
"data-recording actions may not follow commit( )\n");
- if (!(*cfp & DT_CLSFLAG_SPECULATE))
- *cfp |= DT_CLSFLAG_DATAREC;
+ *cfp |= DT_CLSFLAG_DATAREC;
}
static void
@@ -1037,6 +1041,50 @@ dt_cg_act_clear(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
dt_cg_store_val(pcb, anp, DTRACEACT_LIBACT, NULL, DT_ACT_CLEAR);
}
+/*
+ * Mark a speculation as committed/discarded and ready for draining.
+ *
+ * The speculation ID must be in IDREG (true for both commit and discard).
+ *
+ * If the speculation does not exist, nothing will be done: the consumer has to
+ * detect this itself if the speculation is inactive (out-of-range values
+ * fault and do not write a commit/discard record).
+ */
+static void
+dt_cg_spec_set_drainable(dt_pcb_t *pcb, dt_node_t *dnp, int idreg)
+{
+ dt_regset_t *drp = pcb->pcb_regs;
+ dt_irlist_t *dlp = &pcb->pcb_ir;
+ dt_ident_t *idp;
+ uint_t lbl_ok = dt_irlist_label(dlp);
+
+ idp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_speculation_set_drainable");
+ assert(idp != NULL);
+
+ /*
+ * spec = dt_speculation_set_drainable(ctx, id);
+ * // call dt_speculation_commit_discard
+ * // (%r1 ... %r5 clobbered)
+ * if (rc == 0) // jeq %r0, 0, lbl_ok
+ * goto ok;
+ * return rc; // mov %dn_reg, %r0
+ * ok:
+ */
+
+ if (dt_regset_xalloc_args(drp) == -1)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+ dt_regset_xalloc(drp, BPF_REG_0);
+ emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_FP, DT_STK_DCTX));
+ emit(dlp, BPF_MOV_REG(BPF_REG_2, idreg));
+ emite(dlp, BPF_CALL_FUNC(idp->di_id), idp);
+ emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, lbl_ok));
+ emit(dlp, BPF_RETURN());
+ emitl(dlp, lbl_ok,
+ BPF_NOP());
+ dt_regset_free(drp, BPF_REG_0);
+ dt_regset_free_args(drp);
+}
+
/*
* Signal that the speculation with the given id should be committed to the
* tracing output.
@@ -1047,16 +1095,12 @@ dt_cg_act_clear(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
static void
dt_cg_act_commit(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
{
- dt_irlist_t *dlp = &pcb->pcb_ir;
- uint_t off;
-
- dt_cg_node(dnp->dn_args, &pcb->pcb_ir, pcb->pcb_regs);
-
- off = dt_rec_add(pcb->pcb_hdl, dt_cg_fill_gap, DTRACEACT_COMMIT,
- sizeof(uint64_t), sizeof(uint64_t), NULL,
- DT_ACT_COMMIT);
+ dt_regset_t *drp = pcb->pcb_regs;
- emit(dlp, BPF_STORE(BPF_DW, BPF_REG_9, off, BPF_REG_0)); /* FIXME */
+ dt_cg_node(dnp->dn_args, &pcb->pcb_ir, drp);
+ dt_cg_spec_set_drainable(pcb, dnp, dnp->dn_args->dn_reg);
+ dt_regset_free(drp, dnp->dn_args->dn_reg);
+ dt_cg_store_val(pcb, dnp->dn_args, DTRACEACT_COMMIT, NULL, DT_ACT_COMMIT);
}
static void
@@ -1094,16 +1138,12 @@ dt_cg_act_denormalize(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
static void
dt_cg_act_discard(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
{
- dt_irlist_t *dlp = &pcb->pcb_ir;
- uint_t off;
-
- dt_cg_node(dnp->dn_args, &pcb->pcb_ir, pcb->pcb_regs);
-
- off = dt_rec_add(pcb->pcb_hdl, dt_cg_fill_gap, DTRACEACT_DISCARD,
- sizeof(uint64_t), sizeof(uint64_t), NULL,
- DT_ACT_DISCARD);
+ dt_regset_t *drp = pcb->pcb_regs;
- emit(dlp, BPF_STORE(BPF_DW, BPF_REG_9, off, BPF_REG_0)); /* FIXME */
+ dt_cg_node(dnp->dn_args, &pcb->pcb_ir, drp);
+ dt_cg_spec_set_drainable(pcb, dnp, dnp->dn_args->dn_reg);
+ dt_regset_free(drp, dnp->dn_args->dn_reg);
+ dt_cg_store_val(pcb, dnp->dn_args, DTRACEACT_DISCARD, NULL, DT_ACT_DISCARD);
}
/*
@@ -1407,22 +1447,48 @@ dt_cg_act_setopt(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
* Signal that subsequent tracing output in the current clause should be kept
* back pending a commit() or discard() for the speculation with the given id.
*
- * Stores:
- * integer (4 bytes) -- speculation ID
+ * Updates the specid in the output buffer header, rather than emitting a new
+ * record into it.
*/
static void
dt_cg_act_speculate(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
{
dt_irlist_t *dlp = &pcb->pcb_ir;
- uint_t off;
+ dt_regset_t *drp = pcb->pcb_regs;
+ dt_ident_t *idp;
+ uint_t lbl_exit = pcb->pcb_exitlbl;
- dt_cg_node(dnp->dn_args, &pcb->pcb_ir, pcb->pcb_regs);
+ idp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_speculation_speculate");
+ assert(idp != NULL);
+
+ dt_cg_node(dnp->dn_args, dlp, drp);
+ dnp->dn_reg = dnp->dn_args->dn_reg;
+
+ if (dt_regset_xalloc_args(drp) == -1)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
- off = dt_rec_add(pcb->pcb_hdl, dt_cg_fill_gap, DTRACEACT_SPECULATE,
- sizeof(uint64_t), sizeof(uint64_t), NULL,
- DT_ACT_SPECULATE);
+ /*
+ * rc = dt_speculation_speculate(spec);
+ * // lddw %r1, %dn_reg
+ * // call dt_speculation_speculate
+ * // (%r1 ... %r5 clobbered)
+ * // (%r0 = error return)
+ * if (rc != 0) // jne %r0, 0, lbl_exit
+ * goto exit;
+ * *((uint32_t *)&buf[4]) = spec; // mov [%r9 + 4], %dn_reg
+ * exit: // nop
+ */
- emit(dlp, BPF_STORE(BPF_DW, BPF_REG_9, off, BPF_REG_0)); /* FIXME */
+ emit(dlp, BPF_STORE(BPF_W, BPF_REG_FP, DT_STK_SPILL(0),
+ dnp->dn_reg));
+ emit(dlp, BPF_MOV_REG(BPF_REG_1, dnp->dn_reg));
+ dt_regset_xalloc(drp, BPF_REG_0);
+ emite(dlp, BPF_CALL_FUNC(idp->di_id), idp);
+ dt_regset_free_args(drp);
+ emit(dlp, BPF_BRANCH_IMM(BPF_JNE, BPF_REG_0, 0, lbl_exit));
+ emit(dlp, BPF_STORE(BPF_W, BPF_REG_9, 4, dnp->dn_reg));
+ dt_regset_free(drp, BPF_REG_0);
+ dt_regset_free(drp, dnp->dn_reg);
}
static void
@@ -3011,12 +3077,39 @@ dt_cg_array_op(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
emit(dlp, BPF_ALU64_REG((dnp->dn_flags & DT_NF_SIGNED) ? BPF_ARSH : BPF_RSH, dnp->dn_reg, n));
}
+/*
+ * Get and return a new speculation ID. These are unallocated entries in the
+ * specs map, obtained by calling dt_speculation(). Return zero if none is
+ * available. TODO: add a drop in this case?
+ */
static void
dt_cg_subr_speculation(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
{
+ dt_ident_t *idp;
+
+ idp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_speculation");
+ assert(idp != NULL);
+
TRACE_REGSET(" subr-speculation:Begin");
- dnp->dn_reg = dt_regset_alloc(drp);
- emit(dlp, BPF_MOV_IMM(dnp->dn_reg, 0));
+ if ((dnp->dn_reg = dt_regset_alloc(drp)) == -1)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+
+
+ /*
+ * spec = dt_speculation();
+ * // call dt_speculation
+ * // (%r1 ... %r5 clobbered)
+ * // (%r0 = speculation ID, or 0)
+ * return rc; // mov %dn_reg, %r0
+ */
+
+ if (dt_regset_xalloc_args(drp) == -1)
+ longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+ dt_regset_xalloc(drp, BPF_REG_0);
+ emite(dlp, BPF_CALL_FUNC(idp->di_id), idp);
+ emit(dlp, BPF_MOV_REG(dnp->dn_reg, BPF_REG_0));
+ dt_regset_free(drp, BPF_REG_0);
+ dt_regset_free_args(drp);
TRACE_REGSET(" subr-speculation:End ");
}
@@ -4887,6 +4980,9 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
dxp->dx_ident->di_id = dt_regset_alloc(pcb->pcb_regs);
dt_cg_node(dnp, &pcb->pcb_ir, pcb->pcb_regs);
} else if (dnp->dn_kind == DT_NODE_CLAUSE) {
+ int nonspec_acts = 0;
+ int speculative = 0;
+
dt_cg_prologue(pcb, dnp->dn_pred);
for (act = dnp->dn_acts; act != NULL; act = act->dn_list) {
@@ -4902,6 +4998,11 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
actdp->fun(pcb, act->dn_expr,
actdp->kind);
}
+
+ if (actdp->kind == DTRACEACT_SPECULATE)
+ speculative = 1;
+ else
+ nonspec_acts++;
break;
}
case DT_NODE_AGG:
@@ -4926,7 +5027,8 @@ dt_cg(dt_pcb_t *pcb, dt_node_t *dnp)
"statement\n", dnp->dn_kind);
}
}
- if (dnp->dn_acts == NULL)
+ if (dnp->dn_acts == NULL ||
+ (speculative && nonspec_acts == 0))
pcb->pcb_stmt->dtsd_clauseflags |= DT_CLSFLAG_DATAREC;
dt_cg_epilogue(pcb);
diff --git a/libdtrace/dt_consume.c b/libdtrace/dt_consume.c
index 5075254cb399..8296a0051065 100644
--- a/libdtrace/dt_consume.c
+++ b/libdtrace/dt_consume.c
@@ -364,6 +364,37 @@ dt_stddev(uint64_t *data, uint64_t normal)
return dt_sqrt_128(diff);
}
+static uint32_t
+dt_spec_bufs_hval(const dt_spec_bufs_head_t *head)
+{
+ uint32_t g = 0, hval = 0;
+ uint32_t *p = (uint32_t *) &head->dtsh_id;
+
+ while ((uintptr_t) p < (((uintptr_t) &head->dtsh_id) +
+ sizeof(head->dtsh_id))) {
+ hval = (hval << 4) + *p++;
+ g = hval & 0xf0000000;
+ if (g != 0) {
+ hval ^= (g >> 24);
+ hval ^= g;
+ }
+ }
+
+ return hval;
+}
+
+static int
+dt_spec_bufs_cmp(const dt_spec_bufs_head_t *p,
+ const dt_spec_bufs_head_t *q)
+{
+ if (p->dtsh_id == q->dtsh_id)
+ return 0;
+ return 1;
+}
+
+DEFINE_HE_STD_LINK_FUNCS(dt_spec_bufs, dt_spec_bufs_head_t, dtsh_he);
+DEFINE_HTAB_STD_OPS(dt_spec_bufs);
+
static int
dt_flowindent(dtrace_hdl_t *dtp, dtrace_probedata_t *data, dtrace_epid_t last,
dtrace_epid_t next)
@@ -1935,31 +1966,217 @@ dt_print_trace(dtrace_hdl_t *dtp, FILE *fp, dtrace_recdesc_t *rec,
return dt_print_rawbytes(dtp, fp, data, rec->dtrd_size);
}
+/*
+ * The lifecycle of speculation buffers is as follows:
+ *
+ * - They are created upon speculation() as entries in the specs map mapping
+ * from the speculation ID to a dt_bpf_specs_t entry with read, written,
+ * and draining values all zero.
+ *
+ * - speculate() verifies the existence of the requested speculation entry in
+ * the specs map, and that draining has not been set in it, and atomically
+ * bumps the written value.
+ *
+ * - Speculations drain from the perf ring buffer into dt_spec_bufs, one
+ * dt_spec_buf per ring-buffer of data fetched from the kernel with a nonzero
+ * specid (one speculated clause); these are chained into dt_spec_buf_heads,
+ * one per speculation ID, and these are chained into dtp->dt_spec_bufs
+ * instead of being consumed.
+ *
+ * - commit / discard set the specs map entry's drained value to 1, which
+ * indicates that it is drainable by userspace and prevents further
+ * speculate()s, and record a single entry in the output buffer with the
+ * committed/discarded ID attached
+ *
+ * - Non-speculated buffers (with a zero specid) are scanned by
+ * dt_consume_one_buffer for commit / discard; the first found for a given
+ * live speculation triggers draining, chaining the spec buf head into
+ * dtp->dt_spec_bufs_draining. dt_spec_bufs_draining contains a counter of
+ * the number of buffers drained ("read", mirroring "written" in the specs
+ * map).
+ *
+ * - dt_spec_bufs_draining is traversed on every buffer consume and any
+ * speculations that are committing have their speculation buffers processed
+ * as if they had just been received (but keeping their original CPU number);
+ * both entries that are committing and those that are discarding are then
+ * removed, leaving the buffer head behind to be filled out by future
+ * ring-buffer fetches, and the number removed recorded by incrementing
+ * dtsh_draining_t.read. Buffers for which read >= written are removed from
+ * dt_spec_bufs_draining and have their buffer heads removed from
+ * dt_spec_bufs and their ID removed from the specs map, freeing them for
+ * recycling by future calls to speculation().
+ */
+
+/*
+ * Member of the dtsh_draining_list.
+ */
+typedef struct dtsh_draining {
+ dt_list_t dtsd_list;
+ dt_spec_bufs_head_t *dtsd_dtsh;
+ uint64_t dtsd_read;
+} dtsh_draining_t;
+
+static dt_spec_bufs_head_t *
+dt_create_spec_buf_head(dtrace_hdl_t *dtp, int32_t spec)
+{
+ dt_spec_bufs_head_t *dtsh;
+
+ dtsh = dt_zalloc(dtp, sizeof(struct dt_spec_bufs_head));
+ if (!dtsh)
+ goto oom;
+ dtsh->dtsh_id = spec;
+
+ if (dt_htab_insert(dtp->dt_specs_byid, dtsh) < 0)
+ goto oom;
+ dt_list_append(&dtp->dt_spec_bufs, dtsh);
+ return dtsh;
+oom:
+ dt_free(dtp, dtsh);
+ dt_set_errno(dtp, EDT_NOMEM);
+ return NULL;
+}
+
+static dt_spec_bufs_t *
+dt_create_spec_buf(dtrace_hdl_t *dtp, dt_spec_bufs_head_t *dtsh,
+ dtrace_epid_t epid, unsigned int cpu,
+ dtrace_datadesc_t *datadesc, char *data,
+ uint32_t size)
+{
+ dt_spec_bufs_t *dtsb;
+
+ dtsb = dt_zalloc(dtp, sizeof(struct dt_spec_bufs));
+ if (!dtsb)
+ goto oom;
+
+ dtsb->dtsb_cpu = cpu;
+ dtsb->dtsb_size = size;
+ dtsb->dtsb_data = dt_alloc(dtp, size);
+ if (!dtsb->dtsb_data)
+ goto oom;
+
+ dtsh->dtsh_size += size;
+ memcpy(dtsb->dtsb_data, data, size);
+
+ dt_list_append(&dtsh->dtsh_dtsb_list, dtsb);
+ return dtsb;
+
+oom:
+ dt_free(dtp, dtsb);
+ dt_set_errno(dtp, EDT_NOMEM);
+ return NULL;
+}
+
+/*
+ * Remove a speculation's buffers and possibly the speculation head and
+ * the record of it in the BPF specs map (which frees the ID for reuse).
+ *
+ * Note: if the speculation is being committed, it will also be interned on the
+ * dtp->dt_spec_bufs_draining list. Such speculations must be removed via
+ * dt_gc_speculations, which ultimately calls this function.
+ */
+static void
+dt_destroy_spec_bufs(dtrace_hdl_t *dtp, dt_spec_bufs_head_t *dtsh,
+ int remove_specid)
+{
+ dt_spec_bufs_t *dtsb;
+
+ while ((dtsb = dt_list_next(&dtsh->dtsh_dtsb_list)) != NULL) {
+
+ dt_list_delete(&dtsh->dtsh_dtsb_list, dtsb);
+ dt_free(dtp, dtsb->dtsb_data);
+ dt_free(dtp, dtsb);
+ }
+
+ dtsh->dtsh_size = 0;
+
+ if (remove_specid) {
+ dt_ident_t *idp = dt_dlib_get_map(dtp, "specs");
+
+ if (idp)
+ dt_bpf_map_delete(idp->di_id, &dtsh->dtsh_id);
+ dt_list_delete(&dtp->dt_spec_bufs, dtsh);
+ dt_free(dtp, dtsh);
+ }
+}
+
+/*
+ * Peeking flags (values for the peekflag parameter for functions that have
+ * one).
+ *
+ * These let you process a single buffer more than once. The first call
+ * should pass CONSUME_PEEK_START: this suppresses deletion of consumed records.
+ * Subsequent calls should pass CONSUME_PEEK; this does as CONSUME_PEEK_START
+ * does, but also suppresses hiving off of speculative buffers (because they
+ * have already been hived off under CONSUME_PEEK_START). The final call should
+ * pass CONSUME_PEEK_FINISH; this does a normal buffer consumption (with
+ * deletion) except that speculative hiving-off is again suppressd.
+ *
+ * These are not bit-flags: pass only one.
+ */
+#define CONSUME_PEEK_START 0x1
+#define CONSUME_PEEK 0x2
+#define CONSUME_PEEK_FINISH 0x3
+
static dtrace_workstatus_t
dt_consume_one_buffer(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
dtrace_probedata_t *pdat, dtrace_consume_probe_f *efunc,
dtrace_consume_rec_f *rfunc, int flow, int quiet,
- dtrace_epid_t *last, void *arg);
+ int peekflags, dtrace_epid_t *last, int committing,
+ void *arg);
+
+/*
+ * Commit one speculation.
+ */
+static dtrace_workstatus_t
+dt_commit_one_spec(dtrace_hdl_t *dtp, FILE *fp, dt_spec_bufs_head_t *dtsh,
+ dtrace_probedata_t *pdat, dtrace_consume_probe_f *efunc,
+ dtrace_consume_rec_f *rfunc, int flow, int quiet,
+ int peekflags, dtrace_epid_t *last, void *arg)
+{
+ dt_spec_bufs_t *dtsb;
+
+ for (dtsb = dt_list_next(&dtsh->dtsh_dtsb_list);
+ dtsb != NULL; dtsb = dt_list_next(dtsb)) {
+ dtrace_workstatus_t ret;
+ dtrace_probedata_t specpdat;
+
+ memcpy(&specpdat, pdat, sizeof(dtrace_probedata_t));
+ specpdat.dtpda_cpu = dtsb->dtsb_cpu;
+ ret = dt_consume_one_buffer(dtp, fp, dtsb->dtsb_data,
+ dtsb->dtsb_size, &specpdat,
+ efunc, rfunc, flow, quiet,
+ peekflags, last, 1, arg);
+ if (ret != DTRACE_WORKSTATUS_OKAY)
+ return ret;
+ }
+
+ return DTRACE_WORKSTATUS_OKAY;
+}
static dtrace_workstatus_t
dt_consume_one_buffer(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
dtrace_probedata_t *pdat, dtrace_consume_probe_f *efunc,
dtrace_consume_rec_f *rfunc, int flow, int quiet,
- dtrace_epid_t *last, void *arg)
+ int peekflags, dtrace_epid_t *last, int committing,
+ void *arg)
{
dtrace_epid_t epid;
+ dt_spec_bufs_head_t tmpl;
+ dt_spec_bufs_head_t *dtsh;
+ int specid;
int i;
int rval;
+ dtrace_workstatus_t ret;
+ int commit_discard_seen, only_commit_discards;
+ int data_recording = 1;
epid = ((uint32_t *)data)[0];
-#ifdef FIXME
- tag = ((uint32_t *)data)[1]; /* for future use */
-#endif
+ specid = ((uint32_t *)data)[1];
/*
* Fill in the epid and address of the epid in the buffer. We need to
- * pass this to the efunc.
+ * pass this to the efunc and possibly to create speculations.
*/
pdat->dtpda_epid = epid;
pdat->dtpda_data = data;
@@ -1978,30 +2195,115 @@ dt_consume_one_buffer(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
return DTRACE_WORKSTATUS_ERROR;
}
- if (flow)
- dt_flowindent(dtp, pdat, *last, DTRACE_EPIDNONE);
+ /*
+ * If speculating (and not peeking), hive this buffer off into a
+ * suitable spec buf, creating the spec buf head if need be. No need to
+ * do anything else with this buffer until a commit or discard is seen
+ * for it (in some other, non-speculated buffer).
+ */
- rval = (*efunc)(pdat, arg);
+ if (!committing && specid != 0) {
+ size_t cursz = 0;
- if (flow) {
- if (pdat->dtpda_flow == DTRACEFLOW_ENTRY)
- pdat->dtpda_indent += 2;
- }
+ /*
+ * If peeking, we dealt with this buffer earlier: don't
+ * re-speculate it again.
+ */
+ if (peekflags == CONSUME_PEEK ||
+ peekflags == CONSUME_PEEK_FINISH)
+ return DTRACE_WORKSTATUS_OKAY;
+
+ tmpl.dtsh_id = specid;
+ dtsh = dt_htab_lookup(dtp->dt_specs_byid, &tmpl);
+
+ /*
+ * Discard when over the specsize.
+ *
+ * TODO: add a drop when OOM or > specsize -- and also on OOM in
+ * any of the consuming functions.
+ */
+
+ if (dtsh)
+ cursz = dtsh->dtsh_size;
+
+ if (cursz + size > dtp->dt_options[DTRACEOPT_SPECSIZE])
+ return DTRACE_WORKSTATUS_OKAY;
+
+ if (!dtsh) {
+ if ((dtsh = dt_create_spec_buf_head(dtp, specid)) == NULL)
+ return -1;
+ }
+
+ if (dt_create_spec_buf(dtp, dtsh, epid, pdat->dtpda_cpu,
+ pdat->dtpda_ddesc, data, size) == NULL)
+ return -1;
- switch (rval) {
- case DTRACE_CONSUME_NEXT:
return DTRACE_WORKSTATUS_OKAY;
- case DTRACE_CONSUME_DONE:
- return DTRACE_WORKSTATUS_DONE;
- case DTRACE_CONSUME_ABORT:
- return dt_set_errno(dtp, EDT_DIRABORT);
- case DTRACE_CONSUME_THIS:
- break;
- default:
- return dt_set_errno(dtp, EDT_BADRVAL);
}
/*
+ * First, scan for commit/discard. Track whether we have seen discards,
+ * and whether we have seen anything else, to determine whether this
+ * clause should be considered data-recording from the user's
+ * perspective. (A clause with only a discard is not data-recording.
+ * Commits cannot share a clause with data-recording actions at all: see
+ * dt_cg_clsflags.)
+ *
+ * Do nothing of this if committing speculated buffers, since speculated
+ * buffers cannot contain commits or discards.
+ */
+ commit_discard_seen = 0;
+ only_commit_discards = 1;
+ for (i = 0; !committing && i < pdat->dtpda_ddesc->dtdd_nrecs; i++) {
+ dtrace_recdesc_t *rec;
+ dtrace_actkind_t act;
+
+ rec = &pdat->dtpda_ddesc->dtdd_recs[i];
+ act = rec->dtrd_action;
+
+ if (act == DTRACEACT_COMMIT || act == DTRACEACT_DISCARD) {
+ commit_discard_seen = 1;
+ } else
+ only_commit_discards = 0;
+ }
+
+ /*
+ * If this clause is a commit or discard, and no other actions have been
+ * seen, this is not a data-recording clause, and we should not call the
+ * efunc or rfunc at all.
+ */
+
+ if (commit_discard_seen && only_commit_discards)
+ data_recording = 0;
+
+ if (data_recording) {
+ if (flow)
+ dt_flowindent(dtp, pdat, *last, DTRACE_EPIDNONE);
+
+ rval = (*efunc)(pdat, arg);
+
+ if (flow) {
+ if (pdat->dtpda_flow == DTRACEFLOW_ENTRY)
+ pdat->dtpda_indent += 2;
+ }
+
+ switch (rval) {
+ case DTRACE_CONSUME_NEXT:
+ return DTRACE_WORKSTATUS_OKAY;
+ case DTRACE_CONSUME_DONE:
+ return DTRACE_WORKSTATUS_DONE;
+ case DTRACE_CONSUME_ABORT:
+ return dt_set_errno(dtp, EDT_DIRABORT);
+ case DTRACE_CONSUME_THIS:
+ break;
+ default:
+ return dt_set_errno(dtp, EDT_BADRVAL);
+ }
+ }
+
+ /*
+ * Now scan for data-recording actions.
+ *
* FIXME: This code is temporary.
*/
for (i = 0; i < pdat->dtpda_ddesc->dtdd_nrecs; i++) {
@@ -2037,6 +2339,49 @@ dt_consume_one_buffer(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
}
}
+ if (act == DTRACEACT_COMMIT || act == DTRACEACT_DISCARD) {
+ /*
+ * Committing or discarding. If this is the first
+ * commit/discard we've seen for this speculation,
+ * arrange to drain it until enough CPUs have passed by
+ * that all must have been drained. Out-of-range IDs
+ * are automatically ignored by the code below, since
+ * they will have no dtsh entries.
+ */
+
+ assert(specid == 0);
+
+ tmpl.dtsh_id = *(uint32_t *)recdata;
+ dtsh = dt_htab_lookup(dtp->dt_specs_byid, &tmpl);
+
+ /*
+ * Speculation exists and is not already being drained.
+ */
+ if (dtsh && !dtsh->dtsh_spec.draining) {
+ dtsh_draining_t *dtsd;
+ dt_bpf_specs_t spec;
+ dt_ident_t *idp = dt_dlib_get_map(dtp, "specs");
+ int rval;
+
+ rval = dt_bpf_map_lookup(idp->di_id, &tmpl.dtsh_id, &spec);
+ if (rval != 0)
+ return dt_set_errno(dtp, -rval);
+
+ assert(spec.draining);
+ dtsd = dt_zalloc(dtp, sizeof(dtsh_draining_t));
+ if (!dtsd)
+ return dt_set_errno(dtp, EDT_NOMEM);
+ dtsd->dtsd_dtsh = dtsh;
+ dtsh->dtsh_committing = (act == DTRACEACT_COMMIT);
+ memcpy(&dtsh->dtsh_spec, &spec,
+ sizeof(dt_bpf_specs_t));
+ dt_list_append(&dtp->dt_spec_bufs_draining, dtsd);
+ }
+ continue;
+ }
+
+ assert(data_recording);
+
rval = (*rfunc)(pdat, rec, arg);
if (rval == DTRACE_CONSUME_NEXT)
@@ -2122,9 +2467,49 @@ dt_consume_one_buffer(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
* that we're done processing this EPID. The return value is ignored in
* this case. XXX should we respect at least DTRACE_CONSUME_ABORT?
*/
- (*rfunc)(pdat, NULL, arg);
+ if (data_recording) {
+ (*rfunc)(pdat, NULL, arg);
- *last = epid;
+ *last = epid;
+ }
+
+ /*
+ * If we're not committing a speculative buffer already, commit any spec
+ * buffers that are marked as committing and draining and have any
+ * content to drain.
+ */
+ if (!committing) {
+ dtsh_draining_t *dtsd, *next;
+
+ for (dtsd = dt_list_next(&dtp->dt_spec_bufs_draining);
+ dtsd != NULL; dtsd = next) {
+
+ dtsh = dtsd->dtsd_dtsh;
+ dtsd->dtsd_read += dt_list_length(&dtsd->dtsd_dtsh->dtsh_dtsb_list);
+
+ if (dtsh->dtsh_committing) {
+ if ((ret = dt_commit_one_spec(dtp, fp, dtsh,
+ pdat, efunc, rfunc,
+ flow, quiet, peekflags,
+ last, arg)) !=
+ DTRACE_WORKSTATUS_OKAY) {
+ dt_destroy_spec_bufs(dtp, dtsh, 0);
+ return ret;
+ }
+ }
+
+ next = dt_list_next(dtsd);
+
+ if (dtsd->dtsd_read < dtsd->dtsd_dtsh->dtsh_spec.written)
+ dt_destroy_spec_bufs(dtp, dtsh, 0);
+ else {
+ dt_destroy_spec_bufs(dtp, dtsh, 1);
+ dt_htab_delete(dtp->dt_specs_byid, dtsd->dtsd_dtsh);
+ dt_list_delete(&dtp->dt_spec_bufs_draining, dtsd);
+ dt_free(dtp, dtsd);
+ }
+ }
+ }
return DTRACE_WORKSTATUS_OKAY;
}
@@ -2132,7 +2517,7 @@ dt_consume_one_buffer(dtrace_hdl_t *dtp, FILE *fp, char *data, uint32_t size,
static dtrace_workstatus_t
dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, char *buf,
dtrace_probedata_t *pdat, dtrace_consume_probe_f *efunc,
- dtrace_consume_rec_f *rfunc, int flow, int quiet,
+ dtrace_consume_rec_f *rfunc, int flow, int quiet, int peekflags,
dtrace_epid_t *last, void *arg)
{
char *data = buf;
@@ -2151,7 +2536,7 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, char *buf,
* uint32_t size;
* uint32_t pad;
* uint32_t epid;
- * uint32_t tag;
+ * uint32_t specid;
* uint64_t data[n];
* }
* and 'data' points to the 'size' member at this point.
@@ -2170,7 +2555,8 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, char *buf,
size -= sizeof(uint32_t);
return dt_consume_one_buffer(dtp, fp, data, size, pdat, efunc,
- rfunc, flow, quiet, last, arg);
+ rfunc, flow, quiet, peekflags,
+ last, 0, arg);
} else if (hdr->type == PERF_RECORD_LOST) {
#ifdef FIXME
uint64_t lost;
@@ -2195,7 +2581,7 @@ dt_consume_one(dtrace_hdl_t *dtp, FILE *fp, char *buf,
int
dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, dt_peb_t *peb,
dtrace_consume_probe_f *efunc, dtrace_consume_rec_f *rfunc,
- int peek_only, void *arg)
+ int peekflags, void *arg)
{
struct perf_event_mmap_page *rb_page = (void *)peb->base;
struct perf_event_header *hdr;
@@ -2214,6 +2600,11 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, dt_peb_t *peb,
/*
* Clear the probe data, and fill in data independent fields.
+ *
+ * Initializing more fields here (or anywhere above
+ * dt_consume_one_buffer) may require the addition of new fields to
+ * dt_spec_bufs, if you want the original value to be preserved acorss
+ * speculate/commit.
*/
memset(&pdat, 0, sizeof(pdat));
pdat.dtpda_handle = dtp;
@@ -2226,7 +2617,12 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, dt_peb_t *peb,
base = peb->base + pebset->page_size;
do {
- head = ring_buffer_read_head(rb_page);
+ if (peekflags == CONSUME_PEEK || peekflags == CONSUME_PEEK_FINISH)
+ head = peb->last_head;
+ else {
+ head = ring_buffer_read_head(rb_page);
+ peb->last_head = head;
+ }
tail = rb_page->data_tail;
if (head == tail)
@@ -2262,7 +2658,8 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, dt_peb_t *peb,
}
rval = dt_consume_one(dtp, fp, event, &pdat, efunc,
- rfunc, flow, quiet, &last, arg);
+ rfunc, flow, quiet, peekflags,
+ &last, arg);
if (rval == DTRACE_WORKSTATUS_DONE)
return DTRACE_WORKSTATUS_OKAY;
if (rval != DTRACE_WORKSTATUS_OKAY)
@@ -2271,9 +2668,9 @@ dt_consume_cpu(dtrace_hdl_t *dtp, FILE *fp, dt_peb_t *peb,
tail += hdr->size;
} while (tail != head);
- if (!peek_only)
+ if (peekflags == 0 || peekflags == CONSUME_PEEK_FINISH)
ring_buffer_write_tail(rb_page, tail);
- } while (!peek_only);
+ } while (peekflags == 0);
return DTRACE_WORKSTATUS_OKAY;
}
@@ -2420,7 +2817,8 @@ dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, struct epoll_event *events,
dtp->dt_errarg = &begin;
rval = dt_consume_cpu(dtp, fp, bpeb, dt_consume_begin_probe,
- dt_consume_begin_record, 1, &begin);
+ dt_consume_begin_record, CONSUME_PEEK_START,
+ &begin);
dtp->dt_errhdlr = begin.dtbgn_errhdlr;
dtp->dt_errarg = begin.dtbgn_errarg;
@@ -2454,7 +2852,8 @@ dt_consume_begin(dtrace_hdl_t *dtp, FILE *fp, struct epoll_event *events,
dtp->dt_errarg = &begin;
rval = dt_consume_cpu(dtp, fp, bpeb, dt_consume_begin_probe,
- dt_consume_begin_record, 0, &begin);
+ dt_consume_begin_record, CONSUME_PEEK_FINISH,
+ &begin);
dtp->dt_errhdlr = begin.dtbgn_errhdlr;
dtp->dt_errarg = begin.dtbgn_errarg;
@@ -2514,12 +2913,41 @@ dt_consume_proc_exits(dtrace_hdl_t *dtp)
pthread_mutex_unlock(&dph->dph_lock);
}
+
+int
+dt_consume_init(dtrace_hdl_t *dtp)
+{
+ dtp->dt_specs_byid = dt_htab_create(dtp, &dt_spec_bufs_htab_ops);
+
+ if (!dtp->dt_specs_byid)
+ return dt_set_errno(dtp, EDT_NOMEM);
+ return 0;
+}
+
+void
+dt_consume_fini(dtrace_hdl_t *dtp)
+{
+ dt_spec_bufs_head_t *dtsh;
+ dtsh_draining_t *dtsd;
+
+ while ((dtsd = dt_list_next(&dtp->dt_spec_bufs_draining)) != NULL) {
+ dt_list_delete(&dtp->dt_spec_bufs_draining, dtsd);
+ dt_free(dtp, dtsd);
+ }
+
+ while ((dtsh = dt_list_next(&dtp->dt_spec_bufs)) != NULL)
+ dt_destroy_spec_bufs(dtp, dtsh, 1);
+
+ dt_htab_destroy(dtp, dtp->dt_specs_byid);
+}
+
dtrace_workstatus_t
dtrace_consume(dtrace_hdl_t *dtp, FILE *fp, dtrace_consume_probe_f *pf,
dtrace_consume_rec_f *rf, void *arg)
{
dtrace_optval_t timeout = dtp->dt_options[DTRACEOPT_SWITCHRATE];
struct epoll_event events[dtp->dt_conf.num_online_cpus];
+ int drained = 0;
int i, cnt;
dtrace_workstatus_t rval;
@@ -2585,6 +3013,7 @@ dtrace_consume(dtrace_hdl_t *dtp, FILE *fp, dtrace_consume_probe_f *pf,
* by one. If tracing has stopped, skip the CPU on which the END probe
* executed because we want to process that one last.
*/
+drain:
for (i = 0; i < cnt; i++) {
dt_peb_t *peb = events[i].data.ptr;
@@ -2598,6 +3027,20 @@ dtrace_consume(dtrace_hdl_t *dtp, FILE *fp, dtrace_consume_probe_f *pf,
return rval;
}
+ /*
+ * If a commit or discard has come in, loop twice, because if it was a
+ * commit the commit probably wasn't the first in the CPU list, and it is
+ * quite likely that an earlier CPU contains some of the speculative
+ * content we want to commit. Circle round and process it once more to
+ * pick this up. This means users don't find themselves with committed
+ * speculative content routinely split between one consume loop and the
+ * next.
+ */
+ if (!drained && dt_list_next(&dtp->dt_spec_bufs_draining) != NULL) {
+ drained = 1;
+ goto drain;
+ }
+
/*
* If tracing has not been stopped, we are done here.
*/
diff --git a/libdtrace/dt_dlibs.c b/libdtrace/dt_dlibs.c
index 04becfa6a016..fa85cd446036 100644
--- a/libdtrace/dt_dlibs.c
+++ b/libdtrace/dt_dlibs.c
@@ -59,6 +59,9 @@ static const dt_ident_t dt_bpf_symbols[] = {
DT_BPF_SYMBOL(dt_get_string, DT_IDENT_SYMBOL),
DT_BPF_SYMBOL(dt_get_tvar, DT_IDENT_SYMBOL),
DT_BPF_SYMBOL(dt_set_tvar, DT_IDENT_SYMBOL),
+ DT_BPF_SYMBOL(dt_speculation, DT_IDENT_SYMBOL),
+ DT_BPF_SYMBOL(dt_speculation_speculate, DT_IDENT_SYMBOL),
+ DT_BPF_SYMBOL(dt_speculation_set_drainable, DT_IDENT_SYMBOL),
DT_BPF_SYMBOL(dt_strnlen, DT_IDENT_SYMBOL),
/* BPF maps */
DT_BPF_SYMBOL(aggs, DT_IDENT_PTR),
@@ -68,6 +71,7 @@ static const dt_ident_t dt_bpf_symbols[] = {
DT_BPF_SYMBOL(lvars, DT_IDENT_PTR),
DT_BPF_SYMBOL(mem, DT_IDENT_PTR),
DT_BPF_SYMBOL(probes, DT_IDENT_PTR),
+ DT_BPF_SYMBOL(specs, DT_IDENT_PTR),
DT_BPF_SYMBOL(state, DT_IDENT_PTR),
DT_BPF_SYMBOL(strtab, DT_IDENT_PTR),
DT_BPF_SYMBOL(tvars, DT_IDENT_PTR),
@@ -80,6 +84,7 @@ static const dt_ident_t dt_bpf_symbols[] = {
DT_BPF_SYMBOL_ID(STRSZ, DT_IDENT_SCALAR, DT_CONST_STRSZ),
DT_BPF_SYMBOL_ID(STKSIZ, DT_IDENT_SCALAR, DT_CONST_STKSIZ),
DT_BPF_SYMBOL_ID(BOOTTM, DT_IDENT_SCALAR, DT_CONST_BOOTTM),
+ DT_BPF_SYMBOL_ID(NSPEC, DT_IDENT_SCALAR, DT_CONST_NSPEC),
/* End-of-list marker */
{ NULL, }
};
diff --git a/libdtrace/dt_errtags.h b/libdtrace/dt_errtags.h
index f5b3bab72959..83257a148d0f 100644
--- a/libdtrace/dt_errtags.h
+++ b/libdtrace/dt_errtags.h
@@ -148,7 +148,7 @@ typedef enum {
D_DECL_PROTO_VOID, /* void must be sole parameter */
D_DECL_PROTO_NAME, /* void parameter may not have a name */
D_DECL_PROTO_FORM, /* parameter name has no formal */
- D_COMM_COMM, /* commit() after commit() */
+ D_OBSOLETE1, /* (was commit() after commit()) */
D_COMM_DREC, /* commit() after data action */
D_SPEC_SPEC, /* speculate() after speculate() */
D_SPEC_COMM, /* speculate() after commit() */
diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index bd8d9943c6fa..fb8cc0447a6c 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -31,6 +31,7 @@
extern "C" {
#endif
+#include <dt_bpf_maps.h>
#include <dt_parser.h>
#include <dt_regset.h>
#include <dt_strtab.h>
@@ -225,6 +226,31 @@ typedef struct dt_lib_depend {
dt_list_t dtld_dependents; /* linked-list of lib dependents */
} dt_lib_depend_t;
+typedef struct dt_spec_bufs {
+ dt_list_t dtsb_list; /* linked-list forward/back pointers */
+ unsigned int dtsb_cpu; /* cpu for data */
+ char *dtsb_data; /* data for later processing */
+ uint32_t dtsb_size; /* size of data */
+} dt_spec_bufs_t;
+
+typedef struct dt_spec_bufs_head {
+ dt_list_t dtsh_list; /* list of dt_spec_bufs_heads */
+ int32_t dtsh_id; /* speculation ID */
+ size_t dtsh_size; /* size of all buffers in this spec */
+ int dtsh_committing; /* when draining, nonzero if commit */
+ dt_bpf_specs_t dtsh_spec; /* bpf-side specs record for this spec
+ (buffer read/write counts). */
+ dt_list_t dtsh_dtsb_list; /* list of dt_spec_bufs */
+ struct dt_hentry dtsh_he; /* htab links */
+} dt_spec_bufs_head_t;
+
+/*
+ * This will be raised much higher in future: right now it is nailed low
+ * because the search-for-free-speculation code is unrolled rather than being a
+ * proper loop, due to limitations in the BPF verifier.
+ */
+#define DT_MAX_NSPECS 16 /* sanity upper bound on speculations */
+
typedef uint32_t dt_version_t; /* encoded version (see below) */
struct dtrace_hdl {
@@ -365,6 +391,9 @@ struct dtrace_hdl {
hrtime_t dt_laststatus; /* last status */
hrtime_t dt_lastswitch; /* last switch of buffer data */
hrtime_t dt_lastagg; /* last snapshot of aggregation data */
+ dt_list_t dt_spec_bufs; /* List of spec bufs */
+ dt_list_t dt_spec_bufs_draining; /* List of spec bufs being drained */
+ dt_htab_t *dt_specs_byid;/* spec ID -> list of dt_spec_bufs_head_t */
char *dt_sprintf_buf; /* buffer for dtrace_sprintf() */
int dt_sprintf_buflen; /* length of dtrace_sprintf() buffer */
pthread_mutex_t dt_sprintf_lock; /* lock for dtrace_sprintf() buffer */
@@ -729,6 +758,9 @@ extern int dt_aggregate_go(dtrace_hdl_t *);
extern int dt_aggregate_init(dtrace_hdl_t *);
extern void dt_aggregate_destroy(dtrace_hdl_t *);
+extern int dt_consume_init(dtrace_hdl_t *);
+extern void dt_consume_fini(dtrace_hdl_t *);
+
extern dtrace_datadesc_t *dt_datadesc_hold(dtrace_datadesc_t *ddp);
extern void dt_datadesc_release(dtrace_hdl_t *, dtrace_datadesc_t *);
extern dtrace_datadesc_t *dt_datadesc_create(dtrace_hdl_t *);
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index 867a61a30cc5..d3908c0be05a 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -790,7 +790,16 @@ dt_vopen(int version, int flags, int *errp,
*/
dtp->dt_options[DTRACEOPT_STRSIZE] = 256;
- /* Set the default value of maxframes. */
+ /*
+ * Set the default speculation size and number of simultaneously active
+ * speculations.
+ */
+ dtp->dt_options[DTRACEOPT_SPECSIZE] = 1024 * 1024 * 4;
+ dtp->dt_options[DTRACEOPT_NSPEC] = 1;
+
+ /*
+ * Set the default value of maxframes.
+ */
fd = fopen("/proc/sys/kernel/perf_event_max_stack", "r");
assert(fd);
if (fscanf(fd, "%lu", &dtp->dt_options[DTRACEOPT_MAXFRAMES]) != 1)
@@ -1108,6 +1117,12 @@ dt_vopen(int version, int flags, int *errp,
*/
dt_dlib_init(dtp);
+ /*
+ * Initialize consume handling, e.g. storage of uncommitted speculations.
+ */
+ if (dt_consume_init(dtp) < 0)
+ return set_open_errno(dtp, errp, dtp->dt_errno);
+
/*
* Initialize the collection of probes that is made available by the
* known providers.
@@ -1196,6 +1211,8 @@ dtrace_close(dtrace_hdl_t *dtp)
dt_free(dtp, dtp->dt_xlatormap);
+ dt_consume_fini(dtp);
+
for (idp = dtp->dt_externs; idp != NULL; idp = ndp) {
ndp = idp->di_next;
dt_ident_destroy(idp);
diff --git a/libdtrace/dt_peb.h b/libdtrace/dt_peb.h
index 961db93c3837..ab327ec775a2 100644
--- a/libdtrace/dt_peb.h
+++ b/libdtrace/dt_peb.h
@@ -26,6 +26,7 @@ typedef struct dt_peb {
int fd; /* fd of perf output buffer */
char *base; /* address of buffer */
char *endp; /* address of end of buffer */
+ uint64_t last_head; /* last known head, for peeking */
} dt_peb_t;
/*
diff --git a/libdtrace/dtrace.h b/libdtrace/dtrace.h
index 036876facbc0..a05cc4a9f21b 100644
--- a/libdtrace/dtrace.h
+++ b/libdtrace/dtrace.h
@@ -145,12 +145,13 @@ typedef struct dtrace_stmtdesc {
} dtrace_stmtdesc_t;
/* dtsd clause flags */
-#define DT_CLSFLAG_DATAREC 1 /* data-recording */
-#define DT_CLSFLAG_SPECULATE 2 /* speculate */
-#define DT_CLSFLAG_COMMIT 4 /* commit */
-#define DT_CLSFLAG_EXIT 8 /* exit */
-#define DT_CLSFLAG_DESTRUCT 16 /* destructive */
-#define DT_CLSFLAG_AGGREGATION 32 /* aggregation */
+#define DT_CLSFLAG_DATAREC 1 /* data-recording */
+#define DT_CLSFLAG_SPECULATE 2 /* speculate */
+#define DT_CLSFLAG_COMMIT 4 /* commit */
+#define DT_CLSFLAG_COMMIT_DISCARD 8 /* commit/discard */
+#define DT_CLSFLAG_EXIT 16 /* exit */
+#define DT_CLSFLAG_DESTRUCT 32 /* destructive */
+#define DT_CLSFLAG_AGGREGATION 64 /* aggregation */
typedef int dtrace_stmt_f(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
dtrace_stmtdesc_t *sdp, void *data);
diff --git a/test/unittest/speculation/err.CommitWithInvalid.d b/test/unittest/speculation/err.CommitWithInvalid.d
new file mode 100644
index 000000000000..7dc094d4a21e
--- /dev/null
+++ b/test/unittest/speculation/err.CommitWithInvalid.d
@@ -0,0 +1,40 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: When commit() is called with an out-of-range buffer number,
+ * a fault is raised.
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation
+ */
+#pragma D option quiet
+#pragma D option nspec=8
+
+BEGIN
+{
+ self->i = 0;
+}
+
+BEGIN
+{
+ commit(1024);
+}
+
+BEGIN
+{
+ trace("This should not be seen");
+}
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/speculation/err.CommitWithInvalid.r b/test/unittest/speculation/err.CommitWithInvalid.r
new file mode 100644
index 000000000000..a9fd33ad9d30
--- /dev/null
+++ b/test/unittest/speculation/err.CommitWithInvalid.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 4 (ID 1: dtrace:::BEGIN): illegal operation in action #2
diff --git a/test/unittest/speculation/err.D_ACT_SPEC.SpeculateWithCopyOut.d b/test/unittest/speculation/err.D_ACT_SPEC.SpeculateWithCopyOut.d
index aae3e4ff84c1..908e9b9c703f 100644
--- a/test/unittest/speculation/err.D_ACT_SPEC.SpeculateWithCopyOut.d
+++ b/test/unittest/speculation/err.D_ACT_SPEC.SpeculateWithCopyOut.d
@@ -5,7 +5,7 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
+/* @@skip: dtv2, no copyout yet */
/*
* ASSERTION: Destructive actions may never be speculative.
*
diff --git a/test/unittest/speculation/err.D_ACT_SPEC.SpeculateWithCopyOutStr.d b/test/unittest/speculation/err.D_ACT_SPEC.SpeculateWithCopyOutStr.d
index c75d15067c8c..1b23ec3bcbe3 100644
--- a/test/unittest/speculation/err.D_ACT_SPEC.SpeculateWithCopyOutStr.d
+++ b/test/unittest/speculation/err.D_ACT_SPEC.SpeculateWithCopyOutStr.d
@@ -5,7 +5,7 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
+/* @@skip: dtv2, no copyoutstr yet */
/*
* ASSERTION: Destructive actions may never be speculative.
*
diff --git a/test/unittest/speculation/err.D_COMM_COMM.CommitAftCommit.d b/test/unittest/speculation/err.D_COMM_COMM.CommitAftCommit.d
deleted file mode 100644
index 4b20022ccc19..000000000000
--- a/test/unittest/speculation/err.D_COMM_COMM.CommitAftCommit.d
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Oracle Linux DTrace.
- * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
- * Licensed under the Universal Permissive License v 1.0 as shown at
- * http://oss.oracle.com/licenses/upl.
- */
-
-/*
- * ASSERTION:
- * A clause cannot contain multiple commit() calls to same buffer.
- *
- * SECTION: Speculative Tracing/Committing a Speculation;
- * Options and Tunables/cleanrate
- */
-#pragma D option quiet
-#pragma D option cleanrate=3000hz
-
-BEGIN
-{
- self->i = 0;
- var1 = 0;
-}
-
-profile:::tick-1sec
-/!var1/
-{
- var1 = speculation();
- printf("Speculation ID: %d\n", var1);
-}
-
-profile:::tick-1sec
-/var1/
-{
- speculate(var1);
- printf("Speculating on id: %d\n", var1);
- self->i++;
-}
-
-profile:::tick-1sec
-/(!self->i)/
-{
-}
-
-profile:::tick-1sec
-/(self->i)/
-{
- commit(var1);
- commit(var1);
- exit(0);
-}
-
-END
-{
- printf("Succesfully commited both buffers");
- exit(0);
-}
-
-ERROR
-{
- exit(0);
-}
diff --git a/test/unittest/speculation/err.D_COMM_COMM.CommitAftCommit.r b/test/unittest/speculation/err.D_COMM_COMM.CommitAftCommit.r
deleted file mode 100644
index a687cd0b6d34..000000000000
--- a/test/unittest/speculation/err.D_COMM_COMM.CommitAftCommit.r
+++ /dev/null
@@ -1,2 +0,0 @@
--- @@stderr --
-dtrace: failed to compile script test/unittest/speculation/err.D_COMM_COMM.CommitAftCommit.d: [D_COMM_COMM] line 48: commit( ) may not follow commit( )
diff --git a/test/unittest/speculation/err.D_COMM_COMM.DisjointCommit.d b/test/unittest/speculation/err.D_COMM_COMM.DisjointCommit.d
deleted file mode 100644
index 24c7ae7d6231..000000000000
--- a/test/unittest/speculation/err.D_COMM_COMM.DisjointCommit.d
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Oracle Linux DTrace.
- * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
- * Licensed under the Universal Permissive License v 1.0 as shown at
- * http://oss.oracle.com/licenses/upl.
- */
-
-/*
- * ASSERTION:
- * A clause cannot contain multiple commit() calls to disjoint buffers.
- *
- * SECTION: Speculative Tracing/Committing a Speculation;
- * Options and Tunables/cleanrate
- */
-#pragma D option quiet
-#pragma D option cleanrate=3000hz
-
-BEGIN
-{
- self->i = 0;
- self->j = 0;
- self->commit = 0;
- var1 = 0;
- var2 = 0;
-}
-
-BEGIN
-{
- var1 = speculation();
- printf("Speculation ID: %d\n", var1);
-}
-
-BEGIN
-{
- var2 = speculation();
- printf("Speculation ID: %d\n", var2);
-}
-
-BEGIN
-/var1/
-{
- speculate(var1);
- printf("Speculating on id: %d\n", var1);
- self->i++;
-}
-
-BEGIN
-/var2/
-{
- speculate(var2);
- printf("Speculating on id: %d", var2);
- self->j++;
-
-}
-
-BEGIN
-/(self->i) && (self->j)/
-{
- commit(var1);
- commit(var2);
- self->commit++;
-}
-
-BEGIN
-/self->commit/
-{
- printf("Succesfully commited both buffers");
- exit(0);
-}
-
-BEGIN
-/!self->commit/
-{
- printf("Couldnt commit both buffers");
- exit(1);
-}
-
-ERROR
-{
- exit(1);
-}
diff --git a/test/unittest/speculation/err.D_COMM_COMM.DisjointCommit.r b/test/unittest/speculation/err.D_COMM_COMM.DisjointCommit.r
deleted file mode 100644
index ae18ddf58396..000000000000
--- a/test/unittest/speculation/err.D_COMM_COMM.DisjointCommit.r
+++ /dev/null
@@ -1,2 +0,0 @@
--- @@stderr --
-dtrace: failed to compile script test/unittest/speculation/err.D_COMM_COMM.DisjointCommit.d: [D_COMM_COMM] line 60: commit( ) may not follow commit( )
diff --git a/test/unittest/speculation/tst.ExitAftDiscard.d b/test/unittest/speculation/err.DiscardWithInvalid.d
similarity index 51%
copy from test/unittest/speculation/tst.ExitAftDiscard.d
copy to test/unittest/speculation/err.DiscardWithInvalid.d
index 758c1554a0af..15ad11908646 100644
--- a/test/unittest/speculation/tst.ExitAftDiscard.d
+++ b/test/unittest/speculation/err.DiscardWithInvalid.d
@@ -1,36 +1,40 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
- * ASSERTION: Using exit after discard should work fine.
+ * ASSERTION: When discard() is called with an out-of-range buffer number,
+ * a fault is raised.
*
* SECTION: Speculative Tracing/Discarding a Speculation
- *
*/
#pragma D option quiet
+#pragma D option nspec=8
BEGIN
{
self->i = 0;
- self->spec = speculation();
}
BEGIN
-/self->spec/
{
- speculate(self->spec);
- self->i++;
- printf("self->i: %d\n", self->i);
+ discard(1024);
+}
+
+BEGIN
+{
+ trace("This should not be seen");
}
BEGIN
-/self->i/
{
- discard(self->spec);
exit(0);
}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/speculation/err.DiscardWithInvalid.r b/test/unittest/speculation/err.DiscardWithInvalid.r
new file mode 100644
index 000000000000..a9fd33ad9d30
--- /dev/null
+++ b/test/unittest/speculation/err.DiscardWithInvalid.r
@@ -0,0 +1,3 @@
+
+-- @@stderr --
+dtrace: error on enabled probe ID 4 (ID 1: dtrace:::BEGIN): illegal operation in action #2
diff --git a/test/unittest/speculation/err.SpecSizeVariations1.d b/test/unittest/speculation/err.SpecSizeVariations1.d
deleted file mode 100644
index 05fb2cf632e9..000000000000
--- a/test/unittest/speculation/err.SpecSizeVariations1.d
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Oracle Linux DTrace.
- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
- * Licensed under the Universal Permissive License v 1.0 as shown at
- * http://oss.oracle.com/licenses/upl.
- */
-/* @@xfail: dtv2 */
-
-/*
- * ASSERTION:
- * Verify the behavior of variations in specsize.
- *
- * SECTION: Speculative Tracing/Options and Tuning;
- * Options and Tunables/specsize
- *
- */
-
-#pragma D option quiet
-#pragma D option specsize=0
-
-BEGIN
-{
- self->speculateFlag = 0;
- self->commitFlag = 0;
- self->spec = speculation();
- printf("Speculative buffer ID: %d\n", self->spec);
-}
-
-BEGIN
-{
- speculate(self->spec);
- printf("Lots of data\n");
- printf("Has to be crammed into this buffer\n");
- printf("Until it overflows\n");
- printf("And causes flops\n");
- self->speculateFlag++;
-
-}
-
-BEGIN
-/1 <= self->speculateFlag/
-{
- commit(self->spec);
- self->commitFlag++;
-}
-
-BEGIN
-/1 <= self->commitFlag/
-{
- printf("Statement was executed\n");
- exit(0);
-}
-
-BEGIN
-/1 > self->commitFlag/
-{
- printf("Statement wasn't executed\n");
- exit(1);
-}
diff --git a/test/unittest/speculation/err.SpecSizeVariations1.r b/test/unittest/speculation/err.SpecSizeVariations1.r
deleted file mode 100644
index daca8b5083ff..000000000000
--- a/test/unittest/speculation/err.SpecSizeVariations1.r
+++ /dev/null
@@ -1,2 +0,0 @@
--- @@stderr --
-dtrace: could not enable tracing: Enabling exceeds size of buffer
diff --git a/test/unittest/speculation/err.SpecSizeVariations2.d b/test/unittest/speculation/err.SpecSizeVariations2.d
deleted file mode 100644
index 9685d2400e58..000000000000
--- a/test/unittest/speculation/err.SpecSizeVariations2.d
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Oracle Linux DTrace.
- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
- * Licensed under the Universal Permissive License v 1.0 as shown at
- * http://oss.oracle.com/licenses/upl.
- */
-/* @@xfail: dtv2 */
-
-/*
- * ASSERTION:
- * Verify the behavior of variations in specsize.
- *
- * SECTION: Speculative Tracing/Options and Tuning;
- * Options and Tunables/specsize
- *
- */
-
-#pragma D option quiet
-#pragma D option specsize=7
-
-BEGIN
-{
- self->speculateFlag = 0;
- self->commitFlag = 0;
- self->spec = speculation();
- printf("Speculative buffer ID: %d\n", self->spec);
-}
-
-BEGIN
-{
- speculate(self->spec);
- printf("Lots of data\n");
- printf("Has to be crammed into this buffer\n");
- printf("Until it overflows\n");
- printf("And causes flops\n");
- self->speculateFlag++;
-
-}
-
-BEGIN
-/1 <= self->speculateFlag/
-{
- commit(self->spec);
- self->commitFlag++;
-}
-
-BEGIN
-/1 <= self->commitFlag/
-{
- printf("Statement was executed\n");
- exit(0);
-}
-
-BEGIN
-/1 > self->commitFlag/
-{
- printf("Statement wasn't executed\n");
- exit(1);
-}
diff --git a/test/unittest/speculation/err.SpecSizeVariations2.r b/test/unittest/speculation/err.SpecSizeVariations2.r
deleted file mode 100644
index daca8b5083ff..000000000000
--- a/test/unittest/speculation/err.SpecSizeVariations2.r
+++ /dev/null
@@ -1,2 +0,0 @@
--- @@stderr --
-dtrace: could not enable tracing: Enabling exceeds size of buffer
diff --git a/test/unittest/speculation/tst.CommitAfterDiscard.d b/test/unittest/speculation/tst.CommitAfterDiscard.d
index b07222179e16..49456cdd4521 100644
--- a/test/unittest/speculation/tst.CommitAfterDiscard.d
+++ b/test/unittest/speculation/tst.CommitAfterDiscard.d
@@ -4,19 +4,16 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION:
* Call to commit() on a buffer after it has been discarded is silently
* ignored.
*
- * SECTION: Speculative Tracing/Committing a Speculation;
- * Options and Tunables/cleanrate
+ * SECTION: Speculative Tracing/Committing a Speculation
*
*/
#pragma D option quiet
-#pragma D option cleanrate=3000hz
BEGIN
{
@@ -48,7 +45,7 @@ BEGIN
BEGIN
/self->commit/
{
- printf("Commited a discarded buffer\n");
+ printf("Committed a discarded buffer\n");
exit(0);
}
@@ -56,7 +53,7 @@ BEGIN
BEGIN
/!self->commit/
{
- printf("Couldnt commit a discarded buffer\n");
+ printf("Couldn't commit a discarded buffer\n");
exit(1);
}
diff --git a/test/unittest/speculation/tst.CommitAfterDiscard.r b/test/unittest/speculation/tst.CommitAfterDiscard.r
index 3674e24e5bc4..8ae7a38ec525 100644
--- a/test/unittest/speculation/tst.CommitAfterDiscard.r
+++ b/test/unittest/speculation/tst.CommitAfterDiscard.r
@@ -1,3 +1,3 @@
Speculation ID: 1
-Commited a discarded buffer
+Committed a discarded buffer
diff --git a/test/unittest/speculation/tst.CommitCommitCommit.d b/test/unittest/speculation/tst.CommitCommitCommit.d
new file mode 100644
index 000000000000..e91d0d05db22
--- /dev/null
+++ b/test/unittest/speculation/tst.CommitCommitCommit.d
@@ -0,0 +1,58 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: A clause can have multiple commits.
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation
+ *
+ */
+#pragma D option quiet
+#pragma D option nspec=3
+
+BEGIN
+{
+ i = speculation();
+ j = speculation();
+ k = speculation();
+ printf("Speculation IDs: %d %d %d\n", i, j, k);
+}
+
+BEGIN
+{
+ speculate(i);
+ printf("Speculating on id: %d\n", i);
+}
+
+BEGIN
+{
+ speculate(j);
+ printf("Speculating on id: %d\n", j);
+}
+
+BEGIN
+{
+ speculate(k);
+ printf("Speculating on id: %d\n", k);
+}
+
+BEGIN
+{
+ commit(k);
+ commit(j);
+ commit(i);
+}
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/speculation/tst.CommitCommitCommit.r b/test/unittest/speculation/tst.CommitCommitCommit.r
new file mode 100644
index 000000000000..bce7ae388a20
--- /dev/null
+++ b/test/unittest/speculation/tst.CommitCommitCommit.r
@@ -0,0 +1,5 @@
+Speculation IDs: 1 2 3
+Speculating on id: 3
+Speculating on id: 2
+Speculating on id: 1
+
diff --git a/test/unittest/speculation/tst.CommitDiscard4x.d b/test/unittest/speculation/tst.CommitDiscard4x.d
new file mode 100644
index 000000000000..3a1f5b04f907
--- /dev/null
+++ b/test/unittest/speculation/tst.CommitDiscard4x.d
@@ -0,0 +1,99 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: A clause can have multiple commits and discards.
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation
+ *
+ */
+#pragma D option quiet
+#pragma D option nspec=8
+
+BEGIN
+{
+ a = speculation();
+ b = speculation();
+ c = speculation();
+ d = speculation();
+ e = speculation();
+ f = speculation();
+ g = speculation();
+ h = speculation();
+ printf("Speculation IDs: %d %d %d %d %d %d %d %d\n",
+ a, b, c, d, e, f, g, h);
+}
+
+BEGIN
+{
+ speculate(a);
+ printf("Speculating on id: %d\n", a);
+}
+
+BEGIN
+{
+ speculate(b);
+ printf("Speculating on id: %d\n", b);
+}
+
+BEGIN
+{
+ speculate(c);
+ printf("Speculating on id: %d\n", c);
+}
+
+BEGIN
+{
+ speculate(d);
+ printf("Speculating on id: %d\n", d);
+}
+
+BEGIN
+{
+ speculate(e);
+ printf("Speculating on id: %d\n", e);
+}
+
+BEGIN
+{
+ speculate(f);
+ printf("Speculating on id: %d\n", f);
+}
+
+BEGIN
+{
+ speculate(g);
+ printf("Speculating on id: %d\n", g);
+}
+
+BEGIN
+{
+ speculate(h);
+ printf("Speculating on id: %d\n", h);
+}
+
+BEGIN
+{
+ commit(h);
+ discard(g);
+ commit(f);
+ discard(e);
+ commit(d);
+ discard(c);
+ commit(b);
+ discard(a);
+}
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/speculation/tst.CommitDiscard4x.r b/test/unittest/speculation/tst.CommitDiscard4x.r
new file mode 100644
index 000000000000..b6bbe9d26851
--- /dev/null
+++ b/test/unittest/speculation/tst.CommitDiscard4x.r
@@ -0,0 +1,6 @@
+Speculation IDs: 1 2 3 4 5 6 7 8
+Speculating on id: 8
+Speculating on id: 6
+Speculating on id: 4
+Speculating on id: 2
+
diff --git a/test/unittest/speculation/tst.CommitWithInactive.d b/test/unittest/speculation/tst.CommitWithInactive.d
new file mode 100644
index 000000000000..17bfe52ba7cf
--- /dev/null
+++ b/test/unittest/speculation/tst.CommitWithInactive.d
@@ -0,0 +1,38 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: When commit() is called with an inactive buffer number,
+ * it is ignored.
+ *
+ * SECTION: Speculative Tracing/Comitting a Speculation
+ */
+#pragma D option quiet
+BEGIN
+{
+ self->i = 0;
+}
+
+BEGIN
+{
+ commit(1);
+}
+
+BEGIN
+{
+ trace("This should be seen");
+}
+
+BEGIN
+{
+ exit(0);
+}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/speculation/tst.CommitWithInactive.r b/test/unittest/speculation/tst.CommitWithInactive.r
new file mode 100644
index 000000000000..5c6e69bdcfe1
--- /dev/null
+++ b/test/unittest/speculation/tst.CommitWithInactive.r
@@ -0,0 +1 @@
+This should be seen
diff --git a/test/unittest/speculation/tst.CommitWithZero.d b/test/unittest/speculation/tst.CommitWithZero.d
index dbc6dc06e8b8..9246d1de64d4 100644
--- a/test/unittest/speculation/tst.CommitWithZero.d
+++ b/test/unittest/speculation/tst.CommitWithZero.d
@@ -4,30 +4,23 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION: An Id of zero though invalid may be passed to speculate(),
* commit() and discard() without any ill effects.
*
- * SECTION: Speculative Tracing/Creating a Speculation;
- * Options and Tunables/cleanrate
+ * SECTION: Speculative Tracing/Creating a Speculation
*/
#pragma D option quiet
-#pragma D option cleanrate=4000hz
BEGIN
{
self->commitFlag = 0;
- self->var1 = speculation();
- printf("Speculative buffer ID: %d\n", self->var1);
- self->spec = speculation();
- printf("Speculative buffer ID: %d\n", self->spec);
}
BEGIN
{
- commit(self->spec);
+ commit(0);
self->commitFlag++;
}
diff --git a/test/unittest/speculation/tst.CommitWithZero.r b/test/unittest/speculation/tst.CommitWithZero.r
index 507400da55a4..7534ce772b29 100644
--- a/test/unittest/speculation/tst.CommitWithZero.r
+++ b/test/unittest/speculation/tst.CommitWithZero.r
@@ -1,6 +1,2 @@
-Speculative buffer ID: 1
-Speculative buffer ID: 0
commit(), self->commitFlag = 1
--- @@stderr --
-dtrace: 1 failed speculation (no speculative buffer available)
diff --git a/test/unittest/speculation/tst.DataRecAftDiscard.d b/test/unittest/speculation/tst.DataRecAftDiscard.d
index e262604e5910..23601df39ff9 100644
--- a/test/unittest/speculation/tst.DataRecAftDiscard.d
+++ b/test/unittest/speculation/tst.DataRecAftDiscard.d
@@ -4,17 +4,14 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION:
* Data recording actions may follow discard.
*
- * SECTION: Speculative Tracing/Discarding a Speculation;
- * Options and Tunables/cleanrate
+ * SECTION: Speculative Tracing/Discarding a Speculation
*/
#pragma D option quiet
-#pragma D option cleanrate=2000hz
BEGIN
{
diff --git a/test/unittest/speculation/tst.DiscardAftCommit.d b/test/unittest/speculation/tst.DiscardAftCommit.d
index ca4a0645c00f..7b7e0e6896c1 100644
--- a/test/unittest/speculation/tst.DiscardAftCommit.d
+++ b/test/unittest/speculation/tst.DiscardAftCommit.d
@@ -4,18 +4,16 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION:
- * Can call discard() on a buffer after it has been commited.
+ * Can call discard() on a buffer after it has been committed.
*
- * SECTION: Speculative Tracing/Discarding a Speculation;
- * Options and Tunables/cleanrate
+ * SECTION: Speculative Tracing/Discarding a Speculation
*
*/
+
#pragma D option quiet
-#pragma D option cleanrate=3000hz
BEGIN
{
@@ -47,7 +45,7 @@ BEGIN
BEGIN
/self->discard/
{
- printf("Discarded a commited buffer\n");
+ printf("Discarded a committed buffer\n");
exit(0);
}
@@ -55,7 +53,7 @@ BEGIN
BEGIN
/!self->discard/
{
- printf("Couldnt discard a commited buffer\n");
+ printf("Couldn't discard a committed buffer\n");
exit(1);
}
diff --git a/test/unittest/speculation/tst.DiscardAftCommit.r b/test/unittest/speculation/tst.DiscardAftCommit.r
index 3f960663fd8c..004727149781 100644
--- a/test/unittest/speculation/tst.DiscardAftCommit.r
+++ b/test/unittest/speculation/tst.DiscardAftCommit.r
@@ -1,5 +1,5 @@
Speculation ID: 1
This statement and the following are speculative!!
Speculating on id: 1
-Discarded a commited buffer
+Discarded a committed buffer
diff --git a/test/unittest/speculation/tst.DiscardAftDataRec.d b/test/unittest/speculation/tst.DiscardAftDataRec.d
index 3d7df87ef838..740016648c11 100644
--- a/test/unittest/speculation/tst.DiscardAftDataRec.d
+++ b/test/unittest/speculation/tst.DiscardAftDataRec.d
@@ -4,11 +4,10 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION:
- * Discard may not follow data recording actions.
+ * Discard may follow data recording actions.
*
* SECTION: Speculative Tracing/Discarding a Speculation
*
diff --git a/test/unittest/speculation/tst.DiscardAftDiscard.d b/test/unittest/speculation/tst.DiscardAftDiscard.d
index d6231e2cca5c..1f5ae2b9740c 100644
--- a/test/unittest/speculation/tst.DiscardAftDiscard.d
+++ b/test/unittest/speculation/tst.DiscardAftDiscard.d
@@ -4,18 +4,15 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION:
* Can call discard on an already discarded buffer.
*
- * SECTION: Speculative Tracing/Discarding a Speculation;
- * Options and Tunables/cleanrate
+ * SECTION: Speculative Tracing/Discarding a Speculation
*
*/
#pragma D option quiet
-#pragma D option cleanrate=3000hz
BEGIN
{
@@ -55,7 +52,7 @@ BEGIN
BEGIN
/(!self->discard2) || (!self->discard1)/
{
- printf("Couldnt discard a discarded buffer\n");
+ printf("Couldn't discard a discarded buffer\n");
exit(1);
}
diff --git a/test/unittest/speculation/tst.ExitAftDiscard.d b/test/unittest/speculation/tst.DiscardWithInactive.d
similarity index 51%
copy from test/unittest/speculation/tst.ExitAftDiscard.d
copy to test/unittest/speculation/tst.DiscardWithInactive.d
index 758c1554a0af..4228244bfa3d 100644
--- a/test/unittest/speculation/tst.ExitAftDiscard.d
+++ b/test/unittest/speculation/tst.DiscardWithInactive.d
@@ -1,36 +1,38 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
- * ASSERTION: Using exit after discard should work fine.
+ * ASSERTION: When discard() is called with an inactive buffer number,
+ * it is ignored.
*
* SECTION: Speculative Tracing/Discarding a Speculation
- *
*/
#pragma D option quiet
-
BEGIN
{
self->i = 0;
- self->spec = speculation();
}
BEGIN
-/self->spec/
{
- speculate(self->spec);
- self->i++;
- printf("self->i: %d\n", self->i);
+ discard(1);
+}
+
+BEGIN
+{
+ trace("This should be seen");
}
BEGIN
-/self->i/
{
- discard(self->spec);
exit(0);
}
+
+ERROR
+{
+ exit(1);
+}
diff --git a/test/unittest/speculation/tst.DiscardWithInactive.r b/test/unittest/speculation/tst.DiscardWithInactive.r
new file mode 100644
index 000000000000..5c6e69bdcfe1
--- /dev/null
+++ b/test/unittest/speculation/tst.DiscardWithInactive.r
@@ -0,0 +1 @@
+This should be seen
diff --git a/test/unittest/speculation/tst.DiscardWithZero.d b/test/unittest/speculation/tst.DiscardWithZero.d
index 8ff2d43d9fe5..98c1f1bfde8e 100644
--- a/test/unittest/speculation/tst.DiscardWithZero.d
+++ b/test/unittest/speculation/tst.DiscardWithZero.d
@@ -4,31 +4,23 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION: An Id of zero though invalid may be passed to speculate(),
* commit() and discard() without any ill effects.
*
- * SECTION: Speculative Tracing/Creating a Speculation;
- * Options and Tunables/cleanrate
+ * SECTION: Speculative Tracing/Creating a Speculation
*/
#pragma D option quiet
-#pragma D option cleanrate=4000hz
BEGIN
{
self->discardFlag = 0;
- self->var1 = speculation();
- printf("Speculative buffer ID: %d\n", self->var1);
- self->spec = speculation();
- printf("Speculative buffer ID: %d\n", self->spec);
}
BEGIN
-/0 == self->spec/
{
- discard(self->spec);
+ discard(0);
self->discardFlag++;
}
diff --git a/test/unittest/speculation/tst.DiscardWithZero.r b/test/unittest/speculation/tst.DiscardWithZero.r
index e4a7cb7f9528..f356261e2522 100644
--- a/test/unittest/speculation/tst.DiscardWithZero.r
+++ b/test/unittest/speculation/tst.DiscardWithZero.r
@@ -1,6 +1,2 @@
-Speculative buffer ID: 1
-Speculative buffer ID: 0
discard(), self->discardFlag = 1
--- @@stderr --
-dtrace: 1 failed speculation (no speculative buffer available)
diff --git a/test/unittest/speculation/tst.ExitAftDiscard.d b/test/unittest/speculation/tst.ExitAftDiscard.d
index 758c1554a0af..cbe32a572ee4 100644
--- a/test/unittest/speculation/tst.ExitAftDiscard.d
+++ b/test/unittest/speculation/tst.ExitAftDiscard.d
@@ -4,7 +4,6 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION: Using exit after discard should work fine.
diff --git a/test/unittest/speculation/tst.NoSpecBuffer.d b/test/unittest/speculation/tst.NoSpecBuffer.d
index a3a2107c7132..da138e364f30 100644
--- a/test/unittest/speculation/tst.NoSpecBuffer.d
+++ b/test/unittest/speculation/tst.NoSpecBuffer.d
@@ -5,18 +5,18 @@
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/* @@trigger: none */
/*
* ASSERTION:
- * The number of speculative buffers defaults to one. If no speculative buffer
- * is available when speculation is called, an ID of zero is returned.
+ * If no speculative buffer is available when speculation is called,
+ * an ID of zero is returned.
*
* SECTION: Speculative Tracing/Creating a Speculation
*
*/
#pragma D option quiet
+#pragma D option nspec=1
BEGIN
{
diff --git a/test/unittest/speculation/tst.NoSpecBuffer.r b/test/unittest/speculation/tst.NoSpecBuffer.r
index 8d6f9d2c8946..88d21d7ca4f7 100644
--- a/test/unittest/speculation/tst.NoSpecBuffer.r
+++ b/test/unittest/speculation/tst.NoSpecBuffer.r
@@ -1,5 +1,3 @@
Speculative buffer ID: 1
Speculative buffer ID: 0
i: 2 self->spec: 0
--- @@stderr --
-dtrace: 1 failed speculation (no speculative buffer available)
diff --git a/test/unittest/speculation/tst.SingleCPU.d b/test/unittest/speculation/tst.SingleCPU.d
new file mode 100644
index 000000000000..a1cb4612a81b
--- /dev/null
+++ b/test/unittest/speculation/tst.SingleCPU.d
@@ -0,0 +1,69 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Verify many speculations (single-CPU case).
+ *
+ * SECTION: Speculative Tracing
+ */
+
+#pragma D option quiet
+
+/* This test should take only 10s, but is taking much longer than the 10s
+ one would expect (48s here). Boosting timeout temporarily. */
+/* @@timeout: 120 */
+
+BEGIN
+{
+ n = 0;
+}
+
+/*
+ * Each tick, n is incremented. Which clause is used rotates modulo 4.
+ * 0: get a specid
+ * 1: speculate some output
+ * 2: speculate some other output
+ * 3: commit (sometimes) or discard (usually)
+ */
+
+tick-10ms
+/ (n & 3) == 0 /
+{
+ i = speculation();
+}
+
+tick-10ms
+/ (n & 3) == 1 /
+{
+ speculate(i);
+ printf("%4d %4d", n, i);
+}
+
+tick-10ms
+/ (n & 3) == 2 /
+{
+ speculate(i);
+ printf("%4d hello world\n", n);
+}
+
+tick-10ms
+/ (n & 3) == 3 && (n & 63) == 3 /
+{
+ commit(i);
+}
+
+tick-10ms
+/ (n & 3) == 3 && (n & 63) != 3 /
+{
+ discard(i);
+}
+
+tick-10ms
+/ n++ >= 1000 /
+{
+ exit(0);
+}
diff --git a/test/unittest/speculation/tst.SingleCPU.r b/test/unittest/speculation/tst.SingleCPU.r
new file mode 100644
index 000000000000..3659925d10b0
--- /dev/null
+++ b/test/unittest/speculation/tst.SingleCPU.r
@@ -0,0 +1,17 @@
+ 1 1 2 hello world
+ 65 1 66 hello world
+ 129 1 130 hello world
+ 193 1 194 hello world
+ 257 1 258 hello world
+ 321 1 322 hello world
+ 385 1 386 hello world
+ 449 1 450 hello world
+ 513 1 514 hello world
+ 577 1 578 hello world
+ 641 1 642 hello world
+ 705 1 706 hello world
+ 769 1 770 hello world
+ 833 1 834 hello world
+ 897 1 898 hello world
+ 961 1 962 hello world
+
diff --git a/test/unittest/speculation/tst.SpecSizeVariations3.d b/test/unittest/speculation/tst.SpecSizeVariations3.d
deleted file mode 100644
index 9ba2d1ebf9d9..000000000000
--- a/test/unittest/speculation/tst.SpecSizeVariations3.d
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Oracle Linux DTrace.
- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
- * Licensed under the Universal Permissive License v 1.0 as shown at
- * http://oss.oracle.com/licenses/upl.
- */
-/* @@xfail: dtv2 */
-
-/*
- * ASSERTION:
- * Verify the behavior of speculations with changes in specsize.
- *
- * SECTION: Speculative Tracing/Options and Tuning;
- * Options and Tunables/specsize
- *
- */
-
-#pragma D option quiet
-#pragma D option specsize=8
-
-BEGIN
-{
- self->speculateFlag = 0;
- self->commitFlag = 0;
- self->spec = speculation();
- printf("Speculative buffer ID: %d\n", self->spec);
-}
-
-BEGIN
-{
- speculate(self->spec);
- printf("Lots of data\n");
- printf("Has to be crammed into this buffer\n");
- printf("Until it overflows\n");
- printf("And causes flops\n");
- self->speculateFlag++;
-
-}
-
-BEGIN
-/1 <= self->speculateFlag/
-{
- commit(self->spec);
- self->commitFlag++;
-}
-
-BEGIN
-/1 <= self->commitFlag/
-{
- printf("Statement was executed\n");
- exit(1);
-}
-
-BEGIN
-/1 > self->commitFlag/
-{
- printf("Statement wasn't executed\n");
- exit(0);
-}
diff --git a/test/unittest/speculation/tst.SpecSizeVariations3.r b/test/unittest/speculation/tst.SpecSizeVariations3.r
deleted file mode 100644
index 41ccfc14c78c..000000000000
--- a/test/unittest/speculation/tst.SpecSizeVariations3.r
+++ /dev/null
@@ -1,3 +0,0 @@
-Speculative buffer ID: 1
-Statement wasn't executed
-
diff --git a/test/unittest/speculation/tst.SpecSizeVariations4.d b/test/unittest/speculation/tst.SpecSizeVariations4.d
index 342ea316a219..17c6eab6118c 100644
--- a/test/unittest/speculation/tst.SpecSizeVariations4.d
+++ b/test/unittest/speculation/tst.SpecSizeVariations4.d
@@ -4,7 +4,6 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION:
@@ -18,8 +17,11 @@
#pragma D option quiet
#pragma D option specsize=39
+long long x;
+
BEGIN
{
+ x = 123456789;
self->speculateFlag = 0;
self->commitFlag = 0;
self->spec = speculation();
@@ -29,10 +31,10 @@ BEGIN
BEGIN
{
speculate(self->spec);
- printf("Lots of data\n");
- printf("Has to be crammed into this buffer\n");
- printf("Until it overflows\n");
- printf("And causes flops\n");
+ printf("%lld: Lots of data\n", x);
+ printf("%lld: Has to be crammed into this buffer\n", x);
+ printf("%lld: Until it overflows\n", x);
+ printf("%lld: And causes flops\n", x);
self->speculateFlag++;
}
@@ -48,12 +50,12 @@ BEGIN
/1 <= self->commitFlag/
{
printf("Statement was executed\n");
- exit(1);
+ exit(0);
}
BEGIN
/1 > self->commitFlag/
{
printf("Statement wasn't executed\n");
- exit(0);
+ exit(1);
}
diff --git a/test/unittest/speculation/tst.SpecSizeVariations4.r b/test/unittest/speculation/tst.SpecSizeVariations4.r
index 41ccfc14c78c..719e2441d27d 100644
--- a/test/unittest/speculation/tst.SpecSizeVariations4.r
+++ b/test/unittest/speculation/tst.SpecSizeVariations4.r
@@ -1,3 +1,3 @@
Speculative buffer ID: 1
-Statement wasn't executed
+Statement was executed
diff --git a/test/unittest/speculation/tst.SpecSizeVariations5.d b/test/unittest/speculation/tst.SpecSizeVariations5.d
index 4e90fbb1feca..cfbd885a5cdd 100644
--- a/test/unittest/speculation/tst.SpecSizeVariations5.d
+++ b/test/unittest/speculation/tst.SpecSizeVariations5.d
@@ -4,7 +4,6 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION:
@@ -18,8 +17,11 @@
#pragma D option quiet
#pragma D option specsize=40
+long long x;
+
BEGIN
{
+ x = 123456789;
self->speculateFlag = 0;
self->commitFlag = 0;
self->spec = speculation();
@@ -29,10 +31,10 @@ BEGIN
BEGIN
{
speculate(self->spec);
- printf("Lots of data\n");
- printf("Has to be crammed into this buffer\n");
- printf("Until it overflows\n");
- printf("And causes flops\n");
+ printf("%lld: Lots of data\n", x);
+ printf("%lld: Has to be crammed into this buffer\n", x);
+ printf("%lld: Until it overflows\n", x);
+ printf("%lld: And causes flops\n", x);
self->speculateFlag++;
}
diff --git a/test/unittest/speculation/tst.SpecSizeVariations5.r b/test/unittest/speculation/tst.SpecSizeVariations5.r
index da44024d5ffe..d09013a2ae19 100644
--- a/test/unittest/speculation/tst.SpecSizeVariations5.r
+++ b/test/unittest/speculation/tst.SpecSizeVariations5.r
@@ -1,7 +1,7 @@
Speculative buffer ID: 1
-Lots of data
-Has to be crammed into this buffer
-Until it overflows
-And causes flops
+123456789: Lots of data
+123456789: Has to be crammed into this buffer
+123456789: Until it overflows
+123456789: And causes flops
Statement was executed
diff --git a/test/unittest/speculation/tst.SpeculationCommit.d b/test/unittest/speculation/tst.SpeculationCommit.d
index 554f5339db11..957042367b08 100644
--- a/test/unittest/speculation/tst.SpeculationCommit.d
+++ b/test/unittest/speculation/tst.SpeculationCommit.d
@@ -4,18 +4,15 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION: Test the normal behavior of speculate() and commit().
*
* SECTION: Speculative Tracing/Committing a Speculation;
- * Actions and Subroutines/speculation();
- * Options and Tunables/cleanrate
+ * Actions and Subroutines/speculation()
*
*/
#pragma D option quiet
-#pragma D option cleanrate=2000hz
BEGIN
{
diff --git a/test/unittest/speculation/tst.SpeculationCommit.d b/test/unittest/speculation/tst.SpeculationCommitNotQuiet.d
similarity index 78%
copy from test/unittest/speculation/tst.SpeculationCommit.d
copy to test/unittest/speculation/tst.SpeculationCommitNotQuiet.d
index 554f5339db11..322eefeac799 100644
--- a/test/unittest/speculation/tst.SpeculationCommit.d
+++ b/test/unittest/speculation/tst.SpeculationCommitNotQuiet.d
@@ -1,21 +1,18 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
- * ASSERTION: Test the normal behavior of speculate() and commit().
+ * ASSERTION: Test the normal behavior of speculate() and commit() with
+ * quiet mode turned off.
*
* SECTION: Speculative Tracing/Committing a Speculation;
- * Actions and Subroutines/speculation();
- * Options and Tunables/cleanrate
+ * Actions and Subroutines/speculation()
*
*/
-#pragma D option quiet
-#pragma D option cleanrate=2000hz
BEGIN
{
diff --git a/test/unittest/speculation/tst.SpeculationCommitNotQuiet.r b/test/unittest/speculation/tst.SpeculationCommitNotQuiet.r
new file mode 100644
index 000000000000..635f849a4df1
--- /dev/null
+++ b/test/unittest/speculation/tst.SpeculationCommitNotQuiet.r
@@ -0,0 +1,10 @@
+ FUNCTION:NAME
+ :BEGIN Speculation ID: 1
+
+ :BEGIN Called speculate on id: 1
+
+ :BEGIN Succesfully tested buffer commit
+
+-- @@stderr --
+dtrace: script 'test/unittest/speculation/tst.SpeculationCommitNotQuiet.d' matched 5 probes
+
diff --git a/test/unittest/speculation/tst.SpeculationDefault.d b/test/unittest/speculation/tst.SpeculationDefault.d
new file mode 100644
index 000000000000..aeeeb64d9956
--- /dev/null
+++ b/test/unittest/speculation/tst.SpeculationDefault.d
@@ -0,0 +1,31 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Test the normal behavior of a speculative default clause
+ * with quiet mode turned off.
+ *
+ * SECTION: Actions and Subroutines/speculation()
+ *
+ */
+
+BEGIN
+{
+ self->spec = speculation();
+}
+
+BEGIN
+/self->spec/
+{
+ speculate(self->spec);
+}
+
+BEGIN
+/self->spec/
+{
+ exit(0);
+}
diff --git a/test/unittest/speculation/tst.SpeculationDefault.r b/test/unittest/speculation/tst.SpeculationDefault.r
new file mode 100644
index 000000000000..b39c2480397c
--- /dev/null
+++ b/test/unittest/speculation/tst.SpeculationDefault.r
@@ -0,0 +1,5 @@
+ FUNCTION:NAME
+ :BEGIN
+
+-- @@stderr --
+dtrace: script 'test/unittest/speculation/tst.SpeculationDefault.d' matched 3 probes
diff --git a/test/unittest/speculation/tst.SpeculationDefaultCommit.d b/test/unittest/speculation/tst.SpeculationDefaultCommit.d
new file mode 100644
index 000000000000..6a8e20434c93
--- /dev/null
+++ b/test/unittest/speculation/tst.SpeculationDefaultCommit.d
@@ -0,0 +1,38 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Test the normal behavior when committing a speculative
+ * default clause with quiet mode turned off.
+ *
+ * SECTION: Speculative Tracing/Committing a Speculation;
+ * Actions and Subroutines/speculation()
+ *
+ */
+
+BEGIN
+{
+ self->spec = speculation();
+}
+
+BEGIN
+/self->spec/
+{
+ speculate(self->spec);
+}
+
+BEGIN
+/self->spec/
+{
+ commit(self->spec);
+}
+
+BEGIN
+/self->spec/
+{
+ exit(0);
+}
diff --git a/test/unittest/speculation/tst.SpeculationDefaultCommit.r b/test/unittest/speculation/tst.SpeculationDefaultCommit.r
new file mode 100644
index 000000000000..8d09be3ad3e4
--- /dev/null
+++ b/test/unittest/speculation/tst.SpeculationDefaultCommit.r
@@ -0,0 +1,6 @@
+ FUNCTION:NAME
+ :BEGIN
+ :BEGIN
+
+-- @@stderr --
+dtrace: script 'test/unittest/speculation/tst.SpeculationDefaultCommit.d' matched 4 probes
diff --git a/test/unittest/speculation/tst.SpeculationDefaultDiscard.d b/test/unittest/speculation/tst.SpeculationDefaultDiscard.d
new file mode 100644
index 000000000000..3292ca982638
--- /dev/null
+++ b/test/unittest/speculation/tst.SpeculationDefaultDiscard.d
@@ -0,0 +1,37 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Licensed under the Universal Permissive License v 1.0 as shown at
+ * http://oss.oracle.com/licenses/upl.
+ */
+
+/*
+ * ASSERTION: Test the normal behavior when discarding a speculative
+ * default clause with quiet mode turned off.
+ *
+ * SECTION: Speculative Tracing/Discarding a Speculation;
+ * Actions and Subroutines/speculation()
+ */
+
+BEGIN
+{
+ self->spec = speculation();
+}
+
+BEGIN
+/self->spec/
+{
+ speculate(self->spec);
+}
+
+BEGIN
+/self->spec/
+{
+ discard(self->spec);
+}
+
+BEGIN
+/self->spec/
+{
+ exit(0);
+}
diff --git a/test/unittest/speculation/tst.SpeculationDefaultDiscard.r b/test/unittest/speculation/tst.SpeculationDefaultDiscard.r
new file mode 100644
index 000000000000..156d6b6ecba8
--- /dev/null
+++ b/test/unittest/speculation/tst.SpeculationDefaultDiscard.r
@@ -0,0 +1,5 @@
+ FUNCTION:NAME
+ :BEGIN
+
+-- @@stderr --
+dtrace: script 'test/unittest/speculation/tst.SpeculationDefaultDiscard.d' matched 4 probes
diff --git a/test/unittest/speculation/tst.SpeculationDiscard.d b/test/unittest/speculation/tst.SpeculationDiscard.d
index 8803324a81bb..132cc13beedb 100644
--- a/test/unittest/speculation/tst.SpeculationDiscard.d
+++ b/test/unittest/speculation/tst.SpeculationDiscard.d
@@ -4,17 +4,14 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION: Test the normal behavior of speculate() and discard().
*
- * SECTION: Speculative Tracing/Discarding a Speculation;
- * Options and Tunables/cleanrate
+ * SECTION: Speculative Tracing/Discarding a Speculation
*
*/
#pragma D option quiet
-#pragma D option cleanrate=2000hz
BEGIN
{
@@ -42,7 +39,7 @@ BEGIN
BEGIN
/(1 == self->discard)/
{
- printf("Succesfully tested buffer discard\n");
+ printf("Successfully tested buffer discard\n");
exit(0);
}
diff --git a/test/unittest/speculation/tst.SpeculationDiscard.r b/test/unittest/speculation/tst.SpeculationDiscard.r
index 8b960a0dbd18..80e8b50fadc1 100644
--- a/test/unittest/speculation/tst.SpeculationDiscard.r
+++ b/test/unittest/speculation/tst.SpeculationDiscard.r
@@ -1,3 +1,3 @@
Speculation ID: 1
-Succesfully tested buffer discard
+Successfully tested buffer discard
diff --git a/test/unittest/speculation/tst.SpeculationDiscard.d b/test/unittest/speculation/tst.SpeculationDiscardNotQuiet.d
similarity index 71%
copy from test/unittest/speculation/tst.SpeculationDiscard.d
copy to test/unittest/speculation/tst.SpeculationDiscardNotQuiet.d
index 8803324a81bb..23013c6e5ff1 100644
--- a/test/unittest/speculation/tst.SpeculationDiscard.d
+++ b/test/unittest/speculation/tst.SpeculationDiscardNotQuiet.d
@@ -1,20 +1,16 @@
/*
* Oracle Linux DTrace.
- * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION: Test the normal behavior of speculate() and discard().
*
- * SECTION: Speculative Tracing/Discarding a Speculation;
- * Options and Tunables/cleanrate
+ * SECTION: Speculative Tracing/Discarding a Speculation
*
*/
-#pragma D option quiet
-#pragma D option cleanrate=2000hz
BEGIN
{
@@ -42,7 +38,7 @@ BEGIN
BEGIN
/(1 == self->discard)/
{
- printf("Succesfully tested buffer discard\n");
+ printf("Successfully tested buffer discard\n");
exit(0);
}
diff --git a/test/unittest/speculation/tst.SpeculationDiscardNotQuiet.r b/test/unittest/speculation/tst.SpeculationDiscardNotQuiet.r
new file mode 100644
index 000000000000..be17cec0cec9
--- /dev/null
+++ b/test/unittest/speculation/tst.SpeculationDiscardNotQuiet.r
@@ -0,0 +1,8 @@
+ FUNCTION:NAME
+ :BEGIN Speculation ID: 1
+
+ :BEGIN Successfully tested buffer discard
+
+-- @@stderr --
+dtrace: script 'test/unittest/speculation/tst.SpeculationDiscardNotQuiet.d' matched 5 probes
+
diff --git a/test/unittest/speculation/tst.SpeculationID.d b/test/unittest/speculation/tst.SpeculationID.d
index 21ef5ac64b55..f55d5fda44f5 100644
--- a/test/unittest/speculation/tst.SpeculationID.d
+++ b/test/unittest/speculation/tst.SpeculationID.d
@@ -4,7 +4,6 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION:
diff --git a/test/unittest/speculation/tst.SpeculationWithZero.d b/test/unittest/speculation/tst.SpeculationWithZero.d
index 959b734a9b75..04991b40f5a2 100644
--- a/test/unittest/speculation/tst.SpeculationWithZero.d
+++ b/test/unittest/speculation/tst.SpeculationWithZero.d
@@ -4,7 +4,6 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION:
@@ -19,14 +18,11 @@
BEGIN
{
self->speculateFlag = 0;
- self->spec = speculation();
- self->spec = speculation();
- printf("Speculative buffer ID: %d\n", self->spec);
}
BEGIN
{
- speculate(self->spec);
+ speculate(0);
self->speculateFlag++;
}
diff --git a/test/unittest/speculation/tst.SpeculationWithZero.r b/test/unittest/speculation/tst.SpeculationWithZero.r
index 9165c854920c..35952e0a25e9 100644
--- a/test/unittest/speculation/tst.SpeculationWithZero.r
+++ b/test/unittest/speculation/tst.SpeculationWithZero.r
@@ -1,5 +1,2 @@
-Speculative buffer ID: 0
Statement wasn't executed
--- @@stderr --
-dtrace: 1 failed speculation (no speculative buffer available)
diff --git a/test/unittest/speculation/tst.TwoSpecBuffers.d b/test/unittest/speculation/tst.TwoSpecBuffers.d
index 2df996927c15..25e73b0662c7 100644
--- a/test/unittest/speculation/tst.TwoSpecBuffers.d
+++ b/test/unittest/speculation/tst.TwoSpecBuffers.d
@@ -4,12 +4,11 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
/*
* ASSERTION:
- * Increasing the value of nspec to two should will increase the number of
- * speculative buffers to two.
+ * Increasing the value of nspec to two should set the number of
+ * speculative buffers to two: getting a third should fail.
*
* SECTION: Speculative Tracing/Options and Tuning;
* Options and Tunables/nspec
@@ -17,7 +16,6 @@
*/
#pragma D option quiet
-#pragma D option cleanrate=3000hz
#pragma D option nspec=2
BEGIN
@@ -40,7 +38,7 @@ BEGIN
BEGIN
/var1 && var2 && (!var3)/
{
- printf("Succesfully got two speculative buffers");
+ printf("Successfully got two speculative buffers");
exit(0);
}
diff --git a/test/unittest/speculation/tst.TwoSpecBuffers.r b/test/unittest/speculation/tst.TwoSpecBuffers.r
index 3a35b4673ee4..0c6bd3d47fff 100644
--- a/test/unittest/speculation/tst.TwoSpecBuffers.r
+++ b/test/unittest/speculation/tst.TwoSpecBuffers.r
@@ -1,6 +1,4 @@
Speculation ID: 1
Speculation ID: 2
Speculation ID: 0
-Succesfully got two speculative buffers
--- @@stderr --
-dtrace: 1 failed speculation (no speculative buffer available)
+Successfully got two speculative buffers
diff --git a/test/unittest/speculation/tst.negcommit.d b/test/unittest/speculation/tst.negcommit.d
index cafb0a149bc7..5a680a84f866 100644
--- a/test/unittest/speculation/tst.negcommit.d
+++ b/test/unittest/speculation/tst.negcommit.d
@@ -4,7 +4,6 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
-/* @@xfail: dtv2 */
BEGIN
{
diff --git a/test/unittest/speculation/tst.negcommit.r b/test/unittest/speculation/tst.negcommit.r
index 716afcb52d70..6bb75d1462ba 100644
--- a/test/unittest/speculation/tst.negcommit.r
+++ b/test/unittest/speculation/tst.negcommit.r
@@ -3,4 +3,4 @@
-- @@stderr --
dtrace: script 'test/unittest/speculation/tst.negcommit.d' matched 2 probes
-dtrace: error on enabled probe ID 1 (ID 1: dtrace:::BEGIN): illegal operation in action #1
+dtrace: error on enabled probe ID 2 (ID 1: dtrace:::BEGIN): illegal operation in action #1
diff --git a/test/unittest/speculation/tst.zerosize.d b/test/unittest/speculation/tst.zerosize.d
index 74d1ace9e1e3..03d3b8497aa9 100644
--- a/test/unittest/speculation/tst.zerosize.d
+++ b/test/unittest/speculation/tst.zerosize.d
@@ -4,6 +4,7 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
+
/* @@xfail: dtv2 */
#pragma D option destructive
--
2.33.0.256.gb827f06fa9
More information about the DTrace-devel
mailing list