[hackers] [dmenu] readstdin: reduce memory-usage by duplicating the line from getline() || Hiltjo Posthuma

From: <git_AT_suckless.org>
Date: Wed, 8 Mar 2023 21:30:12 +0100 (CET)

commit dfbbf7f6e1b22ccf9e5a45d77ee10995577fb4fc
Author: Hiltjo Posthuma <hiltjo_AT_codemadness.org>
AuthorDate: Wed Mar 8 21:20:52 2023 +0100
Commit: Hiltjo Posthuma <hiltjo_AT_codemadness.org>
CommitDate: Wed Mar 8 21:28:51 2023 +0100

    readstdin: reduce memory-usage by duplicating the line from getline()
    
    Improves upon commit 32db2b125190d366be472ccb7cad833248696144
    
    The getline() implementation often uses a more greedy way of allocating memory.
    Using this buffer directly and forcing an allocation (by setting it to NULL)
    would waste a bit of extra space, depending on the implementation of course.
    
    Tested on musl libc and glibc.
    The current glibc version allocates a minimum of 120 bytes per line.
    For smaller lines musl libc seems less wasteful but still wastes a few bytes
    per line.
    
    On a dmenu_path listing on my system the memory usage was about 350kb (old) vs
    30kb (new) on Void Linux glibc.
    
    Side-note that getline() also reads NUL bytes in lines, while strdup() would
    read until the NUL byte. Since dmenu reads text lines either is probably
    fine(tm). Also rename junk to linesiz.

diff --git a/dmenu.c b/dmenu.c
index 27b7a30..4e7df12 100644
--- a/dmenu.c
+++ b/dmenu.c
_AT_@ -550,11 +550,11 @@ static void
 readstdin(void)
 {
         char *line = NULL;
- size_t i, junk, itemsiz = 0;
+ size_t i, itemsiz = 0, linesiz = 0;
         ssize_t len;
 
         /* read each line from stdin and add it to the item list */
- for (i = 0; (len = getline(&line, &junk, stdin)) != -1; i++) {
+ for (i = 0; (len = getline(&line, &linesiz, stdin)) != -1; i++) {
                 if (i + 1 >= itemsiz) {
                         itemsiz += 256;
                         if (!(items = realloc(items, itemsiz * sizeof(*items))))
_AT_@ -562,9 +562,10 @@ readstdin(void)
                 }
                 if (line[len - 1] == '\n')
                         line[len - 1] = '\0';
- items[i].text = line;
+ if (!(items[i].text = strdup(line)))
+ die("strdup:");
+
                 items[i].out = 0;
- line = NULL; /* next call of getline() allocates a new line */
         }
         free(line);
         if (items)
Received on Wed Mar 08 2023 - 21:30:12 CET

This archive was generated by hypermail 2.3.0 : Wed Mar 08 2023 - 21:36:38 CET