CoreFreq: reading the CPU counters, and the watchdog you have to turn off
CoreFreq : CPU monitoring and tuning software designed for the 64-bit processors.
At a glance
- What is it?
- CoreFreq is a GPL-2.0 Linux kernel module plus daemon plus client that reads core ratios, performance counters, C-States, junction temperature and voltage across Intel, AMD Zen 5, Arm, RISC-V and PowerPC. For accurate readings on Intel it asks you to add nmi_watchdog=0 to the kernel command line and rebuild against the fixed counters, which is a real trade the README states without spelling out what you lose.
- Who is it for?
- Use CoreFreq if you need per-core frequency ratios, instruction-per-cycle figures, package C-State residency or junction headroom that the usual desktop tools estimate rather than read, and you are on bare metal with a kernel you are willing to load a module into.
- Can I use it commercially?
- Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 7 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.
Editorial analysis
nmi_watchdog=0, and the counter remap that makes it necessary
The first prerequisite in the README is the one to read twice, because it asks you to change a system-wide kernel setting for a measurement benefit.
For Intel only, for a better accuracy, disable the kernel NMI Watchdog. Add nmi_watchdog=0 in the kernel boot loader, and build with the fixed performance counters:
nmi_watchdog=0make MSR_CORE_PERF_UC=MSR_CORE_PERF_FIXED_CTR1 MSR_CORE_PERF_URC=MSR_CORE_PERF_FIXED_CTR2Two separate changes, and the second one explains the first. The Makefile's defaults are MSR_CORE_PERF_UCC ?= MSR_IA32_APERF and MSR_CORE_PERF_URC ?= MSR_IA32_MPERF. Those are the derived performance counters, the pair a hypervisor and a kernel most want to read because they are cheap and always available. They are also shared. Anything else on the system that reads them contaminates CoreFreq's numbers, and the kernel's NMI watchdog is one such reader.
So the accuracy problem is contention on a counter pair, and the fix is to move CoreFreq onto the fixed counters instead, FIXED_CTR1 and FIXED_CTR2, which are otherwise unclaimed. The README presents the rebuild as part of the accuracy step, which is the right way to present it, and it is a genuinely clever piece of engineering: instead of asking everyone else to stop counting, count on different registers.
The boot parameter is the part that is not clever, and it is where the cost sits. nmi_watchdog=0 disables the kernel's non-maskable-interval watchdog for the entire system, not for CoreFreq and not for the process you are measuring. The NMI watchdog is a last-resort mechanism: if the kernel stops responding to everything else, the watchdog fires an NMI, the kernel prints a backtrace of where it was stuck, and on many systems the machine panics and reboots. That backtrace is frequently the only evidence you get about a hardware hang or a firmware bug.
Disabling it means a kernel that hangs does not report why. There is no other component that can do this, because a hung kernel is by definition not running the code that would report it.
The README's phrasing is for a better accuracy, and it does not mention the watchdog's diagnostic role at all. That is not dishonesty, it is the perspective of someone who reads the counter and does not think about the person debugging a hang. But it is a system-wide change made for a per-measurement benefit, and it is the decision in this project an evaluator should make most deliberately.
The setting is also Intel-only in the instructions, which is consistent: the counter contention that motivates the remap is a property of how x86 performance counters are shared, and the Arm, RISC-V and PowerPC paths do not have MSRs in the same sense.
A kernel module means DKMS and CKMS are load-bearing
CoreFreq is a Linux kernel module, and that single fact determines most of the operational cost of running it.
The architecture is three processes. corefreqk is the kernel module. corefreqd is a daemon that runs as root. corefreq-cli is the client, which runs as an ordinary user in another terminal or console. The module reads the hardware registers; the daemon mediates; the client renders. The README is explicit that a shared memory exists to protect the kernel from the user-space part of the software, and that threads are synchronised atomically to avoid mutexes and deadlock inside the kernel.
That privilege split is the right design and it is worth naming what it means. The kernel module runs at the highest privilege on the machine and reads model-specific registers, so it is a substantial trust assumption, which is why the GPL-2.0 licence and the single named author matter: you are loading code written by one person into the kernel of your machine. The daemon runs as root and is the process that talks to the module. The client runs unprivileged, so the rendering layer, which is the part that parses SMBIOS strings and draws a colour dashboard, is not privileged.
The operational consequence is that a kernel upgrade breaks CoreFreq until it is rebuilt, because a kernel module is compiled against a specific kernel's headers and ABI. The repository's answer is at the top level: dkms.conf and ckms.ini. DKMS is the Dynamic Kernel Module Support system used by Debian and Ubuntu, and CKMS is the CentOS, RHEL and Fedora equivalent. Both rebuild the module automatically when the kernel changes.
Neither file is in the build or install instructions, which is the gap. The README walks through building from source with git clone, cd CoreFreq, make -j, and then installing with make install, loading with insmod build/corefreqk.ko or modprobe corefreqk, and starting the daemon with systemctl start corefreqd. The manual path is complete and correct. What it does not say is that the manual path is the one that will leave you broken after your next kernel update, and that dkms.conf and ckms.ini exist to prevent exactly that.
The signing requirement is the other operational detail. If module signature verification is enabled in your kernel, you have to sign corefreqk.ko, and the README links to the kernel's own module-signing documentation and to the Gentoo wiki page on manually signing modules. That is a real step that distributions with Secure Boot enabled will hit, and the build produces the unsigned .ko that needs it.
For distributions other than Arch, the README also notes that you may need to reload the systemd daemons with systemctl daemon-reload after installing, because corefreqd.service has to be picked up. That is a small friction point and it is the kind of thing that gets reported as a bug when it is not.
So the honest summary of running this is: you are loading a third-party kernel module, you need automatic rebuilds across kernel upgrades, you may need to sign it, and you may need to reload systemd. The measurement it gives you is worth that to some people and not to others.
Four architectures, selected by uname, and an AMD list that reaches Zen 5
The build chooses its source directory from the running machine, and the repository has one directory per architecture.
The Makefile sets HW = $(shell uname -m) and then adds -I$(PWD)/$(HW) to the kernel module's compiler flags. The repository contains x86_64/, aarch64/, ppc64le/ and riscv64/. So there is no configure step and no --target flag: you build on the machine you intend to run on, and make reads uname to find the right table of register definitions.
That design follows from what the program is. Reading a core frequency ratio or a junction temperature means reading a register whose address and bit layout are specific to a CPU microarchitecture, and microarchitectures are enumerated by family and model numbers that differ per vendor. The README's coverage list is written in exactly those terms, and the AMD half is the clearest example because AMD publishes family codes: families from 0Fh up to 17h covering Zen, Zen+ and Zen 2, 18h for Hygon Dhyana, 19h for Zen 3, Zen 3+, Zen 4 and Zen 4c, and 1Ah for Zen 5 and Zen 5c.
Reading that list tells you two things. First, the coverage is current: 1Ah is Zen 5, so a machine you can buy now is supported. Second, the cost of staying current is structural. Every time Intel or AMD ships a new microarchitecture with new registers, someone has to add a table. That is not a documentation task, it is a code task, and it recurs on a schedule set by two vendors rather than by the project.
On the Intel side the list is phrased by marketing name instead: Atom, Core 2, Nehalem, SandyBridge and superiors. The superiors is doing a lot of work there, since everything since Sandy Bridge is covered by implication, and Intel's more recent hybrid designs and Efficiency cores are not named at all.
The architecture list in the repository's own topic tags matches: aarch64, amd-epyc, amd-threadripper, arm64, intel-x86-64, powerpc, riscv64, ryzen, and dgx-spark, which is an NVIDIA box built on an Arm SoC, so the aarch64 path is being used on hardware nobody would have predicted for a CPU monitor.
The measurement surface, once the architecture is right, is listed in the Purpose section. Core frequencies and ratios, with SpeedStep, Turbo Boost, Hyper-Threading and base clock. Performance counters including the Time Stamp Counter, Unhalted Core Cycles and Unhalted Reference Cycles. Instructions per cycle or per second, reported as IPS, IPC or CPI. C-States C0, C1, C3, C6 and C7, plus the package-level C1E and auto-undedmonotion of C1 and C3. DTS temperature and Tjunction Max with TM1 and TM2 thermal monitoring state. Core voltage, if and only if the registers are documented. A topology map including caches. And processor features, brand and architecture strings.
That last qualifier on voltage is doing real work. Core voltage is read from registers that AMD has never documented on consumer parts, so on those chips the feature is absent rather than approximate, and the README says so rather than shipping a number that means nothing.
CORE_COUNT is 256 and MAX_FREQ_HZ is 7.125 GHz, both compiled in
The Makefile is a plain hand-written build with no configure script, which means its defaults are compile-time constants, and two of them are limits rather than preferences.
CORE_COUNT ?= 256 is passed to both the kernel module and the user-space builds as -D CORE_COUNT=$(CORE_COUNT). TASK_ORDER ?= 5 does the same. MAX_FREQ_HZ ?= 7125000000 does the same. UBENCH = 0 also does.
CORE_COUNT is the one to look at. A compile-time constant of 256 that is used to size per-CPU data structures is a hard ceiling, not a starting point, and 256 is not a large number of threads by 2026 standards. A 32-core Threadripper with SMT gives you 64. A large EPYC or Xeon in a high-density configuration can pass 256, and at that point the correct response is to rebuild with a different value rather than to expect the tool to cope.
That is a real constraint and it is invisible from the README, which never mentions CORE_COUNT. The only way to find it is to read the Makefile or to run out of array space. And the rebuild is not painful: it is a make variable on the command line, the same mechanism as the performance-counter remap. The problem is discoverability, not difficulty.
MAX_FREQ_HZ at 7.125 GHz is a different kind of constant. It looks like a ceiling on what frequency the code will consider valid, which makes sense as a sanity bound against a misread register. The implication is that a CPU boosting above 7.125 GHz would produce a frequency reading that fails the bound, and the fix is another make variable rather than a code change. A 2026 part running at 6 GHz is inside it; a heavily overclocked one might not be.
The version numbers work the same way and are worth noting because they are not derived from git. COREFREQ_MAJOR = 2, COREFREQ_MINOR = 1 and COREFREQ_REV = 4, and they are passed as -D COREFREQ_MAJOR, -D COREFREQ_MINOR and -D COREFREQ_REV to both the kernel and user-space builds. So the version is compiled into the binaries and into the module, and the same three numbers have to be consistent across the source, the Makefile and the release tag. They currently agree: the Makefile says 2.1.4 and the newest tag is v2.1.4.
There is also a DELAY_TSC knob that defaults to 1 on x86_64 and 0 everywhere else, which is x86-specific time-stamp-counter delay compensation, and an optional optimisation level where OPTIM_LVL=0 adds -fno-inline. A kernel module with inlining disabled is a deliberate choice about generated code size and about keeping the hot path auditable.
The warning flags are -Wall -Wfatal-errors, so a warning is not fatal but the first error stops the build. And the Makefile is careful about verbosity: it detects -s in MAKEFLAGS and suppresses the ln, mkdir and rm invocations, so a silent build is genuinely silent.
Virtualization means one Hyper-V register, and nothing else
One prerequisite section covers virtualisation, and it is short enough that the constraint is easy to miss.
On AMD and Intel, some virtualisation. The explanation is that virtual machines do not provide access to the registers the CoreFreq driver employs: the fixed performance counters, the model specific registers, and the PCI registers. However, CoreFreq is making use of the virtualized performance counter HV_X64_MSR_VP_RUNTIME, at address 0x40000010.
That address is the Hyper-V enlightened VMCS MSR, and it is a Microsoft hypervisor interface. So the practical position is: CoreFreq does not work in a virtual machine, except in a Hyper-V one, and even there only through a single register that gives you a subset of what you get on bare metal.
This is worth stating plainly because it is the question a lot of evaluators have. The tool needs hardware performance counters, and hardware performance counters are precisely the thing hypervisors do not pass through, because they are the mechanism a guest would otherwise use to infer what the host and the other tenants are doing. That is a deliberate security boundary in every mainstream hypervisor, not an oversight.
Hyper-V is the exception because Microsoft's stack defines the interface itself. So a cloud instance on Azure, or a Hyper-V VM on a physical server, gets partial support, and a Proxmox, VMware, VirtualBox, KVM, Parallels or AWS Nitro instance does not.
The consequence for evaluation is that CoreFreq is a bare-metal tool. If you are deciding whether to adopt it for a fleet that includes virtual machines, the answer for the virtual ones is no, and there is no configuration that changes that. The README's phrasing, some virtualisation, is accurate and understated.
The build output gives one more clue about the modern state of this. The make -j output ends with a BTF step for the module, generating BPF Type Format information for corefreqk.ko. BTF is the metadata format that lets eBPF programs and tools understand kernel and module data structures at runtime without compiled-in knowledge. A CPU monitor generating BTF for its module is a project that is being built with current kernel tooling rather than against a decade-old baseline.
The other prerequisites are much older. The Linux kernel minimum is 3.3, which dates from 2012, and the GNU C Library is the only userspace dependency. A fifteen-year-old kernel floor and BTF support in the same build is the shape of a project that keeps its compatibility promise while adopting new features where they are free.
Monitoring ships; the BIOS-like tuning half is still in progress
The project describes itself as CPU monitoring software with BIOS like functionalities, and the difference between those two phrases is the gap between what is installed and what is listed as in progress.
The Purpose section ends with a bulleted list headed In progress. It covers the Uncore, memory controller channels and geometry, DIMM timings, stress tools, power and energy with RAPL, P-State, HWP and TDP, overclocking, the cpuidle and cpufreq drivers, ClockSource, and Mitigation Mechanisms.
That is a substantial list and it is roughly everything you would use a BIOS for. Overclocking, memory timings, power limits and idle-state tuning are the BIOS's core functions, and none of them are implemented. The words BIOS like functionalities are aspirational: the resemblance is the target, not the current state.
What does ship is measurement, and the measurement is the good part. Core frequencies and ratios against SpeedStep, Turbo Boost, Hyper-Threading and base clock, so you can see what the processor is actually doing rather than what it is rated for. The performance counters, so you can compute instructions per cycle and see whether a workload is compute-bound or stalled. Package C-States, which is the number that tells you whether a modern idle machine is actually idling. DTS temperature and Tjunction Max with the TM1 and TM2 monitoring state, so you can see how much thermal headroom you have before throttling. And a topology map including caches, which is useful for anyone reasoning about NUMA behaviour.
The client is where the shipped measurement surfaces. The help output lists interface options including absolute frequency, package C-States, memory units in kilobyte, megabyte or gigabyte, energy unit toggling, temperature in Fahrenheit, SMBIOS string index and colour theme index, and a Show Secret Data flag. The command options are a view selector with frequency, instructions, core, idle, package, tasks, interrupts, sensors, voltage, power, slices and custom views, a dashboard, and monitoring modes for sensors, voltage and power.
That is a well-built terminal dashboard rather than a set of scripts. The build produces four client object files, corefreq-cli.o, corefreq-cli-rsc.o, corefreq-cli-json.o and corefreq-cli-extra.o, so there is a resource monitor, a JSON output mode and an extras module alongside the main client. The JSON mode is what you would use to feed the readings into something else.
On rendering, the UI wants an ASCII console or an Xterm with VT100 support and ANSI colours, with optional transparency. The README then gives per-terminal fixes, which is a good sign about the author's own setup: Ubuntu Terminal has a Show bold text in bright colors preference, alacritty needs draw_bold_text_with_bright_colors set to true in its config file, and SSH needs a forced pseudo-terminal allocation with ssh -t corefreq-cli because a menu-driven application on a remote machine needs a TTY. That last one is the detail that matters most in practice, and it is the kind of thing that only appears in a README written by someone who has done it.
v2.1.3 and v2.1.4, two and a half hours apart
The release history is short, which for a project that has been running since 2015 says something about its release discipline.
The three most recent tags are v2.1.2 on 2026-06-19, v2.1.3 on 2026-08-16 at 07:11, and v2.1.4 on 2026-08-16 at 09:48. The last push was on 2026-09-23, about five weeks after the newest tag.
Two releases on the same morning, two and a half hours apart, both patch-level. That is the signature of a fix that shipped and was then followed by a second fix, or of a build or packaging problem discovered immediately after tagging. Neither is a problem in itself; the notable thing is that the maintainer was clearly present and shipping.
The gap before that is about two months, from v2.1.2 in June to v2.1.3 in August, which fits a monitoring tool. There is nothing to release when nothing has changed, and the changes that do get made are usually new CPU support or a register fix for a newly released part.
The version scheme is a plain triple, and as the Makefile section noted, the same three numbers are compiled into both the kernel module and the user-space binaries as COREFREQ_MAJOR, COREFREQ_MINOR and COREFREQ_REV. So the version is not derived from git and cannot drift silently, but it also means the Makefile is a place where the version has to be edited by hand, and a tag that does not match the Makefile would produce binaries that misreport themselves.
The project is GPL-2.0 with a LICENSE file at the root, and the copyright line reads 2015-2026 Cyril Courtiat, appearing both in the Makefile header and in the client's own help output. One named author, eleven years, and a tool that loads code into the kernel. That combination is the main thing to weigh, and it is not a criticism: a CPU register monitor is a domain where one person who has spent a decade learning the per-microarchitecture register layouts is genuinely better placed than a rotating committee, and the coverage list running through Zen 5 is evidence of that decade.
The homepage is the author's own site at cyring.fr rather than a documentation subdomain, and the README is the documentation. There is no separate docs directory in the top-level listing, which for a project of this size and this age is either a deliberate choice or an accumulation rather than a design.
What the README does contain is unusually complete for a single-author C project. The prerequisites cover the kernel configuration in detail, with three mandatory symbols, a long optional list including the BORE and Cachy schedulers and ACPI_CPPC_LIB, and one symbol explicitly marked forbidden. The build steps include the actual compiler output so you can tell a successful build from a partial one. The install section covers both the from-source path and the distribution-package path, and the start section covers both. That is the shape of documentation written by someone who has answered the same questions many times.
Editorial conclusion
Use CoreFreq if you need per-core frequency ratios, instruction-per-cycle figures, package C-State residency or junction headroom that the usual desktop tools estimate rather than read, and you are on bare metal with a kernel you are willing to load a module into. Do not install it on a machine where a silent kernel hang is your only fault signal, because the accuracy path on Intel requires disabling the NMI watchdog for the whole system, not just for CoreFreq, and the README does not say what that costs. Do not expect it to work in a virtual machine, since the only virtualized path it uses is the Hyper-V enlightened MSR. Do not expect the tuning half, either: overclocking, RAPL energy reporting, cpuidle and cpufreq control and mitigation inspection are all listed as in progress. Verify five things. Read your current kernel configuration and check CONFIG_TRIM_UNUSED_KSYMS is not enabled, because the README lists it as forbidden and the module will not link without the symbols. Confirm your architecture is covered: the build picks a source directory from uname, and the AMD support is indexed by family code up to 1Ah for Zen 5. Check CORE_COUNT, which is compiled in at 256, against your machine's thread count. Set up DKMS or CKMS before you need it, because an ordinary kernel upgrade will otherwise leave you with a module that no longer loads. And decide about the NMI watchdog on Intel deliberately, reading the kernel documentation on what the watchdog protects before you disable it.
Frequently asked questions
What is CoreFreq and what does it measure?
It is a Linux kernel module, daemon and terminal client for CPU monitoring on 64-bit processors, reading core frequencies and ratios, SpeedStep, Turbo Boost and Hyper-Threading, performance counters including TSC, Unhalted Core Cycles and Unhalted Reference Cycles, instructions per cycle, C-States C0 through C7, DTS temperature and Tjunction Max, core voltage where the registers are documented, and a topology map including caches. It covers Intel, AMD through Zen 5, Arm A64, RISC-V RV64 and PowerPC64.
Why do I have to disable the NMI watchdog on Intel?
The README says it is for better accuracy. The Makefile defaults map UCC and URC to the derived counters APERF and MPERF, which are shared, so other readers including the kernel's NMI watchdog contaminate the readings. The fix is a boot parameter of nmi_watchdog=0 plus a rebuild with MSR_CORE_PERF_UC=MSR_CORE_PERF_FIXED_CTR1 and MSR_CORE_PERF_URC=MSR_CORE_PERF_FIXED_CTR2, moving CoreFreq onto the otherwise unused fixed counters. The watchdog is disabled system-wide, not just for CoreFreq.
Does CoreFreq work in a virtual machine?
Generally no, because virtual machines do not expose the fixed performance counters, model specific registers or PCI registers it depends on. The one exception is a virtualized performance counter at HV_X64_MSR_VP_RUNTIME, 0x40000010, which is the Hyper-V enlightened MSR. So Hyper-V guests get partial support and other hypervisors get none.
How do I build and install CoreFreq?
Clone the repository, cd CoreFreq, run make -j, then make install. Load the module with modprobe corefreqk or insmod build/corefreqk.ko, start the daemon as root with systemctl start corefreqd, and run corefreq-cli as an ordinary user. If your kernel enforces module signature verification you must sign corefreqk.ko, and if you did not use DKMS or CKMS you will need to rebuild after every kernel upgrade.
What is the CORE_COUNT limit in CoreFreq?
It is a compile-time constant, 256 by default, passed to the kernel module and the user-space build as a -D define, so it sizes per-CPU data structures and is a hard ceiling rather than a default. If your machine has more threads than that you need to rebuild with a different value. MAX_FREQ_HZ is a similar compiled-in constant, 7125000000 by default.
Can CoreFreq overclock or tune my CPU?
Not yet. The Purpose section lists overclocking, memory controller and DIMM timings, power and energy with RAPL, P-State, HWP and TDP, the cpuidle and cpufreq drivers, ClockSource and Mitigation Mechanisms as in progress. What ships is measurement, not control, so the BIOS-like description describes the target rather than the current capability.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/cyring-corefreq)