-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Three stream read optimizations #8032
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
Changes from all commits
e45f829
db480d7
a3df278
bf75865
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -706,7 +706,11 @@ PHPAPI ssize_t _php_stream_read(php_stream *stream, char *buf, size_t size) | |||||||
break; | ||||||||
} | ||||||||
|
||||||||
if (!stream->readfilters.head && ((stream->flags & PHP_STREAM_FLAG_NO_BUFFER) || stream->chunk_size == 1)) { | ||||||||
/* if the read buffer is currently empty, don't buffer | ||||||||
* large reads (larger than chunk_size), because | ||||||||
* buffering would only hurt performance in such an | ||||||||
* edge case */ | ||||||||
if (!stream->readfilters.head && ((stream->flags & PHP_STREAM_FLAG_NO_BUFFER) || stream->chunk_size == 1 || (stream->writepos == stream->readpos && size >= stream->chunk_size))) { | ||||||||
toread = stream->ops->read(stream, buf, size); | ||||||||
if (toread < 0) { | ||||||||
/* Report an error if the read failed and we did not read any data | ||||||||
|
@@ -1470,6 +1474,26 @@ PHPAPI zend_string *_php_stream_copy_to_mem(php_stream *src, size_t maxlen, int | |||||||
return ZSTR_EMPTY_ALLOC(); | ||||||||
} | ||||||||
|
||||||||
if (php_stream_is(src, PHP_STREAM_IS_STDIO) && | ||||||||
src->readfilters.head == NULL && | ||||||||
php_stream_stat(src, &ssbuf) == 0 && | ||||||||
#ifdef S_ISREG | ||||||||
S_ISREG(ssbuf.sb.st_mode) && | ||||||||
#endif | ||||||||
ssbuf.sb.st_size >= 0) { | ||||||||
/* optimized code path for unfiltered regular files: | ||||||||
* if we know the exact size, we can allocate the | ||||||||
* right buffer size and issue only one read() system | ||||||||
* call */ | ||||||||
|
||||||||
if (ssbuf.sb.st_size <= src->position) | ||||||||
return ZSTR_EMPTY_ALLOC(); | ||||||||
|
||||||||
const size_t remaining = ssbuf.sb.st_size - src->position; | ||||||||
if (remaining < maxlen) | ||||||||
maxlen = remaining; | ||||||||
} | ||||||||
|
||||||||
if (maxlen == PHP_STREAM_COPY_ALL) { | ||||||||
maxlen = 0; | ||||||||
} | ||||||||
|
@@ -1517,7 +1541,7 @@ PHPAPI zend_string *_php_stream_copy_to_mem(php_stream *src, size_t maxlen, int | |||||||
ptr = ZSTR_VAL(result); | ||||||||
|
||||||||
// TODO: Propagate error? | ||||||||
while ((ret = php_stream_read(src, ptr, max_len - len)) > 0){ | ||||||||
while (!php_stream_eof(src) && (ret = php_stream_read(src, ptr, max_len - len)) > 0){ | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I am not mistaken, php_stream_eof() also generates some system calls (poll(), recv() with MSG_PEEK flag). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only if the php-src/main/streams/streams.c Lines 789 to 791 in 05023a2
But you are right, PHP's "xp_streams" implementation is rather clumsy. The way it is implemented, my change adds one system call for streams (replacing recv() with poll() +recv() ); it still eliminates one extra read() system call for regular files!The xp_streams code could be optimized easily. Anybody interested? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two system calls, when it's not at the EOF, we got
How? I can not understand. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Oh yes, you are right. I thought about the "eof" case, but forgot about the "not-eof".
By omitting the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I always assume that doing so might cause a BC break. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
How?
You mean on operating systems which don't support |
||||||||
len += ret; | ||||||||
if (len + min_room >= max_len) { | ||||||||
result = zend_string_extend(result, max_len + step, persistent); | ||||||||
|
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.
@MaxKellermann I don't quite understand why this pull request got closed in it's entirety. I know there is an issue around commits 2+3, but commit 1 (file_get_contents without read buffer) is a clear, simple and non-breaking and uncontroversial improvement IMO. Maybe commit #e45f829 can be extracted into a new pull request to get merged?
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.
OK here you are #8547