NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/60968: NetBSD 10.1 amd64 does not initialise PAT on the secondary CPU on my machine, causing approximately 11× slower framebuffer writes on that core.



>Number:         60968
>Category:       kern
>Synopsis:       NetBSD 10.1 amd64 does not initialise PAT on the secondary CPU on my machine, causing approximately 11Ã? slower framebuffer writes on that core.
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Nov 06 05:40:01 +0000 2026
>Originator:     Nut
>Release:        NetBSD 10.1, GENERIC amd64
>Organization:
>Environment:
NetBSD  10.1 NetBSD 10.1 (GENERIC) #0: Mon Dec 16 13:08:11 UTC 2024  mkrepro%mkrepro.NetBSD.org@localhost:/usr/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
I noticed a large difference in frame buffer write performance depending on which CPU was running the code. My application receives pixel updates over the network and writes them directly to the framebuffer to display a remote desktop. 

While investigating slow rendering, I found that the same full-frame write took approximately 4.72 ms on CPU 0 but 51.79 ms on CPU 1. I repeated the test using the same source buffer, frame bufer mapping and write routine, restricting the benchmark to each CPU in turn. Writes to ordinary RAM took approximately 3.59 ms on either CPU, so the difference appeared specific to frame buffer access.

Using the same frame buffer mapping and write routine, a full-frame write took approximately 4.72 ms on CPU 0 and 51.79 ms on CPU 1. The equivalent ordinary RAM test took approximately 3.59 ms on either CPU.

Read-only per-CPU register captures showed different PAT values:

CPU 0: 0007010600070106
CPU 1: 0007040600070406

The frame buffer PTEs select PAT entry 1. This entry was WC on CPU 0 but WT on CPU 1. With the captured MTRR configuration, this made the frame buffer effectively WC on CPU 0 and UC on CPU 1.

Tracing the NetBSD 10.1 source showed that cpu_hatch() calls cpu_probe(ci) but does not call pat_init(ci). There is a pat_init(ci) call in cpu_attach(), but passing the secondary CPUâ??s structure does not make the function execute on that CPU; the MSR write still happens on the CPU executing the attachment code.

I added pat_init(ci) immediately after cpu_probe(ci) in cpu_hatch(), rebuilt GENERIC and booted the patched kernel. Both CPUs then reported the intended PAT value in two independent captures. MTRRs remained unchanged.

The unchanged frame buffer benchmark then measured approximately 4.72 ms on both CPUs. 
>How-To-Repeat:
On the affected machine (Apple iMac (20-inch, Mid 2007), Intel Core 2 Duo T7300 2.0 GHz, ATI Radeon HD 2400 XT), boot the NetBSD 10.1 GENERIC amd64 kernel.

Run a full-framebuffer write benchmark on each CPU separately, using schedctl to restrict the benchmark process to CPU 0 and then CPU 1. 

Keep the framebuffer mapping, source buffer, write routine and iteration counts unchanged. Run an ordinary RAM destination as a control.

Capture the PAT MSR independently on each CPU using a read-only diagnostic. CPU 1 retains 0007040600070406, while CPU 0 has 0007010600070106.
>Fix:
Adding the existing PAT initialisation call to the secondary CPUâ??s startup path fixed the problem on my machine.

In sys/arch/x86/x86/cpu.c, inside cpu_hatch():
 	cpu_init_msrs(ci, true);
 	cpu_probe(ci);
+	pat_init(ci);
 	cpu_speculation_init(ci);

After rebuilding and booting GENERIC with this change, both CPUs reported PAT 0007010600070106.

With 600 measured samples per CPU and destination, the median times were:
                    CPU 0        CPU 1
Framebuffer         4.716522 ms   4.716137 ms
Ordinary RAM        3.582788 ms   3.582649 ms




Home | Main Index | Thread Index | Old Index