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

Re: [PATCH 2/2] strbuf: allow to use preallocated memory

From
Matthieu Moy <matthieu.moy@grenoble-inp.fr>
Date
May 30, 2016, 14:34 UTC
Message-ID
<vpqpos38vi4.fsf@anie.imag.fr>
In-Reply-To
<1639412597.204503.1464617754937.JavaMail.zimbra@ensimag.grenoble-inp.fr>
William Duclot <william.duclot@ensimag.grenoble-inp.fr> writes:
Show 36 quoted lines
> Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:
>
>> void strbuf_grow(struct strbuf *sb, size_t extra)
>> {
>> 	int new_buf = !sb->alloc;
>> ...
>> 	if (sb->flags & STRBUF_OWNS_MEMORY) {
>> 		if (new_buf) // <---------------------------------------- (1)
>> 			sb->buf = NULL;
>> 		ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);
>> 	} else {
>> 		/*
>> 		 * The strbuf doesn't own the buffer: to avoid to realloc it,
>> 		 * the strbuf needs to use a new buffer without freeing the old
>> 		 */
>> 		if (sb->len + extra + 1 > sb->alloc) {
>> 			size_t new_alloc = MAX(sb->len + extra + 1, alloc_nr(sb->alloc));
>> 			char *buf = xmalloc(new_alloc);
>> 			memcpy(buf, sb->buf, sb->alloc);
>> 			sb->buf = buf;
>> 			sb->alloc = new_alloc;
>> 			sb->flags |= STRBUF_OWNS_MEMORY;
>> 		}
>> 	}
>> 
>> 	if (new_buf) // <---------------------------------------- (2)
>> 		sb->buf[0] = '\0';
>> }
>> 
>> I think (1) is now dead code, since sb->alloc == 0 implies that
>> STRBUF_OWNS_MEMORY is set. (2) seems redundant since you've just
>> memcpy-ed the existing '\0' into the buffer.
>
> You're right for (1), I hadn't noticed that.
> For (2), we'll still have to set sb->buf[new_alloc-1]='\0' after the memcpy, if we
> have sb->alloc==0 then the memcpy won't copy it.

That sounds like one more reason to memcpy len + 1 bytes, and you'll get the '\0' copied.

Show 13 quoted lines
>> After your patch, there are differences between
>> strbuf_wrap_preallocated() which I think are inconsistencies:
>> 
>> * strbuf_attach() does not check for NULL buffer, but it doesn't accept
>>   them either if I read correctly. It would make sense to add the check
>>   to strbuf_attach(), but it's weird to have the performance-critical
>>   oriented function do the expensive stuff that the
>>   non-performance-critical one doesn't.
>
> I agree that strbuf_attach should do the check (it seems strange that it
> doesn't already do it, as the "buffer never NULL" invariant is not new).
> I don't understand your "but" part, what "expensive stuff" are you talking
> about?

"expensive stuff" was an exageration for "== NULL" test. It's not that expensive, but costs a tiny bit of CPU time.

> xmemdupz can only allocate the same size it will copy.
Indeed, so forget about it.
Show 14 quoted lines
>>> +/**
>>> + * Allow the caller to give a pre-allocated piece of memory for the strbuf
>>> + * to use and indicate that the strbuf must use exclusively this buffer,
>>> + * never realloc() it or allocate a new one. It means that the string can
>>> + * be manipulated but cannot overflow the pre-allocated buffer. The
>>> + * pre-allocated buffer will never be freed.
>>> + */
>> 
>> Perhaps say explicitly that although the allocated buffer has a fixed
>> size, the string itself can grow as long as it does not overflow the
>> buffer?
>
> That's what I meant by "the string can be manipulated but cannot overflow
> the pre-allocated buffer". I'll try to reformulate
Maybe "the string can grow, but cannot overflow"?
Show 12 quoted lines
>>> @@ -91,6 +116,8 @@ extern void strbuf_release(struct strbuf *);
>>>   * Detach the string from the strbuf and returns it; you now own the
>>>   * storage the string occupies and it is your responsibility from then on
>>>   * to release it with `free(3)` when you are done with it.
>>> + * Must allocate a copy of the buffer in case of a preallocated/fixed
>>> buffer.
>>> + * Performance-critical operations have to be aware of this.
>> 
>> Better than just warn about performance, you can give the alternative.
>
> I'm not sure what you mean, I don't think there really is an alternative for
> detaching a string?

So, is the comment above saying "You're doomed, there's no way you can get good performance anyway"?

The alternative is just that you don't have to call strbuf_release since the caller can access the .buf field and is already the one responsible for freeing it when needed, and it's safe to just call strbuf_init() if one needs to re-initialize the stbuf structure.

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/
Previous: William DuclotNext: William Duclot
Message 17 of 38 in “strbuf: improve API”
  1. 0/2 strbuf: improve APIWilliam Duclot, May 30, 2016
  2. 1/2 strbuf: add testsWilliam Duclot, May 30, 2016
  3. Johannes SchindelinMay 30, 2016
  4. Simon RabourgMay 30, 2016
  5. Matthieu MoyMay 30, 2016
  6. Michael HaggertyMay 31, 2016
  7. Simon RabourgMay 31, 2016
  8. 2/2 strbuf: allow to use preallocated memoryWilliam Duclot, May 30, 2016
  9. Johannes SchindelinMay 30, 2016
  10. William DuclotMay 30, 2016
  11. Johannes SchindelinMay 31, 2016
  12. Michael HaggertyMay 31, 2016
  13. Johannes SchindelinMay 31, 2016
  14. Michael HaggertyMay 31, 2016
  15. Matthieu MoyMay 30, 2016
  16. William DuclotMay 30, 2016
  17. Matthieu MoyMay 30, 2016
  18. William DuclotMay 30, 2016
  19. Michael HaggertyMay 31, 2016
  20. William DuclotMay 31, 2016
  21. William DuclotJun 3, 2016
  22. Mike HommeyMay 30, 2016
  23. William DuclotMay 30, 2016
  24. Mike HommeyMay 30, 2016
  25. Junio C HamanoMay 31, 2016
  26. WilliamMay 31, 2016
  27. Matthieu MoyMay 31, 2016
  28. William DuclotMay 31, 2016
  29. Remi Galan AlfonsoMay 30, 2016
  30. Jeff KingJun 1, 2016
  31. David TurnerJun 1, 2016
  32. Jeff KingJun 1, 2016
  33. David TurnerJun 1, 2016
  34. Jeff KingJun 1, 2016
  35. Michael HaggertyJun 2, 2016
  36. Matthieu MoyJun 2, 2016
  37. William DuclotJun 2, 2016
  38. Jeff KingJun 24, 2016

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.