Skip to content

Instantly share code, notes, and snippets.

@ivoanjo
Created February 21, 2023 11:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ivoanjo/3136f8608677ee5923439f50fd48eb95 to your computer and use it in GitHub Desktop.
Save ivoanjo/3136f8608677ee5923439f50fd48eb95 to your computer and use it in GitHub Desktop.
#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