Created
February 14, 2026 13:16
-
-
Save marcusmueller/9253e90c50bbcea6bbba41b68b6a067b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Copyright 2023 Marcus Müller | |
| * | |
| * SPDX-License-Identifier: GPL-3.0 | |
| * | |
| */ | |
| #include <fcntl.h> | |
| #include <stdint.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <sys/stat.h> | |
| #include <time.h> | |
| #include <unistd.h> | |
| int64_t ns_difference(struct timespec* before, struct timespec* restrict after) | |
| { | |
| return ((int64_t)after->tv_nsec - (int64_t)before->tv_nsec) + | |
| 1000 * 1000 * 1000 * ((int64_t)after->tv_sec - (int64_t)before->tv_sec); | |
| } | |
| int main(int argc, char* argv[]) | |
| { | |
| struct timespec now_coarse; | |
| struct timespec now; | |
| struct timespec now_after; | |
| char* data = "hello"; | |
| size_t length = strlen(data); | |
| struct stat props; | |
| clock_gettime(CLOCK_REALTIME_COARSE, &now_coarse); | |
| clock_gettime(CLOCK_REALTIME, &now); | |
| int fd = open("temp", O_WRONLY | O_CREAT); | |
| write(fd, data, length); | |
| close(fd); | |
| clock_gettime(CLOCK_REALTIME, &now_after); | |
| stat("temp", &props); | |
| printf("Coarse RT clock before: %10jd.%06ld s\n", | |
| (int64_t)now_coarse.tv_sec, | |
| now_coarse.tv_nsec / 1000); | |
| printf("Realtime clock before: %10jd.%06ld s\n", | |
| (int64_t)now.tv_sec, | |
| now.tv_nsec / 1000); | |
| printf("File Modification time: %10jd.%06ld s\n", | |
| (int64_t)props.st_mtim.tv_sec, | |
| props.st_mtim.tv_nsec / 1000); | |
| printf("Realtime clock after: %10jd.%06ld s\n", | |
| (int64_t)now_after.tv_sec, | |
| now_after.tv_nsec / 1000); | |
| printf("Differences relative to coarse clock before:\n" | |
| "Fine Realtime before: %+8jd ns\n" | |
| "File Modification Time: %+8jd ns\n" | |
| "Realtime clock after: %+8jd ns\n", | |
| ns_difference(&now_coarse, &now), | |
| ns_difference(&now_coarse, &props.st_mtim), | |
| ns_difference(&now_coarse, &now_after)); | |
| unlink("temp"); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Copyright 2023 Marcus Müller | |
| * | |
| * SPDX-License-Identifier: GPL-3.0 | |
| * | |
| */ | |
| #include <fcntl.h> | |
| #include <math.h> | |
| #include <stdint.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <sys/stat.h> | |
| #include <time.h> | |
| #include <unistd.h> | |
| int64_t ns_difference(struct timespec* before, struct timespec* restrict after) | |
| { | |
| return ((int64_t)after->tv_nsec - (int64_t)before->tv_nsec) + | |
| 1000 * 1000 * 1000 * ((int64_t)after->tv_sec - (int64_t)before->tv_sec); | |
| } | |
| int main(int argc, char* argv[]) | |
| { | |
| struct timespec now_coarse; | |
| char* data = "hello"; | |
| const size_t length = strlen(data); | |
| struct stat props; | |
| const uint64_t total_max_count = 1ULL * 100 * 1000 * 1000; | |
| const uint32_t hit_max_count = 10 * 1000; | |
| uint64_t total_count = 0; | |
| uint32_t hit_count = 0; | |
| const uint64_t tick_mask = (1 << 16) - 1; | |
| int32_t* hits = (int32_t*)malloc(sizeof(int32_t) * hit_max_count); | |
| for (; total_count < total_max_count && hit_count < hit_max_count; ++total_count) { | |
| clock_gettime(CLOCK_REALTIME_COARSE, &now_coarse); | |
| int fd = open("temp", O_WRONLY | O_CREAT | O_TRUNC); | |
| write(fd, data, length); | |
| close(fd); | |
| stat("temp", &props); | |
| unlink("temp"); | |
| if (props.st_mtim.tv_nsec != now_coarse.tv_nsec || | |
| props.st_mtim.tv_sec != now_coarse.tv_sec) { | |
| hits[hit_count] = ns_difference(&now_coarse, &(props.st_mtim)); | |
| ++hit_count; | |
| } | |
| if (!(total_count & tick_mask)) { | |
| putchar('.'); | |
| } | |
| } | |
| putchar('\n'); | |
| FILE* outfd = fopen("out.csv", "w"); | |
| for (uint32_t idx = 0; idx < hit_count; ++idx) { | |
| fprintf(outfd, "%d\n", hits[idx]); | |
| } | |
| fclose(outfd); | |
| printf("Total processed: %10jd\n" | |
| "Observed tick progressions: %10u\n" | |
| "Percentage: %2.3f\n", | |
| total_count, | |
| hit_count, | |
| (double)hit_count / total_count); | |
| int32_t max_diff = INT32_MIN; | |
| int32_t min_diff = 2000 * 1000; | |
| uint64_t sum = 0; | |
| for (uint32_t idx = 0; idx < hit_count; ++idx) { | |
| int32_t val = hits[idx]; | |
| sum += val; | |
| if (val < min_diff) { | |
| min_diff = val; | |
| } | |
| if (val > max_diff) { | |
| max_diff = val; | |
| } | |
| } | |
| double average = (double)sum / hit_count; | |
| int32_t int_average = lrint(average); | |
| uint64_t varsum = 0; | |
| for (uint32_t idx = 0; idx < hit_count; ++idx) { | |
| int32_t val = hits[idx]; | |
| varsum += (val - int_average) * (val - int_average); | |
| } | |
| double variance = (double)varsum / hit_count; | |
| printf("Minimum tick delta: %10d\n" | |
| "Maximum tick delta: %10d\n" | |
| "Average tick delta: %10f\n" | |
| "Variance: %10f\n", | |
| min_diff, | |
| max_diff, | |
| average, | |
| variance); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment