Repository navigation
drm/asahi: GEM_RESIDENCY, keep an object's memory resident - #1610
Conversation
On G17, reclaim may release the backing of VM-private objects of idle VMs, which the VM's next job then waits to get back. A client that would rather not pay that for some of its objects (a server holding model weights between requests, Vulkan's memory priority 1.0) had no way to say which. DRM_IOCTL_ASAHI_GEM_RESIDENCY sets or clears a per-object keep flag, reported by DRM_ASAHI_FEATURE_GEM_RESIDENCY (bit 35) on G17. The flag is a priority among the objects that reclaim may release, and no more: - Which reclaim releases GPU memory does not change. The VM shrinkers are not memcg-aware, so only reclaim on behalf of the whole system calls them (kswapd, direct reclaim, a request to the root memory cgroup, drop_caches). Reclaim inside a memory cgroup below the root releases no GPU memory, kept or not. - Which VMs it takes from does not change: an idle one, with no job, binding change or other use in progress or in the last two seconds, and past the backoff that follows a restoration. The memory of a VM in use stays, kept or not. - Within such a VM, kept objects are released after the others, and only when those left the scan target unmet. - Contents advised DONTNEED are purged as before, kept or not. The request is therefore a hint. Userspace cannot rely on a kept object being resident, and a client that stays active, or whose memory cgroup is the one running out of memory, keeps its GPU memory whether it asks or not. A user VM now has two shrinkers. The existing one purges advised contents and releases the idle objects that are not kept, as before. The new one counts the kept objects and has a batch no scan target can reach, so the shrinker core calls its scan only when the target reaches everything it counted: at the last two of the thirteen reclaim priorities, or the last three once scans deferred by earlier passes have built up. Its scan releases what the first shrinker's does and then, only if that did not reach the target, the kept objects. It is registered after the first, so a reclaim pass that reaches it has asked the VM's first shrinker before. Reclaim comes to those priorities when the earlier ones did not free what it was asked for: under memory pressure that nothing else relieves, for a request that names more than the system has to spare, and at once with drop_caches. Kept objects are not a second pass of the first shrinker's scan because the shrinker core hides the reclaim priority from a scan: counted there, they would be released at any priority whenever a VM had nothing else to give, and left uncounted, a VM with only kept objects would never be scanned at all. The flag is changed under the object's reservation, which idle reclaim holds for the VM it walks, so a request takes effect for every reclaim pass that starts after the ioctl returns; backing already released comes back with the next job, as before. Shared, imported and user-memory objects are never released and accept the flag without effect on them. Kept objects count against the memory limits as before. Their sizes are also totalled for the device (user_kept in the gpu_memory sysfs file) until the object is freed. Tested: KUnit in QEMU (arm64, 16K pages), 546 tests, 544 passed, 2 skipped (unrelated configuration); the new asahi_memacct test kept_bytes_follow_the_object checks that the kept total changes only on a change of state, is left as it is by a transfer to another client, is cleared by a free and ignores kernel objects and imports. KUnit does not reach the shrinkers: what reclaim does with kept objects is covered by the selftest that follows, which passes on the J716c (M5 Max MacBook Pro), the case that runs every shrinker at the last priority included. There, with a Vulkan driver that maps memory priority 1.0 to this ioctl, the memory priority and pageable allocation cases of the Vulkan CTS give 430 passed of 430. Developed with Claude Code. Signed-off-by: Erik Bourget <erik@ebourget.net>
A kselftest harness program for the render node that exercises
DRM_IOCTL_ASAHI_GEM_RESIDENCY without submitting GPU work:
- a VM-private object: a keep request moves user_kept (gpu_memory
sysfs file) by the object's size, once for a repeated request, a
clear request moves it back, and freeing a kept object stops
counting it;
- unknown flags fail with EINVAL and an unknown handle with ENOENT,
and neither changes user_kept;
- a shared object takes the flag and is counted the same way;
- light_reclaim_spares_kept_objects: of two idle bound objects,
reclaim releases the one that is not kept first, never the kept one
while the other is resident; the kept one stays through 16 further
reclaim requests; once its request is withdrawn it is released too;
- kept_objects_stay_purgeable: a kept object advised DONTNEED is
purged by reclaim;
- requests_serialize_with_reclaim: while a thread sets and clears the
request on one object as fast as it can and reclaim runs, an object
beside it that is not kept is released, which shows that reclaim got
to the VM during the race, a kept object beside it is not, the state
a request that has returned found is the one reclaim leaves, and
user_kept counts each object once;
- kept_objects_go_under_urgent_pressure: when every shrinker is run at
the last reclaim priority, a kept object is released as well,
without being purged.
The four cases that make the kernel reclaim act on the whole system.
They need root and run only when asked for in the environment:
ASAHI_RESIDENCY_RECLAIM=1 for the three that write to memory.reclaim
of the root memory cgroup, ASAHI_RESIDENCY_DROP_CACHES=1 for the last
one, which writes 2 to /proc/sys/vm/drop_caches.
A memory.reclaim request names an amount, not a priority: the kernel
works down its reclaim priorities until it has reclaimed that much,
and where nothing else can be reclaimed it ends at the last ones, at
which kept objects go like everything else. The three cases therefore
bring the memory to reclaim: a sparse temporary file of 2 GiB in the
working directory, read once into the page cache, from which requests
of 4 MiB are usually met within the first priorities. The objects have
2^19 pages (8 GiB with 16K pages), the least a VM must have for the
lightest priority to scan its shrinker. The cases skip without four
times the objects' size of available memory, in a working directory on
tmpfs and in a memory cgroup with memory.min or memory.low protection.
When a kept object was released, a case has to tell whether reclaim
had leave to release it. It does so in one of two ways, and says which:
- From the record of the shrinker passes, where it can have one: the
events vmscan:mm_shrink_slab_start and mm_shrink_slab_end in a trace
instance (tracefs at /sys/kernel/tracing). The shrinker core calls a
VM's shrinker of kept objects only in a pass whose target reaches
everything that shrinker counted, and the start event shows both
numbers. The events name a shrinker by its pointer, so a case knows
its own VM's shrinker by what it counts, the pages of the VM's idle
kept objects: each case adds a random 0 to 1023 pages to its kept
object, and takes for its VM's shrinker the one that never counted
anything else. Leave to release the object is a pass that called that
shrinker before the case first saw the object gone and had not ended
when the case last saw it resident; a pass ends with the end event
of the same shrinker from the same task. With such a pass the case
is skipped ("as it may"), with their number and priority; without
one it fails, whatever passes other VMs' shrinkers or other times
had. If more than one shrinker in the record counts what the test's
VM counts and a pass called one of them, the case is skipped as
"inconclusive", which claims nothing about the release. The record
is used when no event was lost and it shows the driver's other
shrinker at work, which it knows by the names of the scan functions.
- Otherwise from signs of the environment, a heuristic: whether the
kernel met every request, whether 512 MiB of the file were still
cached after each, and whether kswapd or direct reclaim scanned pages
meanwhile. A kept object released with one of these signs skips the
case, with the sign and the word that it is a heuristic; without one
the case fails. The signs do not show which priorities reclaim
reached: reclaim that comes to the last ones without leaving a sign
fails a case that the record would skip.
kept_objects_go_under_urgent_pressure also requires, where it has the
record, a pass that called its VM's shrinker of kept objects before
the object went.
The trace instance belongs to the program: main() makes it before the
cases fork, named asahi-residency-<pid>, and removes it when the
program exits or is ended by a signal, so a case that fails, times out
or is killed leaves nothing behind. The signals that end the program
wait while the instance is set up or removed, and the handler makes
only async-signal-safe calls, on paths made beforehand. An instance of
that name that exists already is left alone, and the cases then go by
the heuristic.
The result of every series of reclaim requests is checked for an error
(a failed request, or a client total that could not be read) before it
is taken for a released object.
The program is listed in the selftests' TARGETS. It skips where
renderD128 is not this driver's node or lacks the feature.
Tested on the J716c (M5 Max MacBook Pro), built there with gcc against
this tree's UAPI header:
- unprivileged, without the two variables: pass 3, skip 4;
- as root with both variables: pass 7. The object that is not kept
went with the first request and the kept one stayed through 16 more;
the object no longer kept and the advised one went with the next
request each. In the race, 11 million residency requests ran while
reclaim released the control object, with its 11th request, and the
toggled one; the kept object stayed, also through 16 further
requests. At least 1995 MiB of the cold cache's 2048 were left. The
record had one shrinker with the count of the test's VM in each case:
51 and 70 passes over it in these two cases, none of which called
it, and in the urgent case one that did, at priority 0;
- as root with ASAHI_RESIDENCY_RECLAIM=1, right afterwards and once
more later: pass 6, skip 1, with similar figures;
- as root with ASAHI_RESIDENCY_RECLAIM=1 and tracefs hidden from the
program (a private mount over /sys/kernel/tracing): pass 6, skip 1,
by the heuristic;
- five changed copies of the program, light_reclaim_spares_kept_objects
only. One that never asks to keep the object fails, with the record
and without. One that runs every shrinker at the last priority
between the case's two phases is skipped with "as it may: ... 1,
down to priority 0 (traced)". One that does not keep the object while
such a pass calls another client's shrinker of kept objects fails
(no shrinker with the count of the test's VM), and so does one in
which such a pass called a shrinker with that count and ended before
the case first looked. One with a second client whose kept object
has the same size is skipped with "inconclusive: 2 shrinkers ...".
Without the record all five fail;
- a case killed with its process group while it records, the program
ended by SIGTERM, and an instance of its name made beforehand: the
program removes its instance in the first two and leaves the foreign
one alone, with the case passing by the heuristic. Sent SIGTERM at a
random moment of its first 0.3 s, 30 times, it left no instance.
Developed with Claude Code.
Signed-off-by: Erik Bourget <erik@ebourget.net>
DjDeveloperr
left a comment
There was a problem hiding this comment.
Reviewed at cb8258c, and run on an M5 Pro (J714s, T6050, G17S) with the same test kernel as #1609: integration/aurora 69a9fbb + d76f650 + 86708ce + #1608..#1611.
Verdict: approve.
No change without the ioctl. I checked this by reading, because the shrinker change reaches every G17 GPU, the T8140 included. With no object kept:
idle_reclaim_count(false)counts exactly what it counted before: advised objects, plus idle objects whosekeep_resident()is false.reclaim_idle_pages(target, false)runs only its first pass, with the old body.- The new kept shrinker's
count_keptreturns 0, sodo_shrink_slab()returns before any scan.
Other checks:
- The
KEPT_BATCH = LONG_MAXreasoning matchesdo_shrink_slab(): the loop runs only whentotal_scan >= freeable, so priorities 1 and 0 (and 2 oncenr_deferredreaches its cap of 2x the count). - Registration order (kept second) is right, and Drop frees
keptbeforeraw. - The flag is set under the object's resv, which is the VM's resv for every reclaimable (VM-private) object, so a reclaim walk cannot see a half-applied change.
- The sysfs layout change (
user_kept, size 56) is asserted on both the Rust and the C side.
Non-blocking suggestions:
- Per-VM cost. Every user VM now gets a second registered shrinker. Every system-wide reclaim pass also runs a second
countwalk over all of the VM's private BOs (two try-locks and a resv read per BO), even for VMs that never asked to keep anything. That is most of them. On an 8 GB T8140, kswapd runs often. A per-VM count of kept objects, kept up to date inset_keep_resident(), would letcount_keptreturn 0 without the walk. Registering the second shrinker lazily, on the first keep request, would avoid the extra one entirely. - What
user_keptcounts. It includes user-memory (#1609) and shared objects that are flagged but can never be released. The sysfs comment says "whether their memory is held at the moment or not", which covers it, but a sentence saying that it counts requests, not reclaimable bytes, would help readers.
On the M5 Pro (J714s):
- Selftest
asahi-residency, unprivileged: 3 pass, 4 skip (each reclaim case names its variable). - As root with
ASAHI_RESIDENCY_RECLAIM=1 ASAHI_RESIDENCY_DROP_CACHES=1: 5 pass, 2 skip.kept_objects_stay_purgeablepasses: purged after 1 request.kept_objects_go_under_urgent_pressurepasses.light_reclaim_spares_kept_objectsandrequests_serialize_with_reclaimskip with "not enough available memory for the test objects". Their two and three 8 GiB objects need about 68 and 100 GiB available (4x the objects plus 4 GiB), and this 64 GB machine had 61.6 GiB, so the case that shows kept objects surviving light reclaim couldn't run here. Smaller objects (or sizes taken from MemAvailable) would let both run on 64 GB machines.- No trace instance was left, and
user_keptread 0 before and after.
- Vulkan side, mesa #243 (on aurora-wip be147e36250b, built on the device): 426/426 pass, no GPU fault:
dEQP-VK.memory.binding.priority*112/112;dEQP-VK.memory.binding.maintenance6.priority*112/112;dEQP-VK.memory.pageable_allocation.*202/202.
- Ordinary GPU work on the same boot, with the second shrinker registered per VM: multi-queue timeline 214/214, synchronization2 600 pass / 421 not supported, gpubench 41/41, 0 recoveries.
Build shortcut, for the record: the M5 test kernel was built incrementally with include/linux/dma-mapping.h and include/drm/drm_gem_shmem_helper.h at their old mtimes, so files that only include them weren't recompiled. The hunks are a file-scope #define plus comment, and a same-type, same-position field rename; this head has no green CI compile to stand in for a clean build (below).
CI: no check has run on this head. Its base j716c/gpu-gem-userptr isn't a host-tests target, and sep-source's paths don't include drivers/gpu/drm/asahi, so there is no CI compile of this PR yet. A run against integration/aurora once #1609 lands (or a manual dispatch) would give one.
DjDeveloperr
left a comment
There was a problem hiding this comment.
Current readiness/CI inspection on @DjDeveloperr’s behalf.
#1609 is merged and this PR already targets integration/aurora. This exact head still has no workflow runs. Its10 changed files are Asahi driver, UAPI and selftest paths; the current SEP source-check filter does not include those paths, and its rust-build job compiles apple-sep.o. A lifecycle re-trigger or a green SEP-only job alone would not establish a current Asahi-driver compile.
The author’s per-commit J716c build, QEMU and full7/7 hardware reclaim results in the description are separate reported evidence; the earlier J714s review used an incremental kernel and skipped the two oversized reclaim cases. Those scopes are retained rather than relabelled as clean current-merge CI. Actual validation of the final composed Asahi source/host tests remains needed before treating this as ready to merge.
No blind re-run, close/reopen, source churn or reclaim/drop_caches test was performed on the working host. Source approval is not being replaced by a fabricated check result; the missing coverage needs an appropriate build/CI route or exact clean final-composition proof.
|
Merging this at Evidence
Independent review: no blocker. Non-blocking follow-ups for @erikwb, none needed for this merge:
For the merge order: #1752 adds |
Brings in #1610 (GEM_RESIDENCY). It adds DRM_ASAHI_FEATURE_GEM_RESIDENCY (bit 35) at the place in include/uapi/drm/asahi_drm.h where this branch adds DRM_ASAHI_FEATURE_COMPUTE_TIMEOUT (bit 36). Both are kept, in bit order. No other change. Signed-off-by: Diljit Singh <hey@djdev.me>
The problem
On G17, reclaim may release the backing of the VM-private objects of an idle
VM. The VM's next job then waits until the memory is back. A client that
would rather not pay that wait for some of its objects (a server that holds
model weights between requests, an application that gives its memory Vulkan
priority 1.0) had no way to say which: when reclaim took idle memory of its
VM, any object could be the one to go.
The change
drm/asahi: GEM_RESIDENCY, keep an object's memory residentaddsDRM_IOCTL_ASAHI_GEM_RESIDENCY, which sets or clears a per-object keep flagon G17 GPUs. The flag is a priority among the objects that reclaim may
release, which is what its Vulkan use (a memory priority, a hint) needs, and
no more than that:
shrinkers are not memcg-aware, so only reclaim on behalf of the whole
system calls them: kswapd, direct reclaim, a request to the root memory
cgroup,
drop_caches. Reclaim inside a memory cgroup below the root (acgroup at its limit, a
memory.reclaimrequest to it) releases no GPUmemory, kept or not.
binding change or other use in progress or in the last two seconds, and
past the backoff that follows a restoration (16 times what the restoration
took, between 1 and 30 seconds). The memory of a VM in use stays, kept or
not.
when those left the scan target unmet.
DRM_ASAHI_GEM_MADV_DONTNEEDare purged as before, kept ornot.
being resident, and a client that stays active, or whose memory cgroup is
the one running out of memory, keeps its GPU memory whether it asks or not.
holds for the VM it walks, so a request applies to every reclaim pass that
starts after the ioctl returns. Backing that was already released comes
back with the VM's next job, as before.
flag without effect on them. Kernel objects are refused.
of their sizes is reported as
user_keptin the GPU'sgpu_memorysysfsfile.
How the order is kept: a user VM gets a second shrinker for its kept objects.
Its batch is larger than any scan target, so the shrinker core calls its scan
only when the target reaches everything the shrinker counted. With the
driver's
seeksthat is the last two of the thirteen reclaim priorities, orthe last three once scans deferred by earlier passes have built up. That scan
releases what the VM's first shrinker would and only then, if the target is
not met, the kept objects; and the second shrinker is registered after the
first, so a reclaim pass that reaches it has asked the first one before. The
first shrinker (purge, and release of objects that are not kept) is
unchanged. Reclaim comes to those priorities when the earlier ones did not
free what it was asked for: under memory pressure that nothing else relieves,
for a request that names more than the system has to spare (a
memory.reclaimrequest to the root cgroup when there is little page cacheto take), and at once with
drop_caches. A second pass inside the existingscan was not enough: a scan is not told the reclaim priority, so kept objects
counted there would go at any priority whenever a VM had nothing else to
give, and left uncounted, a VM with only kept objects would never be scanned.
selftests: drm/asahi: GEM_RESIDENCYadds a kselftest program for the rendernode (
tools/testing/selftests/drivers/gpu/asahi-residency, listed in theselftests'
TARGETS). Besides the accounting it exercises reclaim. Thosecases act on the whole system, need root and run only when asked for in the
environment:
ASAHI_RESIDENCY_RECLAIM=1runslight_reclaim_spares_kept_objects,kept_objects_stay_purgeableandrequests_serialize_with_reclaim, whichwrite to
memory.reclaimof the root memory cgroup.ASAHI_RESIDENCY_DROP_CACHES=1runskept_objects_go_under_urgent_pressure, which writes 2 to/proc/sys/vm/drop_caches: every shrinker of the system at the lastpriority.
A
memory.reclaimrequest names an amount, not a priority: the kernel worksdown its reclaim priorities until it has reclaimed that much, and where
nothing else can be reclaimed it ends at the last ones, at which kept objects
go like everything else. The three cases therefore bring the memory to
reclaim themselves, a sparse temporary file of 2 GiB in the working
directory that is read once into the page cache, and ask for 4 MiB at a
time, which the kernel usually finds there within the first priorities. The
race case has a control object that is not kept and must be released while
the requests race, which shows that reclaim got to the VM. The cases skip
without four times their objects' size of available memory (objects of
8 GiB), in a working directory on tmpfs, and in a memory cgroup with
memory.minormemory.lowprotection.When a kept object was released, a case has to tell whether reclaim had
leave to release it. It does that in one of two ways, and its output says
which:
vmscan:mm_shrink_slab_startandvmscan:mm_shrink_slab_endin a traceinstance (tracefs at
/sys/kernel/tracing, kernel symbols). The shrinkercore calls a VM's shrinker of kept objects only in a pass whose target
reaches everything that shrinker counted, and the start event carries both
numbers.
nothing of the VM. A case knows its own VM's shrinker by what it counts,
the pages of the VM's idle kept objects: it adds a random 0 to 1023 pages
to the size of its kept object and takes for its VM's shrinker the one
that never counted anything else. Passes over other VMs' shrinkers of
kept objects do not enter into the verdict.
before the case first saw the object gone and that had not ended when
the case last saw it resident. A pass has ended with the
mm_shrink_slab_endevent of the same shrinker from the same task. Thetrace instance runs on the monotonic clock, which the case reads before
and after each look at what its client holds.
the number and priority of those passes. Without one it fails. If more
than one shrinker in the record counts what the test's VM counts and a
pass called one of them, the record cannot tell whose pass it was: the
case is skipped with "inconclusive", which claims nothing about the
release.
other shrinker at work; the driver's shrinkers are told by the names of
their scan functions.
kernel met every request, whether 512 MiB of the file were still cached
after each, and whether kswapd or direct reclaim scanned pages meanwhile.
A kept object released with one of these signs skips the case, with the
sign and the remark that it is a heuristic; without one the case fails.
The signs make it likely, and do not show, that reclaim stayed at its
first priorities: reclaim that goes to the last ones while every request
is met and the cache stays fails a case that the record would skip, and
unrelated reclaim in the system turns a failure into a skip.
kept_objects_go_under_urgent_pressurealso requires, where it has therecord, a pass that called its VM's shrinker of kept objects before the
object went. Every series of reclaim requests is checked for an error (a
failed request, a client total that could not be read) before its result is
taken for a released object.
The trace instance belongs to the program, not to a case:
main()makes itbefore the cases fork, as
asahi-residency-<pid>and only when a reclaimcase was asked for, and removes it when the program exits or is ended by
SIGINT, SIGTERM, SIGHUP or SIGQUIT. Those signals wait while the instance is
set up or removed, and the handler makes only async-signal-safe calls, on
paths made beforehand. A case only empties the buffer and switches the two
events on and off, so a case that fails, times out or is killed leaves
nothing behind. An instance of that name that exists already is
somebody else's: it is left as it is and the cases go by the heuristic.
UAPI additions: ioctl
DRM_ASAHI_GEM_RESIDENCY(id 13),struct drm_asahi_gem_residency, the flagDRM_ASAHI_GEM_RESIDENCY_KEEPandthe feature
DRM_ASAHI_FEATURE_GEM_RESIDENCY, bit 35.Testing
Hardware: M5 Max MacBook Pro (J716c).
integration/auroraea10c4d plus dma-mapping: add DMA_ATTR_NO_BOUNCE #1608and drm/asahi: GEM_USERPTR, buffer objects over the caller's memory #1609 plus this branch, with the J716c
configuration, at each commit. No new warning: the build has the same 31
Rust warnings at each commit, none in code the branch adds.
./tools/testing/kunit/kunit.py run --arch=arm64 --kunitconfig=drivers/soc/apple/sep.kunitconfig:Ran 546 tests: passed: 544, skipped: 2, with the newasahi_memaccttestkept_bytes_follow_the_object. KUnit does not reach the shrinkers.python3 -I tools/asahi/run-host-tests.py:219/224 passed. The five that fail (apple-dcp,g15-pb-growth-testsand
g15-stats-drain-tests, each of the last two also with--mutations)fail identically on
integration/auroraea10c4d on the build host,which lacks the Rust 1.93.1 toolchain the g15 tests ask for.
scripts/checkpatch.pl: 0 errors and 0 warnings on the driver commit; theselftest commit gets only the MAINTAINERS note for its new files.
integration/auroraea10c4d plus the two open J716c device tree pull requests and the
kernel branches of this set, with the kernel code of this branch and of
the branches below it as it is here: the selftest of this branch built
there with gcc 16.1.1 against this branch's UAPI header:
unprivileged, without the two variables:
# Totals: pass:3 fail:0 xfail:0 xpass:0 skip:4 error:0(
kept_size_is_counted_once,bad_arguments,shared_objects_take_the_flag; each reclaim case says which variable ismissing);
as root with both variables:
# Totals: pass:7 fail:0 xfail:0 xpass:0 skip:0 error:0. With two boundobjects of 8 GiB, one of them kept, the first reclaim request released
the one that was not kept and 16 more left the kept one resident
(
light_reclaim_spares_kept_objects); once the request was withdrawn,the next reclaim request released it. A kept object advised DONTNEED was
purged by the first request (
kept_objects_stay_purgeable). While athread set and cleared the request on one object 11.3 million times,
reclaim released the control object with its 11th request and the
toggled object, a kept object beside them stayed resident, also through
16 further requests, and
user_keptcame back to its starting value(
requests_serialize_with_reclaim). The cold cache had 1995 to 2023 MiBof its 2048 left after each case. These cases had the record of the
shrinker passes, with one shrinker that counted what the test's VM
counts: "reclaim passes over the shrinker of this VM's kept objects: 51,
of which 0 called it (traced, 1 such shrinker)", and 70 with 0 in the
race.
kept_objects_go_under_urgent_pressurereleased the kept objectas well (the client held nothing afterwards), its contents were
retained,
user_keptstill counted it, and the record showed the pass:"reclaim passes that called the shrinker of this VM's kept objects
before it went: 1, down to priority 0 (traced)";
as root with
ASAHI_RESIDENCY_RECLAIM=1, right after that run and oncemore later:
# Totals: pass:6 fail:0 xfail:0 xpass:0 skip:1 error:0both times, with 51 and 77, then 51 and 74, passes over the VM's
shrinker of kept objects and again none that called it;
the same with the shrinker calls also traced from outside the program
(
vmscan:mm_shrink_slab_startin a second trace instance): of 6972calls, 5114 were at priority 11 and 1858 at priority 12; the driver's
first shrinker was called 179 times and its shrinkers of kept objects
considered 125 times, never with a target that reached the count. The
program's own record in that run had 51 and 74 passes over its VM's
shrinker of kept objects, the same 125, and none that called it;
as root with
ASAHI_RESIDENCY_RECLAIM=1and tracefs hidden from theprogram (a private mount over
/sys/kernel/tracing):# Totals: pass:6 fail:0 xfail:0 xpass:0 skip:1 error:0, each reclaimcase noting "the shrinker passes were not traced";
five changed copies of the program, to see
light_reclaim_spares_kept_objectsfail, skip and call a run inconclusive, each with the record and with
tracefs hidden:
Expected (long long)kept_size (8609349632) == resident (0); the size differs fromrun to run by the random pages), with the record ("no
reclaim pass called the shrinker of this VM's kept objects before it
went (traced: 0 shrinkers of kept objects count what this VM's
counts, ...)") and without it;
drop_cachesbetween the two phases of the case,so that reclaim does come to the kept object, is skipped with "the kept
object went after 1 requests, as it may: reclaim passes that called
the shrinker of this VM's kept objects before it went: 1, down to
priority 0 (traced)"; without the record it fails, since the
heuristic has no sign for such a pass;
kept object and every shrinker is run at the last priority: a pass
calls the other client's shrinker of kept objects and the test's own
object goes with ordinary reclaim. It fails ("0 shrinkers of kept
objects count what this VM's counts"): another VM's pass is no leave;
and ends before the case first looks, after which the object is not
kept. It fails ("1 shrinkers of kept objects count what this VM's
counts, with 1 passes and 1 calls at other times"): a pass that ended
before the object was last seen resident is no leave;
drop_cachesbetween the phases, is skipped with "inconclusive: 2shrinkers of kept objects count what this VM's counts, and 2 passes
called one of them before it went (traced)".
Without the record all five fail.
the trace instance: with a case killed together with its process group
while it recorded (what the harness does at a timeout), the program
reported the case as failed and removed its instance; ended by SIGTERM
while a case recorded, it removed its instance (exit status 143); started
with an instance of its own name made beforehand, with an event enabled
in it, it left that instance as it was and the case passed with "the
shrinker passes were not traced". Sent SIGTERM at a random moment of its
first 0.3 s, 30 times (each run in a PID namespace of its own, so that
nothing of it outlived the run), it ended with status 143 and left no
instance each time. After every run above
/sys/kernel/tracing/instanceshad noasahi-residency-*left.aurora-wipplusthe honeykrisp change that maps memory priority 1.0 to this ioctl
(VK_EXT_memory_priority, VK_EXT_pageable_device_local_memory):
dEQP-VK.memory.binding.priority*,dEQP-VK.memory.binding.maintenance6.priority*,dEQP-VK.memory.pageable_allocation.*and the two extensions' featurecases under
dEQP-VK.api: 430 passed, 0 failed, 0 not supported.user_keptreads 0 again after the run.Depends on
#1609 (which is stacked on #1608):
the driver's ioctl table has no gaps, so the two new ioctls need an order,
and GEM_USERPTR takes id 12. The code of this branch does not otherwise use
it. The Vulkan side is a separate pull request against aurora-silicon/mesa.
Not covered
the root or for a VM that is in use: GPU memory is not released there with
or without it. Making the shrinkers memcg-aware is not part of this.
own accord (kswapd or direct reclaim close to failing allocations) was not
produced: the last priority was reached with
drop_cachesonly.cache, 8.4 GiB at the least. A machine with none, where the requests can
only be met from the cases' own file, was not tried.
particular by a random 0 to 1023 pages. A shrinker of another VM that
counts exactly the same, and only that, while the test's own never shows
in the record, would be taken for the test's; with both in the record the
case says "inconclusive". The record tells the driver's shrinkers by the
symbol names of their scan functions; where those are not in the trace (no
kernel symbols), the cases fall back to the heuristic.
killed with SIGKILL. A later run does not take it over; it has to be
removed by hand (
rmdir /sys/kernel/tracing/instances/asahi-residency-<pid>).VM still has idle objects that are not kept, if that VM is in use at the
moment or its shrinker comes later in the same pass.
with
EOPNOTSUPP.🤖 Generated with Claude Code