Re: [PATCH v10 12/41] KVM: guest_memfd: Call arch make_shared callback for to-shared conversion
Ackerley Tng <[email protected]>
| Newsgroups | org.kernel.vger.linux-trace-kernel,dev.linux.lists.linux-coco,org.kernel.vger.kvm,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-kselftest,org.kvack.linux-mm |
|---|---|
| Message-ID | <CAEvNRgFNCDDSeuvbwj7pD_d18o1TBXo4TNR2dXHxpm18KPfR5A@mail.gmail.com> |
Sean Christopherson <[email protected]> writes: > On Thu, Aug 13, 2026, Ackerley Tng wrote: >> Sean Christopherson <[email protected]> writes: >> > That's why I think it's worth analyzing the cost: if it's in the >> > noise, leave it alone. If it's meaningful, figure out a not-too-gross way to skip >> > the entire thing if kvm_arch_gmem_make_shared() is a glorified nop in the end. >> >> Is noise defined relative to the entire conversion process? Would this >> benchmark look like >> >> 1. Convert 4G to shared on TDX with CONFIG_AMD_SEV defined >> 2. Convert 4G to shared on TDX without CONFIG_AMD_SEV defined >> >> and then compare the difference in time taken? > > That'd work, though I was envisioning something even simpler: use rdtsc() to > count the cycles it takes to iterate over various ranges of memory. Do whatever > is easiest for you though. I made some changes to add rdtsc() for the conversion process as Sean suggested [1], and exercised conversion like this [2]: 1. Initialize some memory as private 2. Get the guest to fault them into Secure EPTs 3. Converts the memory to shared <<== this is being benchmarked 4. Converts memory back to private I made it build the VM once and convert 5 times: ./gmem_benchmark_tdx_convert --iterations=5 --size=1g Here are the raw prints: [ 396.403818] guest_memfd to_shared: nr_pages=1, make_shared=930 cycles, total=39278 cycles [ 396.412087] guest_memfd to_shared: nr_pages=1, make_shared=252 cycles, total=28060 cycles [ 396.420379] guest_memfd to_shared: nr_pages=1, make_shared=176 cycles, total=26952 cycles [ 396.428643] guest_memfd to_shared: nr_pages=1, make_shared=176 cycles, total=27038 cycles [ 396.436921] guest_memfd to_shared: nr_pages=1, make_shared=176 cycles, total=26980 cycles [ 400.338157] guest_memfd to_shared: nr_pages=1, make_shared=1072 cycles, total=37236 cycles [ 400.346509] guest_memfd to_shared: nr_pages=1, make_shared=316 cycles, total=28338 cycles [ 400.354805] guest_memfd to_shared: nr_pages=1, make_shared=176 cycles, total=27182 cycles [ 400.363090] guest_memfd to_shared: nr_pages=1, make_shared=176 cycles, total=26972 cycles [ 400.371349] guest_memfd to_shared: nr_pages=1, make_shared=176 cycles, total=26886 cycles [ 448.761474] guest_memfd to_shared: nr_pages=262144, make_shared=15041018 cycles, total=6616067680 cycles [ 455.807988] guest_memfd to_shared: nr_pages=262144, make_shared=14937462 cycles, total=6608542680 cycles [ 462.848856] guest_memfd to_shared: nr_pages=262144, make_shared=15138858 cycles, total=6599494898 cycles [ 469.885694] guest_memfd to_shared: nr_pages=262144, make_shared=15721972 cycles, total=6610219850 cycles [ 476.928399] guest_memfd to_shared: nr_pages=262144, make_shared=15000406 cycles, total=6615114540 cycles [ 762.980690] guest_memfd to_shared: nr_pages=1048576, make_shared=61902982 cycles, total=26400884028 cycles [ 791.022885] guest_memfd to_shared: nr_pages=1048576, make_shared=61746114 cycles, total=26401170984 cycles [ 819.054580] guest_memfd to_shared: nr_pages=1048576, make_shared=61096794 cycles, total=26404409058 cycles [ 847.120994] guest_memfd to_shared: nr_pages=1048576, make_shared=61446290 cycles, total=26447461896 cycles [ 875.219750] guest_memfd to_shared: nr_pages=1048576, make_shared=61774646 cycles, total=26444608360 cycles And here's the above, tabulated: nr_pages make_shared total percentage ---------- --------------- --------------- ------------ 1 930 39278 2.3677% 1 252 28060 0.8981% 1 176 26952 0.6530% 1 176 27038 0.6509% 1 176 26980 0.6523% 1 1072 37236 2.8789% 1 316 28338 1.1151% 1 176 27182 0.6475% 1 176 26972 0.6525% 1 176 26886 0.6546% 262144 15041018 6616067680 0.2273% 262144 14937462 6608542680 0.2260% 262144 15138858 6599494898 0.2294% 262144 15721972 6610219850 0.2378% 262144 15000406 6615114540 0.2268% 1048576 61902982 26400884028 0.2345% 1048576 61746114 26401170984 0.2339% 1048576 61096794 26404409058 0.2314% 1048576 61446290 26447461896 0.2323% 1048576 61774646 26444608360 0.2336% Looks to me it is within noise. I also actually tried measuring the conversion time from userspace with CONFIG_AMD_SEV enabled and disabled. Converting a 1G-sized TD was faster by 0.2%, which is in line with the above table. Interestingly, when converting a 4G-sized TD, skipping kvm_gmem_make_shared() was _slower_ over 2 runs. I don't have an explanation for that. I think the code was correct. (If it makes a difference, I skipped kvm_gmem_make_shared() using a custom guest_memfd creation time flag and skipped make_shared if the flag was set on the inode.) I thought adding a kvm_arch_has_gmem_make_shared(), defaulting it to false for all archs and having x86 override with !!kvm_x86_ops.gmem_make_shared is not too bad either: + doesn't leak anything, since the function being called is kvm_arch_gmem_make_shared and the accompanying function is kvm_arch_has_gmem_make_shared. Or maybe just a little, since all the other ops don't have the accompanying _has_ function + it's a kernel-internal thing + not too many lines of code, not too complex Sean, let me know if you prefer to add kvm_arch_has_gmem_make_shared() and for my learning, what your considerations are regarding adding kvm_arch_has_gmem_make_shared() or not. [1] https://github.com/googleprodkernel/linux-cc/commit/3295072cfeb8920e48d9e80c98fd1695d4bbad99 [2] https://github.com/googleprodkernel/linux-cc/commit/a644618f270f02c832fb7e8402fcae98bc91f4e5