-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
libkmod: Improve index dump performance #250
Conversation
2258f0d
to
d7faf8a
Compare
Codecov ReportAttention: Patch coverage is
🚨 Try these New Features:
|
d7faf8a
to
63160b4
Compare
Use FILE for output to reduce the amount of system calls. Removes the only use case of write_str_safe, which can be removed as well. Signed-off-by: Tobias Stoeckmann <[email protected]>
63160b4
to
cc41349
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The numbers look amazing - nicely spotted. The benefit might shrink a bit when(if) we reintroduce fwrite_str_safe()
, but as a whole it should still be a win.
assert_cc(EAGAIN == EWOULDBLOCK); | ||
|
||
do { | ||
ssize_t r = write(fd, buf + done, todo); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did we remove the helper instead of adapting it to use fwrite()
? AFAICT all the safety handling it does is still applicable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with FILE output is that fclose
itself could still write data. And this is a one-shot approach. We cannot call it multiple times until the remaining data is successfully written.
I mistakenly believed that FILE itself handles short writes, but I was wrong. So if we want to keep interrupt-safe writes, we cannot use FILE here. At best, we would adjust the API, but ... Not in a simple PR. :)
if (ctx == NULL) | ||
return -ENOSYS; | ||
|
||
fd2 = dup(fd); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAICT libraries should really be using CLOEXEC, aka fcntl(fd, F_DUPFD_CLOEXEC...)
or alike.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fdopen
would set ´O_CLOEXEC. Unfortunately I cannot simply use
dup3`, which would do it atomically for us, because then I would have to figure out a free fd first (or open one just to reserve it).
if (fp == NULL) { | ||
err = -errno; | ||
close(fd2); | ||
return err; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move all the whole dup/fdopen hunk after all the input validation - aka after the type
check below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would adjust it if we decide if it's even worth it:
- FILE loses EINTR handling (modprobe -c shouldn't really care, since it first uses FILE and then passes a file descriptor to library, but let's not break API and whatever other users might rely on)
- wbuf speeds up processing, but introduces custom code, not improving the error handling
So ... let's see. I wouldn't mind keeping everything as it is right now and, if we ever adjust the API in a release, reconsider turning it FILE-based.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FILE loses EINTR handling
My slight inclination towards a wbuf
-like approach got a whole lot stronger.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I second that. What we could have is one additional API that receives a FILE* as argument.... we are not really going to change the API and break users because of this.
However if we add the new API, then we don't drop the old code since converting it to use FILE* would mean to lose EINTR handling. So.... I'm leaning towards the wbuf approach.
fwrite(buf->bytes, 1, buf->used, fp); | ||
fputc(' ', fp); | ||
fwrite(v.value, 1, v.len, fp); | ||
fputc('\n', fp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity: have you tried placing the contents into a buffer (on the stack) and doing a single write for given value instead of 4? Does it make a difference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This already helps by almost 50 %, which is nice. At first I tried scratchbuf (and soon strbuf), but we could also keep a buffer around for longer. See #252 as an example.
Will close this one since we prefer #252. |
Use FILE for output to reduce the amount of system calls. Removes the only use case of write_str_safe, which can be removed as well.
This has another advantage, beside faster execution: Having a FILE in
kmod_dump_index
allows us easier error detection in the future (by usingferror
here instead of multiplying it into FILE-based and memory-mapped index functions).Talking about execution times, these are collected from modules of an Arch Linux installation:
current master
Uses 198497 write calls.
Takes around 224 ms on this system.
new
Uses 573 write calls.
Takes around 7 ms.
Binary size shrinks by around 200 bytes, library size increases by around 60 bytes.
Speed increasement based on
strace
: around 30xSpeed increasement based on
time
: 4x to 10x (depending if you redirect to /dev/null or a real file)