Skip to content
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

Implement date --resolution #6272

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

Dj-Codeman
Copy link

Implementing the --resolution flag for date

Copy link

GNU testsuite comparison:

Skipping an intermittent issue tests/tail/inotify-dir-recreate (passes in this run but fails in the 'main' branch)

@sylvestre sylvestre changed the title Data resolution Implement date --resolution Apr 26, 2024
Copy link

GNU testsuite comparison:

Skipping an intermittent issue tests/tail/inotify-dir-recreate (passes in this run but fails in the 'main' branch)

Copy link
Collaborator

@BenWiederhake BenWiederhake left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your overall approach "try to use libc::clock_getres, try to handle any errors sensibly" is a good approach, and exactly the right function for this job. Great! :D

See below for many changes.

Also, please write tests, ideally so that CI can test both the CLOCK_REALTIME and CLOCK_MONOTONIC paths. I'm not entirely convinced whether it is a good idea to even query CLOCK_MONOTONIC, because if CLOCK_REALTIME is not available, then the system is either extremely non-conformant or about to kernel panic anyway. And CLOCK_MONOTONIC measures something completely different. When you write tests for this, I'm sure you will stumble upon either a good argument why this is a good idea to keep in, or you will find that all systems support CLOCK_REALTIME anyway.

@@ -1,17 +0,0 @@
repos:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't delete this unrelated file, other people need it :D

Comment on lines +135 to +137
let resolution_secs: f32 =
res_ts.tv_sec as f32 + res_ts.tv_nsec as f32 / RESOLUTION_DIVISOR;
resolution_secs
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let resolution_secs: f32 =
res_ts.tv_sec as f32 + res_ts.tv_nsec as f32 / RESOLUTION_DIVISOR;
resolution_secs
res_ts.tv_sec as f32 + res_ts.tv_nsec as f32 / RESOLUTION_DIVISOR

@@ -103,6 +107,75 @@ enum Iso8601Format {
Ns,
}

// Enum for system clock resolution
enum TimeResolution {}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this needs to be a type.

src/uu/date/src/date.rs Show resolved Hide resolved
Comment on lines +152 to +161
let mut resolution_final: String = String::new();
resolution_final.push_str("0.");
let mut i: u8 = 0;
while i <= resolution_length {
resolution_final.push('0');
i += 1;
}
resolution_final.push('1');

resolution_final.parse::<f32>().unwrap_or(0.1)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let mut resolution_final: String = String::new();
resolution_final.push_str("0.");
let mut i: u8 = 0;
while i <= resolution_length {
resolution_final.push('0');
i += 1;
}
resolution_final.push('1');
resolution_final.parse::<f32>().unwrap_or(0.1)
(0.1).powi(resolution_length)

Also, I'm unhappy that this "guessing" has to happen at all. For example, on a system with a 1-nanosecond resolution it will claim a worse resolution once every 9 tries (10% + 1% + 0.1% + …), that's the perfect breeding ground for Heisenbugs.

If this guessing approach is kept, please add tests to it. (See below.)

Comment on lines +163 to +165
};

resolution
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified.

Example:

fn foo() {
    let bar = match { /* ... */ };
    bar
}

… can be turned into:

fn foo() {
    match { /* ... */ } // No semi-colon
}

}

fn clock_type(ts: &mut timespec) -> Option<i32> {
if unsafe { libc::clock_gettime(CLOCK_REALTIME, &mut *ts) } == 0 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the function unsafe, and why is it safe to use in this particular case? Please write the second answer in a comment, for both function calls.

Why &mut *ts instead of just ts? Rust should automatically coerce a mut-ref to a mut-pointer, and testing this in the playground, this should work.

} else if unsafe { libc::clock_gettime(CLOCK_MONOTONIC, &mut *ts) } == 0 {
Some(CLOCK_MONOTONIC)
} else {
None
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When can this ever happen? If the system is really borked to this degree, then we probably shouldn't guess anyway.

Oh, and this is a bug: If this case ever happens, then ts probably contains garbage data, and must not be used to estimate anything. I suggest just returning "resolution is 1 second" in that scenario.

.long(OPT_RESOLUTION)
.value_name("RESOLUTION")
.help("output the available resolution of timestamps")
.action(ArgAction::SetTrue),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you implement it, please make sure that you set overrides_with, so that date --resolution --resolution also works :)

Please implement and also test this.

}
Some(CLOCK_MONOTONIC) => {
let mut res_ts: timespec = ts;
unsafe { libc::clock_getres(CLOCK_MONOTONIC, &mut res_ts) };
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clock_getres can fail, and the return value must be checked: https://docs.rs/libc/latest/libc/fn.clock_getres.html

And because it must be checked anyway, I don't understand why this code calls SystemTime::now(); and then also clock_gettime.

@sylvestre
Copy link
Sponsor Contributor

ping ? :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants