[DTrace-devel] [PATCH 3/3] Alternative handling of tracemem's dynamic size.
Kris Van Hees
kris.van.hees at oracle.com
Fri Feb 24 04:27:49 UTC 2023
On Thu, Feb 23, 2023 at 10:28:43PM -0500, Kris Van Hees via DTrace-devel wrote:
> On Mon, Jan 30, 2023 at 04:36:16PM -0500, eugene.loh--- via DTrace-devel wrote:
> > From: Eugene Loh <eugene.loh at oracle.com>
> >
> > The tracemem() action takes a constant size argument that gives the size
> > of the buffer used.
> >
> > Optionally, it also takes another size argument that is dynamically
> > computed. Currently, in this DTrace port, this dsize is used only by the
> > consumer, to limit how much data is displayed. The documentation is
> > unclear if dsize should also limit how much data is written into the
> > buffer in the first place. Arguably, it should:
> >
> > *) Copying less data might mean faster run time, although the
> > savings would be very small and would incur the cost of extra
> > BPF instructions.
> >
> > *) Copying less data might protect against accessing memory
> > illegally.
> >
> > Using dsize to cap how much data is written into the buffer is
> > implemented in this patch.
> >
> > Since any changes in behavior would not be seen in our testing, no test
> > changes are made.
> >
> > Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
> > ---
> > libdtrace/dt_cg.c | 29 +++++++++++++++++++++++++++--
> > 1 file changed, 27 insertions(+), 2 deletions(-)
> >
> > diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> > index 17843415..30c48155 100644
> > --- a/libdtrace/dt_cg.c
> > +++ b/libdtrace/dt_cg.c
> > @@ -2028,9 +2028,34 @@ dt_cg_act_tracemem(dt_pcb_t *pcb, dt_node_t *dnp, dtrace_actkind_t kind)
> > off = dt_rec_add(dtp, dt_cg_fill_gap, DTRACEACT_TRACEMEM, nsiz->dn_value, 1, NULL,
> > dsiz ? DTRACE_TRACEMEM_DYNAMIC : DTRACE_TRACEMEM_STATIC);
> >
> > - if (dsiz != NULL)
> > - dt_cg_store_val(pcb, dsiz, DTRACEACT_TRACEMEM, NULL,
> > + if (dsiz != NULL) {
> > + uint_t off_dsiz;
> > + size_t wid_dsiz = ctf_type_size(dsiz->dn_ctfp, dsiz->dn_type);
> > + uint_t Lokay = dt_irlist_label(dlp);
> > +
> > + assert(wid_dsiz > 0 && wid_dsiz <= 8 && (wid_dsiz & (wid_dsiz - 1)) == 0);
> > +
> > + /* compute and record dsiz at the appropriate offset */
> > + dt_cg_node(dsiz, dlp, drp);
> > + off_dsiz = dt_rec_add(dtp, dt_cg_fill_gap, DTRACEACT_TRACEMEM, wid_dsiz, wid_dsiz, NULL,
> > dsiz->dn_flags & DT_NF_SIGNED ? DTRACE_TRACEMEM_SSIZE : DTRACE_TRACEMEM_SIZE);
> > + emit(dlp, BPF_STORE(ldstw[wid_dsiz], BPF_REG_9, off_dsiz, dsiz->dn_reg));
> > +
> > + /*
> > + * Decide whether to reduce the size of the data that is
> > + * actually being recorded. We do this only if the dynamic
> > + * size is non-negative and less than the nsiz. Note that the
> > + * dsiz->dn_reg value has been sign-extended to 64 bits and we
> > + * will never have an nsiz that is 1<<63 or greater. So, just
> > + * treat dsiz->dn_reg as an unsigned value.
> > + */
> > + emit(dlp, BPF_BRANCH_REG(BPF_JLE, nsiz->dn_reg, dsiz->dn_reg, Lokay));
> > + emit(dlp, BPF_MOV_REG(nsiz->dn_reg, dsiz->dn_reg));
> > + emitl(dlp, Lokay,
> > + BPF_NOP());
> > +
> > + dt_regset_free(drp, dsiz->dn_reg);
>
> I think it would be much cleaner to do things in a different order:
>
> 1. compute dsiz (dt_cg_node)
> 2. decide whether to reduce nsiz based on diz
> 3. use dt_cg_store_val to store the dsiz in the output buffer
>
> That avoids the manual operations you do to record dsiz in the buffer.
Hm, on second thought, the problem of course is that dt_cg_store_val() itself
does the dt_cg_node() so that would mean it gets evaluated twice, which can be
an issue.
Then again, we have a very tight code path here that we can (ab)use... We
know for certain that dt_cg_store_val() freed dsiz->dn_reg right before
returning to dt_cg_act_tracemem(), and dsiz->dn_reg still has the register
number in it. Therefore, we can dt_regset_xalloc(drp, dsiz->dn_reg) right
after the dt_cg_store_val() call to "recover" the register and continue using
it.
I modified the patch that way and it works very nicely. It is slightly
naughty but avoid the manual storing of the dsiz scalar in the output buffer
(which is a bit ugly).
> > + }
> >
> > if (dt_regset_xalloc_args(drp) == -1)
> > longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
> > --
> > 2.18.4
> >
> >
> > _______________________________________________
> > DTrace-devel mailing list
> > DTrace-devel at oss.oracle.com
> > https://oss.oracle.com/mailman/listinfo/dtrace-devel
>
> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel
More information about the DTrace-devel
mailing list