[DTrace-devel] [PATCH v2 09/11] htab reduction: providers

Nick Alcock nick.alcock at oracle.com
Mon Nov 1 05:27:00 PDT 2021


On 22 Oct 2021, Eugene Loh said:

> On 10/20/21 2:54 PM, Nick Alcock wrote:
>> The list of providers is a hand-rolled fixed-size htab which is grossly
>> oversized except when USDT or the pid provider is in use, when it can
>> suddenly become terribly undersized: replace it with a dt_htab.
>
> Personal taste:  I'd prefer a full stop in place of that colon.

Agreed. I seem to have colons on the brain right now.

> Also, the "list of providers" was separate from the hash table.
>
> How about:
>          Providers were stored in fixed-size hash tables and companion
>          lists.  The fixed-size tables generally were grossly oversized;
>          with USDT or pid, they were terribly undersized.
>
>          Eliminate the lists and replace the hash tables with dt_htab.
>
> But, your call.

Yours is better.

>> We can move to using destructors (allowing deletion of htab elements
>> without needing a specialized _destroy function, and straightforward
>> freeing of the dt_provs htab on dtrace_close), but this is a little
>> troublesome because the dt_provlist is separate from dt_provs,
>> inaccessible from dt_provs element destructors (which do not have access
>> to a dtp), yet its members are added/removed from the dtp as we go.
>>
>> We can fix this by dropping the dt_provlist and replacing it with
>> dt_htab_next-based iteration over dt_provs. The iteration order is
>> different, but that's all that changes.
>>
>> (This is... debatable, and I can see why people might prefer to keep the
>> old design and just keep a dtp backpointer in every provider element.
>> I'm happy with that approach too.)
>
> I'm having trouble reading those three paragraphs.  What I do know is 

Rephrased a bit:

    We can move to using destructors (allowing deletion of htab elements
    without needing a specialized _destroy function, and straightforward
    freeing of the dt_provs htab on dtrace_close), but this is a little
    troublesome because the dt_provlist is separate from dt_provs, and since
    dt_provs element destructors don't have access to a dtp, the destructors
    also can't get at the dt_provlist to unchain dt_provs elements that are
    being deleted.

> that some stuff that was allocated with dt_zalloc(dtp, ...) and freed 
> with dt_free(dtp, ...) is now sometimes (but not always) freed with 
> free(...).  I guess that's okay -- dt_free() is really just a free() -- 
> but that seems like a sufficiently big "architectural change" that... I 
> dunno.

We have no choice: the place that does the free has no way to get access
to a dtp unless we explicitly start dragging around dtp back-pointers
and wasting space just so we can pass it to a function that then does
nothing with it. Since the wrappers are useless and used only
inconsistently I wouldn't call using them less an architectural change :)

I hate the dt_ allocate/free wrappers with a passion. I'd really like to
coccinelle up the source tree and just delete the lot, or at least
delete their unused-but-if-you-pass-NULL-it-kills-you dtp argument.

>> diff --git a/libdtrace/dt_dof.c b/libdtrace/dt_dof.c
>> @@ -560,6 +560,7 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
>>   	uint_t maxfmt = 0;
>>   #endif
>>   
>> +	dt_htab_next_t *it = NULL;
>>   	dt_provider_t *pvp;
>>   	dt_xlator_t *dxp;
>>   	dof_actdesc_t *dofa;
>
> How about moving that declaration down into the clause where it is used?

Good idea.

>> diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
>> @@ -324,9 +324,7 @@ struct dtrace_hdl {
>>   
>>   	struct dt_probe *dt_error; /* ERROR probe */
>>   
>> -	dt_list_t dt_provlist;	/* linked list of dt_provider_t's */
>> -	struct dt_provider **dt_provs; /* hash table of dt_provider_t's */
>> -	uint_t dt_provbuckets;	/* number of provider hash buckets */
>> +	dt_htab_t *dt_provs;	/* hash table of dt_provider_t's */
>>   	uint_t dt_nprovs;	/* number of providers in hash and list */
>>   	const struct dt_provider *dt_prov_pid; /* PID provider */
>>   	dt_proc_hash_t *dt_procs; /* hash table of grabbed process handles */
>
> The comment "and list" for dt_nprovs no longer makes sense since there 
> is no more list.  Actually, dt_nprovs is not even used for anything.  
> IMHO, it can be removed entirely.

Yes indeed! It's gone.

>> @@ -141,7 +141,7 @@ dt_pcb_pop(dtrace_hdl_t *dtp, int err)
>>   				dt_probe_iter(dtp, &pdp, dt_pcb_destroy_probe,
>>   					      NULL, NULL);
>>   
>> -				dt_provider_destroy(dtp, pvp);
>> +				dt_htab_next_delete(it);
>>   			}
>>   		}
>
> This code is okay, but it's an interesting example of some things I 
> mentioned.  E.g., the old code would destroy pvp, which was okay since 
> it already picked up nvp.  Using a similar approach, one would not need 
> a special dt_htab_next_delete() function.  Alternatively, have the 
> iterator stop at the entry *after* the one that is returned, and then 
> you could delete entries as you iterated through the list.

With the htab iterator now keeping track of the element it'll return on
the next call, this is now:

		dt_htab_delete(dtp->dt_provs, pvp);

... which is probably at least a bit clearer.

-- 
NULL && (void)



More information about the DTrace-devel mailing list