commit: 92efecb5fe4e6cad6b7c34e2e46e6f90d215e220
parent 47364622bed691918f9ad10aaf65de7410847ea4
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Mon, 28 Jul 2025 07:43:05 +0200
cmd/strings: use fwrite for resulting string
Which is still more efficient than a direct write(2)/writev(2)
call due to real binaries having lots of short strings so buffering helps.
Also insert delim at the end so writes can more easily be 4K aligned
and save some syscalls.
Prior version:
$ strace -cw strings /bin/node >/dev/null
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
58.73 0.166938 11 14510 read
41.19 0.117061 6 16789 writev
0.06 0.000163 163 1 execve
0.01 0.000020 20 1 open
0.00 0.000014 13 1 set_tid_address
0.00 0.000012 11 1 1 ioctl
0.00 0.000010 9 1 close
0.00 0.000008 7 1 arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00 0.284226 9 31305 1 total
$ /bin/time strings /bin/node >/dev/null
real 0.240000
user 0.155336
sys 0.084182
With direct writev(2):
$ strace -cw ./cmd/strings /bin/node >/dev/null
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
94.49 2.924822 6 436496 writev
5.50 0.170349 11 14510 read
0.01 0.000171 171 1 execve
0.00 0.000016 15 1 open
0.00 0.000010 10 1 close
0.00 0.000008 7 1 arch_prctl
0.00 0.000007 7 1 set_tid_address
------ ----------- ----------- --------- --------- ----------------
100.00 3.095384 6 451011 total
$ time ./cmd/strings /bin/node >/dev/null
0m00.33s real 0m00.15s user 0m00.18s system
With this commit:
$ strace -cw ./cmd/strings /bin/node >/dev/null
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
59.17 0.159342 10 14510 read
40.76 0.109777 6 16417 writev
0.06 0.000151 150 1 execve
0.01 0.000016 15 1 open
0.00 0.000008 8 1 close
0.00 0.000008 7 1 1 ioctl
0.00 0.000007 7 1 arch_prctl
0.00 0.000007 7 1 set_tid_address
------ ----------- ----------- --------- --------- ----------------
100.00 0.269316 8 30933 1 total
$ /bin/time ./cmd/strings /bin/node >/dev/null
real 0.170000
user 0.105422
sys 0.066265
Diffstat:
1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/cmd/strings.c b/cmd/strings.c
@@ -20,29 +20,23 @@ const char *opt_offset_format = NULL;
char delim = '\n';
static int
-print_string(char *buffer, size_t offset)
+print_string(char *buffer, size_t buflen, size_t offset)
{
int ret = 0;
+ int wrote = 0;
- if(opt_offset_format == NULL)
+ if(opt_offset_format)
{
- ret = printf("%s%c", buffer, delim);
- }
- else
- {
- ret = printf(opt_offset_format, offset, buffer, delim);
+ ret = printf(opt_offset_format, offset);
+ if(ret < 0) return ret;
+ wrote += ret;
}
- if(ret < 0)
- {
- fprintf(stderr, "strings: error: Failed writing: %s\n", strerror(errno));
- errno = 0;
- return 1;
- }
- else
- {
- return 0;
- }
+ ret = fwrite(buffer, buflen, 1, stdout);
+ if(ret < 0) return ret;
+ wrote += ret;
+
+ return wrote;
}
static int
@@ -71,8 +65,12 @@ concat(int fd, const char *fdname)
if(write_pos >= opt_min_strlen)
{
- write_buf[write_pos] = '\0';
- if(print_string(write_buf, offset) != 0) return 1;
+ write_buf[write_pos] = delim;
+ if(print_string(write_buf, write_pos+1, offset) < 0)
+ {
+ fprintf(stderr, "strings: error: Failed writing resulting string: %s\n", strerror(errno));
+ return 1;
+ }
}
offset += write_pos;
@@ -145,13 +143,13 @@ main(int argc, char *argv[])
switch(optarg[0])
{
case 'o':
- opt_offset_format = "%zo %s%c";
+ opt_offset_format = "%zo ";
break;
case 'x':
- opt_offset_format = "%zx %s%c";
+ opt_offset_format = "%zx ";
break;
case 'd':
- opt_offset_format = "%zd %s%c";
+ opt_offset_format = "%zd ";
break;
default:
fprintf(stderr, "strings: error: Unknown format: %s\n", optarg);