|
|
Log in / Subscribe / Register

Better support for locally-attached-memory tiering

We're bad at marketing

We can admit it, marketing is not our strong suit. Our strength is writing the kind of articles that developers, administrators, and free-software supporters depend on to know what is going on in the Linux world. Please subscribe today to help us keep doing that, and so we don’t have to get good at marketing.

By Jonathan Corbet
May 20, 2024

LSFMM+BPF
The term "memory tiering" refers to the management of memory placement on systems with multiple types of memory, each of which has its own performance characteristics. On such systems, poor placement can lead to significantly worse performance. A memory-management-track discussion at the 2024 Linux Storage, Filesystem, Memory Management, and BPF Summit took yet another look at tiering challenges with a focus on upcoming technologies that may simplify (or complicate) the picture.

A quick note: this session mentioned future plans from a number of different companies, and some participants were worried about revealing too much or breaking non-disclosure agreements. For this reason, it was requested that this session be reported without naming the people involved or attributing any statements. Apologies for the forthcoming vagueness, but hopefully the important parts get through.

The specific focus of this session was obtaining optimized placement on systems with CXL memory attached. This memory is large and flexible in its use (it can, for example, be moved from one server to another in some configurations) but, since it is more distantly attached, it is also slower. If, though, the system can learn to use this memory properly and place the right data there, there is a huge potential for both performance improvements and cost savings. Preferably, this would happen without the need for new, specialized interfaces. The kernel's tiering support should be useful for all systems, and it should be extensible, since memory types will change in the future. The hope for the discussion was to reveal any constraints in the memory-management subsystem that would impede this support and to bring the developers working in this area together.

The trouble with NUMA balancing

The current approach to tiering is based on NUMA balancing — different types of memory appear to be different (CPU-less) NUMA nodes, and the kernel manages the placement of memory on each node. The advantage is that the kernel's NUMA-balancing code is ten years old at this point, and is relatively mature. Tiering support has been added more recently, with a special mode that attempts to optimize memory placement.

The use of NUMA balancing for tiering is not ideal, though; it is too slow in a number of ways. Perhaps the biggest problem is page promotion. It is relatively easy for the kernel to notice data that is not seeing frequent use and demote it to slower memory. The promotion path — observing frequent use of data on slow memory and moving it to a faster tier — is harder. Promotion needs to be fast; once a process starts using some data, it tends to work on it for a while; if that data is not promoted immediately, performance will suffer.

NUMA balancing uses a sliding-window technique, where memory is access-protected and the resulting faults (on the pages that are actually accessed) are noted. This algorithm takes time and is not responsive enough for the promotion case; performance will decay while pages are waiting to be promoted. NUMA balancing is also a system-wide task, but it really needs to be job-wide, and should eventually be controlled with memory control groups. An additional challenge in making all of this work is a lack of good benchmarks to measure the effectiveness of tiering algorithms.

It was pointed out that one type of memory — that which is hosted on peripheral devices like GPUs — is special in its own way. Unmapping that memory (prior to migrating it and mapping it in its new location) can stop the device in its tracks and kill performance, so automatic tiering has to be disabled on such systems. The lack of device awareness in the kernel's tiering mechanisms needs to be fixed.

One possible approach that was suggested was to focus on DAMON (which was discussed earlier that day) as a flexible way to implement tiering algorithms. On the other hand, DAMON also feels a bit like a separate memory-management subsystem, and it could be better to keep this support in the core.

An upcoming change that should help with this task is that, in the future, CXL controllers will allow the kernel to easily observe which pages are being accessed. That will be a fast source of truth, under the kernel's control. But it is not clear how that information can be used. It seems that either NUMA balancing or DAMON could be extended to take advantage of CXL hot-page detection. One developer said that hot-page detection looks like many hardware-assistance features that promise to help, but where the hardware developers always get it wrong and the problem still has to be solved in software.

NUMA balancing was designed to converge on an optimal solution for a given workload and not move a lot of data around. That makes it hard to extend to this case, where active migration of data is needed. Trying to create a complex policy that will work for all workloads is impossible, developers said, so it will be necessary to make NUMA balancing more extensible — or to use a different mechanism entirely. It is important, one developer suggested, to avoid conflating the mechanism for detecting hotness for the one that moves pages; the two need to be firmly decoupled.

Possible solutions

Various ideas flew around the room. A 2023 session had looked at the use of hardware performance counters for page aging; perhaps that work could be extended here. It seems, though, that not all CPUs have performance-management units that provide the information that is needed. The multi-generational LRU already contains several tiers internally that could be used to manage tiering, but one developer said that experiments with LRU-based hot-page detection did not work out as well as had been hoped. It was also said that "hot-page detection" should really be "hot-folio detection", and that scanning should work better in general for larger folios.

One component of NUMA balancing is often called "workload follows memory"; if a task finds itself running far from its memory, it can be migrated to a closer node. That doesn't work for CXL, though, since CXL nodes have no CPU, so tasks cannot be migrated there. It was suggested that task migration should be disabled in general, that balancing workloads across CPUs is no longer relevant in our world. Task migration can throw NUMA systems out of balance, forcing the migration of memory to follow tasks around. Migration can also split communicating tasks apart from each other. Often, it was said, it is better to just leave the system alone.

This was, of course, a room full of memory-management developers; had there been CPU-scheduler developers present, that assertion would likely have been challenged. Even in this crowd, one developer disagreed, saying that the problem isn't task migration; instead, the CPU scheduler just isn't being given enough information to make the best decisions.

There is, it seems, a need for some sort of "hot-memory abstraction" for the kernel. It could take advantage of "accessed" bits in the page tables, performance-monitoring units, the upcoming CXL hot-page detection feature, or any "future hardware innovation" that might be in the works. Whatever information is available should be brought in and provided in a single interface. It could be useful for more than tiering; NUMA balancing would also benefit from better information. One possible problem is that, while tiering does not normally need to know which CPU is accessing data, NUMA balancing depends heavily on that information.

Toward the end of the session, mechanisms for acting on this information were discussed. One possibility is to push as much of it to user space as possible; the migration of memory will often require changes elsewhere in the system (such as redirecting interrupts) that only user space can know about anyway. The kernel currently provides a memory.reclaim knob to trigger reclaim; perhaps a memory.demote could be provided as well? Maybe there needs to be a kpromoted thread, or perhaps that task should be handled by user space.

Memory promotion, it was said, should be done asynchronously, unlike how NUMA migration is done. Moving memory synchronously can create latency blips that user space might notice; performing promotion asynchronously would still be noticeable, but it would not stall an application in the same way.

At the conclusion of the session, it was repeated that a proper solution in this area could lead to "massive amounts" of money being saved, especially in hyperscaler deployments. A memory-tiering working group is being formed to continue work in this area and to ensure that all of the known use cases are handled.

Index entries for this article
KernelMemory management/Tiered-memory systems
ConferenceStorage, Filesystem, Memory-Management and BPF Summit/2024


to post comments

Better support for locally-attached-memory tiering

Posted May 28, 2024 19:40 UTC (Tue) by gmprice (subscriber, #167884) [Link]

One thing to consider regarding memory tiering as a whole, is that there is no free lunch. Just because you *can* move pages, doesn't mean doing so *will* result in beneficial performance gains - even if the decision "is correct". To determine what page to migrate, some interposition and/or processing must have been done, and therefore "performance stolen" from the system as a whole.

For example, if hot-page detection is implemented via page faults, you introduce latency to the program by generating these faults. If you migrate a page that is actively being used you may introduce additional faults and/or stalls during the migration process. You may even introduce unintended migrations if that page happened to be part of a complex folio. Etc, etc, etc.

I've taken to calling this the "Heisenberg Principle" of performance chasing: profiling the system changes the system.

In the best-case scenario, as discussed in the mempolicy talk, you select the best place for a piece of data when its page initially allocated. This mitigates the need for profiling and/or migration. This isn't really feasible, workloads change over time and different parts of the memory become hot or cold or what have you.

However, when you consider that "doing too much" is detrimental, I think the tiering/numa balancing space may be chasing the wrong problem. The tiering problem is almost certainly some form of a Halting/Undecidability problem at worst, and almost an exact replica of the Detection Problem at best (Time to Detect, Time to Act, Time To Observe Results). So rather than looking at that as the primary solution, maybe it should be seen as the "tool of last resort". Are we sure this is the tool we needing to be grabbing for every workload, or have we not explored certain areas yet?

To some extent, we should (warning: opinion ahead) be trying to figure out how to avoid and/or minimize migrations. Then deploy migration-based tiering solutions for very well understood scenarios - which the program itself or a hyper/supervisor can help inform the system how/when/what to move (think pidfd_madvise). The note about this being a scheduler issue is a good example of this reasoning - if the memory is remote, why not move the task? This is a good line of reasoning in my opinion and others like it should be explored more deeply before we default to page migration being the hammer for every nail.


Copyright © 2024, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds