[DTrace-devel] [PATCH 1/3] Clear agg keys

Kris Van Hees kris.van.hees at oracle.com
Mon Aug 14 22:04:33 UTC 2023


On Mon, Aug 14, 2023 at 03:17:15PM -0400, Eugene Loh via DTrace-devel wrote:
> On 8/14/23 13:15, Kris Van Hees wrote:
> 
> > On Fri, Aug 11, 2023 at 01:04:05AM -0400, Eugene Loh via DTrace-devel wrote:
> > > On 8/8/23 17:24, eugene.loh at oracle.com wrote:
> > > 
> > > > From: Eugene Loh <eugene.loh at oracle.com>
> > > > 
> > > > Aggregations use a "map of maps" to access per-CPU BPF maps whose
> > > > keys are of size dt_maxtuplesize to accommodate keys of various
> > > > sizes.  Care was exercised on the cg side to ensure that a key
> > > > would be zeroed out before filling so that garbage bytes would not
> > > > pollute the key.
> > > > 
> > > > Exercise similar caution on the consumer side.
> > > > 
> > > > THIS PATCH NEEDS TESTS.
> > > Reminder:  if this gets worked into the trunc patch, then the trunc tests
> > > could be said to be the tests for this "Clear agg keys" stuff as well.
> > > Also...
> > > 
> > > > Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
> > > > ---
> > > >    libdtrace/dt_aggregate.c | 9 +++++++--
> > > >    1 file changed, 7 insertions(+), 2 deletions(-)
> > > > 
> > > > diff --git a/libdtrace/dt_aggregate.c b/libdtrace/dt_aggregate.c
> > > > index 24faf1c1..1b8167d6 100644
> > > > --- a/libdtrace/dt_aggregate.c
> > > > +++ b/libdtrace/dt_aggregate.c
> > > > @@ -570,11 +570,16 @@ hashnext:
> > > >    	/* Copy the key. */
> > > >    	size = agg->dtagd_ksize;
> > > > -	ptr = dt_alloc(dtp, size);
> > > > +	ptr = dt_alloc(dtp, dtp->dt_maxtuplesize);
> > > >    	if (ptr == NULL)
> > > >    		return dt_set_errno(dtp, EDT_NOMEM);
> > > > -	memcpy(ptr, key, size);
> > > > +	memset(ptr, 0, dtp->dt_maxtuplesize);
> > > The dt_alloc() and memset() are dt_maxtuplesize because that's how big the
> > > keys for the aggs maps are.  But I don't think we ever use the last 8 bytes
> > > of dt_maxtuplesize for aggs, do we?  If not, then the key size for the aggs
> > > map can be reduced by 8 bytes.  Again, though, where that goes depends on
> > > whether this patch is integrated into the trunc() patch.
> > Why not use dt_zalloc(dtp, dtp->dt_maxtuplesize)?
> 
> Yeah, but actually I guess we don't need to zero anything out at all.  We
> can just memcpy() the entire dt_maxtuplesize in.

Actually, I belive that the following is sufficient:

 static int
 dt_aggwalk_remove(dtrace_hdl_t *dtp, dt_ahashent_t *h)
 {
        dtrace_aggdata_t        *agd = &h->dtahe_data;
        int                     i, ncpus = dtp->dt_conf.num_online_cpus;
+       char                    *key = dtp->dt_aggregate.dtat_key;
+
+       memset(key, 0, dtp->dt_maxtuplesize);
+       memcpy(key, agd->dtada_key, agd->dtada_desc->dtagd_ksize);
 
        for (i = 0; i < ncpus; i++) {
                int     cpu = dtp->dt_conf.cpus[i].cpu_id;
                int     fd = dt_bpf_map_lookup_fd(dtp->dt_aggmap_fd, &cpu);
 
                if (fd < 0)
                        return DTRACE_WORKSTATUS_ERROR;
 
-               dt_bpf_map_delete(fd, agd->dtada_key);
+               dt_bpf_map_delete(fd, key);
                close(fd);
        }
 
        return DTRACE_WORKSTATUS_OKAY;
 }

> The main question is whether this should:
> 
> *)  live as an independent patch.  Maybe that makes sense since it's not
> specific to trunc().  But if so, whether to add any tests for it... maybe it
> can be demonstrated with "clear" or something else?

Hm, actually, I think it is specific to trunc().  We know that tuples are
always constructed in a 0-filled buffer so there will not be garbage between
the elements of a tuple.

> *)  just throw it into the trunc patch.

Per the above, I think it should be in my trunc patch.

> Let me know.  But if separate patches, this should probably go in front of
> trunc().
> 
> And again there is the side issue about using an agg key that's
> dt_maxtuplesize-8.

I think there is banefit from using the same tuple code for associative arrays
and aggregations so the loss of 8 bytes is acceptable.  On the other hand, I've
taken another look at the way I implemented tuples and it seems that I may be
able to optimize it a bit in a way that all tuples benefit from a size
reduction.

But that would be a separate patch.

> > > > +	for (i = 0; i < agg->dtagd_nkrecs; i++) {
> > > > +		rec = &agg->dtagd_krecs[i];
> > > > +		off = rec->dtrd_offset;
> > > > +		memcpy(&ptr[off], &key[off], rec->dtrd_size);
> > > > +	}
> > Why do you copy the individual elements rather than memcpy(ptr, key, size),
> > which should be safe because we already know that the destination buffer is
> > all 0s.  Isn't your loop essentially just performing the same memcpy, but
> > in chunks rather than all at once?
> 
> Yeah.  I was trying to be extra careful now (also guard against gaps between
> key tuple members).  Plus, earlier, in dt_aggregate_snap_one(), this
> "chunk-by-chunk" approach is used to protect against garbage when comparing
> keys for a match.  But I guess both there and here it's overkill.  The
> matter is handled properly now, and neither place needs the chunk-by-chunk
> approach.

Yes, so an independent patch optimizing dt_aggregate_snap_one() might be in
order (not part if the trunc() work).

> > > >    	agd->dtada_key = ptr;
> > > >    	/* Copy the data. */
> > > _______________________________________________
> > > 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