-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Replacing strftime with internal implementation #2544
Conversation
What is the goal of these changes? |
Library author suggestion (#2500 (comment)) and significant performance increase (С++11: 2-4 times, C++17: up to 13 times) (https://github.com/phprus/fmt-bench/tree/optimize-tm-formatting-3). |
So here are the results of quick and dirty tests of current trunk and you implementation at fd23701 (timings are in nanoseconds):
The penultimate format string is a shorter form from this stackoverflow answer. Now for simple cases your implementation saves from 250 to 370 ns. Basically you made fast cases faster, but slow cases much slower. That's why I asked about the goal of these changes. |
Performance test: https://github.com/phprus/fmt-bench/tree/9dc6195ad904b58394e527bc9f04ed7480764d99 macOS 10.14.6 Mojave C++11:
C++17:
In all cases on my MacBookPro, the presented implementation is faster. I couldn't find an environment where |
Windows 10
copy paste of all runsC++11
C++17
C++20
|
Thanks! |
Please rerun the test with the following changes:
|
@phprus, I don't understand what you mean by "locale settings". Though
|
I'm not doing it because I've already spent more time on this than I would've wanted. |
Windows ucrt Replacing |
Talking about slowness of |
I wouldn't worry too much about Windows, we can optimize exotic formats there later (not in this PR). |
…r locale independent formats
…ock, Duration> and std::tm
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.
Thanks for the PR! Overall looks good but please address inline comments.
153a0c4
to
c1e52a3
Compare
Requested changes
c1e52a3
to
4cc64b7
Compare
Looks good but there is still an unneeded |
Done |
include/fmt/chrono.h
Outdated
}; | ||
|
||
template <typename OutputIt, typename Char> class tm_writer { | ||
using char_type = Char; |
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.
It's no longer needed as you can use Char
directly.
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.
Done
a8f14ec
to
8cdc0b3
Compare
Thank you! |
Tomorrow I will start porting the code to using |
Looks like there is a UB in
|
Input data is unknown? I will prepare a patch today... |
I think it's just a large year that causes an overflow in Line 1426 in 684e2fd
|
Cast to |
Sanitizer caught one more UB due to overflow: #include <fmt/chrono.h>
int main() {
char tz[] = "PDT";
auto t = std::tm{.tm_sec = 23,
.tm_min = 22,
.tm_hour = 22,
.tm_mday = 15,
.tm_mon = 9,
.tm_year = 2147483638,
.tm_wday = 6,
.tm_yday = 287,
.tm_isdst = 1,
.tm_gmtoff = -25200,
.tm_zone = tz};
fmt::print("{:%F}", t);
} |
This is an unfixable error due to an offset of 1900 years: Line 1409 in 249f03b
In PR #2550, I added an If the year number overflows due to an offset of 1900 years, we can only throw an exception (we will need to check the range for each call) or output an undefined value (as now, due to a signed int overflow). |
I don't think assert is enough because we'll still get a UB when they are disabled. I suggest throwing an exception instead. |
Proposal: #2500 (comment)
Discussion: Issue #2541
All locale independent formats are implemented native with significant performance increase (С++11: 2-4 times, C++17: up to 13 times).
For locale dependent formats, strftime is used.
Draft because:
Performance regression on Windows, because
ucrt
strftime
is slow by design.Possible solution for Windows regression: split processing into 2 way: fast path and slow path.
Slow path: unrecognized format string (non-standard extensions) or locale-dependent (except "C" locale?) formats in the format string.
Else: Fast path.
Pass the slow path formatting string to
strftime
orstd::time_put
. Fast path - internal implementation.