libbb: much faster concat_path_file()
No binary (build failed)
—
(log yok)
| @@ -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 |
| @@ -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); | |
| @@ -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); | |