This is an archive of the discontinued LLVM Phabricator instance.

[libc++] Implement file_clock::{to,from}_sys
ClosedPublic

Authored by ldionne on Nov 8 2021, 1:01 PM.

Details

Reviewers
mstorsjo
ldionne
Group Reviewers
Restricted Project
Commits
rGdce5fc56b619: [libc++] Implement file_clock::{to,from}_sys
Summary

This is part of https://wg21.link/P0355R7. I am adding these methods
to provide an alternative for the {from,to}_time_t methods that were
removed in https://llvm.org/D113027.

Diff Detail

Event Timeline

ldionne requested review of this revision.Nov 8 2021, 1:01 PM
ldionne created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptNov 8 2021, 1:01 PM
Herald added a reviewer: Restricted Project. · View Herald Transcript
ldionne added inline comments.Nov 8 2021, 1:03 PM
libcxx/include/chrono
2822

IIUC, both the system_clock and file_clock have the same Epochs (the Unix one) on all the platforms we support. So we shouldn't need to do any additional adjustment here AFAIU. Same for from_sys.

Quuxplusone added inline comments.
libcxx/docs/ReleaseNotes.rst
83–86

Instead, in C++20 you can use...?
But what about prior to C++20? Even if the answer is "go jump in a lake," I think it's worth release-noting that. :)

libcxx/test/std/utilities/time/time.clock/time.clock.file/to_from_sys.pass.cpp
34–37

Naming nit: When I see various variables named foo_now, it fires my red-flag detector for TOCTTOU vulnerabilities. In this case, file_now is arguably a "now," but sys_now is clearly a "then," because by the time we've computed it, "now" is later than before. ;) I suggest just ft and st, here and below. (You can still initialize ft with file_clock::now() if you're confident you won't mind whatever's going to happen to this test on DST day or whatever. I just don't like the variable's own name to include the word now.)

47–58

Here, this is a good use of variables named foo_now. :)
I'd recommend testing that

assert(std::chrono::milliseconds(-500) < diff && diff < std::chrono::milliseconds(500));

just to be on the safe side. (And notice my usual preference for () in object-factory-style constructors, idiomatically reserving {} for braced initializer lists.)

60–67

In many cases we'll have sys_diff == file_diff == 0, right?
I'm not sure I understand the fundamental point of this test; it might be clearer if we had any way of generating constant time_points other than the racey now().
Do we intend that

LIBCPP_ASSERT(std::is_same_v<decltype(sys_diff), decltype(file_diff)>);

?

ldionne updated this revision to Diff 385790.Nov 9 2021, 5:51 AM
ldionne marked 4 inline comments as done.

Address review comments. Thanks!

libcxx/docs/ReleaseNotes.rst
83–86

Oh, yeah, somehow I thought the from_time_t we removed was C++20 only. Will adjust to basically say "move to C++20", since this whole file_clock thing is supposed to be C++20 anyways. For some reason I would have bet that it was C++17 since it is tied to filesystem -- oh well.

libcxx/test/std/utilities/time/time.clock/time.clock.file/to_from_sys.pass.cpp
60–67

Do we intend that LIBCPP_ASSERT(std::is_same_v<decltype(sys_diff), decltype(file_diff)>);?

No, we don't. Or at least I don't. In my mind, decltype(sys_diff) is chrono::duration<representation-of-system-clock, period-of-system-clock> whereas decltype(file_diff) is chrono::duration<representation-of-file-clock, period-of-file-clock>, and both don't need to be the same. And in fact they aren't in our implementation (system clock has rep = long long, period = milliseconds and file clock has rep = int128_t, period = nanoseconds).

Both should be "equal", in the sense that if you convert both to the least granular measurement, you should get the same answer. However, both are not necessarily going to equal 0 ticks, because the two time stamps were not taken at the same time. In practice I expect the difference will be very small because there's almost no time between the two calls to now(), but we still should not assume it is 0.

Quuxplusone added inline comments.Nov 9 2021, 5:59 AM
libcxx/test/std/utilities/time/time.clock/time.clock.file/to_from_sys.pass.cpp
30

Btw, IMO it'd be nice to get rid of this line and use std::chrono:: everywhere, for greppability.

60–67

In practice I expect the difference will be very small because there's almost no time between the two calls to now(), but we still should not assume it is 0.

Right; what I meant was more in the line of "flaky tests." Here we have a test where — maybe not 99% of the time, but some significant fraction of the time — it's testing that 0 == 0; and then some small-and-nonreproducible remainder of the time, it's testing something-other-than-that. This is a "testing code smell."

It would be strictly better if we could do something like

auto const ft = chrono::file_clock::time_point("2021-01-01 01:23:45");
auto const st = chrono::system_clock::time_point("2021-01-01 01:23:45");
auto sys_diff = chrono::file_clock::to_sys(ft) - st;
auto file_diff = ft - chrono::file_clock::from_sys(st);
assert(sys_diff == file_diff);

but I don't know that such a primitive for generating timepoints exists (or if it does, it's probably in the date stuff we haven't implemented yet).

ldionne updated this revision to Diff 385882.Nov 9 2021, 10:24 AM
ldionne marked an inline comment as done.

Remove namespace chrono = std::chrono and add XFAIL on 32 bits.

ldionne added inline comments.Nov 9 2021, 10:28 AM
libcxx/test/std/utilities/time/time.clock/time.clock.file/to_from_sys.pass.cpp
60–67

I agree and would 100% have written the test that way, but as you say, we don't have a good way of generating a time point besides now().

ldionne updated this revision to Diff 386521.Nov 11 2021, 8:10 AM

Rebase onto main

ldionne accepted this revision.Nov 11 2021, 11:16 AM
This revision is now accepted and ready to land.Nov 11 2021, 11:16 AM
This revision was automatically updated to reflect the committed changes.