← Commit list

a33ce612b

Denys Vlasenko
Denys Vlasenko
2025-08-04
SUCCESS Duration: 155s

Subject

libbb: much faster concat_path_file()

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

libbb/concat_path_file.c+75 -0
@@ -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
util-linux/lspci.c+1 -1
@@ -47,7 +47,7 @@ static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM,
int pci_class = 0, pci_vid = 0, pci_did = 0;
int pci_subsys_vid = 0, pci_subsys_did = 0;
- char *uevent_filename = concat_path_file(fileName, "/uevent");
+ char *uevent_filename = concat_path_file(fileName, "uevent");
parser = config_open2(uevent_filename, fopen_for_read);
free(uevent_filename);
util-linux/lsusb.c+1 -1
@@ -50,7 +50,7 @@ static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM,
char *tokens[4];
char *busnum = NULL, *devnum = NULL;
int product_vid = 0, product_did = 0;
- char *uevent_filename = concat_path_file(fileName, "/uevent");
+ char *uevent_filename = concat_path_file(fileName, "uevent");
parser = config_open2(uevent_filename, fopen_for_read);
free(uevent_filename);