diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2025-08-04 19:21:45 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2025-08-04 19:21:45 +0200 |
| commit | a33ce612b5f51446e9d69ec5f41d5e2e2bcb4a84 (patch) | |
| tree | a07c37043f80e833d61775b1973a5bb947cd71f1 /libbb | |
| parent | d7d8ffed87679494be09d710c55dc0b7940e6547 (diff) | |
libbb: much faster concat_path_file()
function old new delta
concat_path_file 68 127 +59
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libbb')
| -rw-r--r-- | libbb/concat_path_file.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/libbb/concat_path_file.c b/libbb/concat_path_file.c index 5b4b7f113..dec9588ea 100644 --- a/libbb/concat_path_file.c +++ b/libbb/concat_path_file.c @@ -17,6 +17,7 @@ char* FAST_FUNC concat_path_file(const char *path, const char *filename) { +#if 0 char *lc; if (!path) @@ -25,4 +26,78 @@ char* FAST_FUNC concat_path_file(const char *path, const char *filename) while (*filename == '/') filename++; return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename); +#else +/* ^^^^^^^^^^^ timing of xasprintf-based code above: + * real 7.074s + * user 0.156s <<< + * sys 6.394s + * "rm -rf" of a Linux kernel tree from tmpfs (run time still dominated by in-kernel work, though) + * real 6.989s + * user 0.055s <<< 3 times less CPU used + * sys 6.450s + * vvvvvvvvvvv timing of open-coded malloc+memcpy code below (+59 bytes): + */ + char *buf, *p; + size_t n1, n2, n3; + + while (*filename == '/') + filename++; + + if (!path || !path[0]) + return xstrdup(filename); + + n1 = strlen(path); + n2 = (path[n1 - 1] != '/'); /* 1: "path has no trailing slash" */ + n3 = strlen(filename) + 1; + + buf = xmalloc(n1 + n2 + n3); + p = mempcpy(buf, path, n1); + if (n2) + *p++ = '/'; + p = mempcpy(p, filename, n3); + return buf; +#endif +} + +/* If second component comes from struct dirent, + * it's possible to eliminate one strlen() by using name length + * provided by kernel in struct dirent. See below. + * However, the win seems to be insignificant. + */ + +#if 0 + +/* Extract d_namlen from struct dirent */ +static size_t get_d_namlen(const struct dirent *de) +{ +#if defined(_DIRENT_HAVE_D_NAMLEN) + return de->d_namlen; +#elif defined(_DIRENT_HAVE_D_RECLEN) + const size_t prefix_sz = offsetof(struct dirent, d_name); + return de->d_reclen - prefix_sz; +#else + return strlen(de->d_name); +#endif +} + +char* FAST_FUNC concat_path_dirent(const char *path, const struct dirent *de) +{ + char *buf, *p; + size_t n1, n2, n3; + + if (!path || !path[0]) + return xstrdup(de->d_name); + + n1 = strlen(path); + n2 = (path[n1 - 1] != '/'); + n3 = get_d_namlen(de) + 1; + + buf = xmalloc(n1 + n2 + n3); + p = mempcpy(buf, path, n1); + if (n2) + *p++ = '/'; + p = mempcpy(p, de->d_name, n3); + return buf; } + +#endif |
