git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] sha1_file: use strbuf_add() instead of strbuf_addf()

From
Derrick Stolee <stolee@gmail.com>
Date
Dec 1, 2017, 19:50 UTC
Message-ID
<54da89a5-bf20-cb20-9884-6285033f0d95@gmail.com>
In-Reply-To
<20171201182238.GA27688@sigill.intra.peff.net>
On 12/1/2017 1:22 PM, Jeff King wrote:
> On Fri, Dec 01, 2017 at 12:49:56PM -0500, Derrick Stolee wrote:
[snip]
>> diff --git a/sha1_file.c b/sha1_file.c
>> index 8ae6cb6285..2160323c4a 100644
> This overall looks good, but I noticed one bug and a few cosmetic
> improvements.

Thanks for finding quality improvements to this patch. I'll let it sit over the weekend for more feedback before sending a v2.

Show 19 quoted lines
>
>> --- a/sha1_file.c
>> +++ b/sha1_file.c
>> @@ -1914,17 +1914,18 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
>>   	}
>>   
>>   	oid.hash[0] = subdir_nr;
>> +	strbuf_add(path, "/", 1);
> Maybe:
>
>    strbuf_addch(path, '/');
>
> would be a bit more readable (it's also a tiny bit faster, but this
> isn't part of the tight loop).
>
>> +	baselen = path->len;
> We set this here so that the '/' is included as part of the base. Makes
> sense, but can we now drop the earlier setting of baselen before the
> opendir() call?

Yeah, probably. I had briefly considered just adding the '/' before the first assignment of "baselen", but didn't want to change the error output. I also don't know if there are side effects for other platforms by calling opendir() with a '/'-terminated path.

Show 21 quoted lines
>>   	while ((de = readdir(dir))) {
>>   		if (is_dot_or_dotdot(de->d_name))
>>   			continue;
>>   
>> -		strbuf_setlen(path, baselen);
>> -		strbuf_addf(path, "/%s", de->d_name);
>> -
>>   		if (strlen(de->d_name) == GIT_SHA1_HEXSZ - 2 &&
>>   		    !hex_to_bytes(oid.hash + 1, de->d_name,
>>   				  GIT_SHA1_RAWSZ - 1)) {
>> +			strbuf_setlen(path, baselen);
>> +			strbuf_add(path, de->d_name, GIT_SHA1_HEXSZ - 2);
> Moving this code into the conditional makes sense here, since that's
> where we know the actual size. But what about the case when we _don't_
> hit this conditional. We still do:
>
>    if (cruft_cb)
>          cruft_cb(path->buf);
>
> which is now broken (it will just get the directory name without the
> entry appended).

Good catch! A big reason to pull it inside and use strbuf_add over strbuf_addstr is to avoid a duplicate strlen() calculation. However, I can store the length before the conditional.

Show 12 quoted lines
> I think the optimized versions probably needs to be something more like:
>
>    while (de = readdir(...)) {
>        strbuf_setlen(path, baselen);
>        if (size is HEXSZ - 2) {
>            strbuf_add(path, de->d_name, HEXSZ - 2);
> 	  obj_cb(path->buf);
>        } else if (cruft_cb) {
>            strbuf_addstr(path, de->d_name);
> 	  cruft_cb(path->buf);
>        }
>    }
Small change by storing the length in advance of the conditional:
while (de = readdir(...)) {
     int namelen = strlen(de->d_name);
     strbuf_setlen(path, baselen);
     strbuf_add(path, de->d_name, namelen);
     if (namelen == HEXSZ - 2)
         obj_cb(path->buf)
     else
         cruft_cb(path->buf);
}
Show 7 quoted lines
> Two other thoughts:
>
>    - from past discussions, I suspect most of your performance
>      improvement actually comes from avoiding addf(), and the difference
>      between addstr() and add() may be negligible here. It might be worth
>      timing strbuf_addstr(). If that's similarly fast, that means we
>      could keep the logic out of the conditional entirely.

addstr() duplicates the strlen(), which isn't much but we might as well save cycles where we can if it isn't too hard.

>    - there's an extra micro-optimization there, which is that if there's
>      no obj_cb, we have no need to assemble the full path at all. I doubt
>      it makes much of a difference, as most callers would pass an object
>      callback (I'd be surprised if we even have one that doesn't).

After doing a few 'git grep' commands, I found several that include a NULL cruft_cb but none that have a NULL obj_cb.

Thanks, -Stolee

Previous: Jeff KingNext: Jeff King
Message 3 of 7 in “sha1_file: use strbuf_add() instead of strbuf_addf()”
  1. sha1_file: use strbuf_add() instead of strbuf_addf()Derrick Stolee, Dec 1, 2017
  2. Jeff KingDec 1, 2017
  3. Derrick StoleeDec 1, 2017
  4. Jeff KingDec 1, 2017
  5. sha1_file: use strbuf_add() instead of strbuf_addf()Derrick Stolee, Dec 4, 2017
  6. Jeff KingDec 4, 2017
  7. Derrick StoleeDec 4, 2017

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.