procfs · the kernel as a filesystem
Linux exposes nearly every piece of live kernel state at /proc/. Each file is a synthetic view of a kernel data structure — open it, read it, and you've just inspected a running process from userspace.
/proc/1234/stat and find the utime field (14th). That number, divided by HZ (typically 100), is the user-mode CPU seconds this process has accumulated. Tools like top sample this file in a loop.Source
// procfs · /proc/[pid]/stat — kernel state exposed as a file
// Read with fopen(); fscanf the per-field values.
// Fields (from man 5 proc):
// pid (1) comm (2) state (3) ppid (4) pgrp (5) ...
// utime (14) stime (15) ... ← user/kernel CPU time
// starttime (22) ← clock-tick offset since boot
FILE *f = fopen("/proc/self/stat", "r");
fscanf(f, "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu",
&pid, comm, &state, &ppid, &pgrp, &session, &tty, &tpgid,
&flags, &minflt, &cminflt, &majflt, &cmajflt, &utime, &stime);
fclose(f);What's really happening
/proc isn't a real filesystem — there are no files on disk. Every read is synthesized by the kernel on demand from internal data structures (task_struct, mm_struct,files_struct, etc.). This is why cat /proc/uptime gives a fresh value every time.
Why this is a big deal: /proc lets userspace tools introspect kernel state without syscalls per piece of data. ps, top, lsof, htopand a dozen others all just read these files. Most modern observability stacks bottom out here (or in eBPF, the other answer to the same question).
/proc/[pid]/stat in particular is a single space-separated line with ~50 fields documented in man 5 proc. The CSV-ish format is a stable kernel ABI — modern fields are appended to the end so older tools still parse correctly. Backwards compatibility for decades.