Created
February 21, 2023 11:05
-
-
Save ivoanjo/3136f8608677ee5923439f50fd48eb95 to your computer and use it in GitHub Desktop.
This file contains 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
#define _GNU_SOURCE | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <pthread.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <locale.h> | |
#define SECONDS_AS_NS(value) (value * 1000 * 1000 * 1000L) | |
#define MILLIS_AS_NS(value) (value * 1000 * 1000L) | |
static pid_t busy_thread_tid = 0; | |
static int clock_ticks_per_second = 0; | |
void *busy_thread(void *_unused) { | |
busy_thread_tid = gettid(); | |
uint64_t i = 0; | |
while (true) { | |
i = (i == UINT64_MAX) ? 0 : i + 1; | |
} | |
} | |
long time_from_clock_ns(clockid_t clock_id) { | |
struct timespec time = {0}; | |
int error; | |
error = clock_gettime(clock_id, &time); | |
if (error) printf("Error: %s\n", strerror(error)); | |
return time.tv_nsec + SECONDS_AS_NS(time.tv_sec); | |
} | |
long time_from_proc_ns(pid_t task_id) { | |
if (task_id == 0) return 0; | |
char filename[1024]; | |
snprintf(filename, 1024, "/proc/self/task/%d/stat", task_id); | |
FILE *stat = fopen(filename, "r"); | |
if (stat == NULL) printf("Error: %s\n", strerror(errno)); | |
uint64_t utime, stime; | |
fscanf(stat, "%*d %*s %*c %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lu %lu", &utime, &stime); | |
fclose(stat); | |
uint64_t total_ticks = utime + stime; | |
uint64_t total_time = SECONDS_AS_NS(((double) total_ticks) / clock_ticks_per_second); | |
return total_time; | |
} | |
void sleep_for(uint64_t time_ns) { | |
// As a simplification, we currently only support setting .tv_nsec | |
if (time_ns >= SECONDS_AS_NS(1)) { | |
printf("Error: time_ns cannot be >= 1s\n"); | |
} | |
struct timespec time_to_sleep = {.tv_nsec = time_ns}; | |
while (nanosleep(&time_to_sleep, &time_to_sleep) != 0) { | |
if (errno == EINTR) { | |
// We were interrupted. nanosleep updates "time_to_sleep" to contain only the remaining time, so we just let the | |
// loop keep going. | |
} else { | |
printf("Error: %s\n", strerror(errno)); | |
} | |
} | |
} | |
int main(int argc, char **argv) { | |
pthread_t thread; | |
int error = 0; | |
clock_ticks_per_second = sysconf(_SC_CLK_TCK); | |
srand(0); // Same seed on purpose | |
setlocale(LC_NUMERIC, ""); // For number formatting | |
error = pthread_create(&thread, NULL, busy_thread, NULL); | |
if (error) printf("Error: %s\n", strerror(error)); | |
clockid_t busy_thread_cpu_time; | |
error = pthread_getcpuclockid(thread, &busy_thread_cpu_time); | |
if (error) printf("Error: %s\n", strerror(error)); | |
long last_timestamp = time_from_clock_ns(CLOCK_MONOTONIC); | |
long last_cpu_time = time_from_clock_ns(busy_thread_cpu_time); | |
long last_proc_stat_time = time_from_proc_ns(busy_thread_tid); | |
printf("Started at TIMESTAMP %ld\n", last_timestamp); | |
while (true) { | |
long current_timestamp = time_from_clock_ns(CLOCK_MONOTONIC); | |
long current_cpu_time = time_from_clock_ns(busy_thread_cpu_time); | |
long current_proc_stat_time = time_from_proc_ns(busy_thread_tid); | |
printf("%'11ldns later (wall-time), observed cpu time delta is: %'11ldns, observed proc time is %'11ldns\n", current_timestamp - last_timestamp, current_cpu_time - last_cpu_time, current_proc_stat_time - last_proc_stat_time); | |
time_from_proc_ns(busy_thread_tid); | |
last_timestamp = current_timestamp; | |
last_cpu_time = current_cpu_time; | |
last_proc_stat_time = current_proc_stat_time; | |
sleep_for(rand() % MILLIS_AS_NS(10)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment