Re: [LSF/MM/BPF TOPIC] Swap Abstraction / Native Zswap

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

 



On Thu, Mar 16, 2023 at 12:51 AM Huang, Ying <ying.huang@xxxxxxxxx> wrote:
>
> Yosry Ahmed <yosryahmed@xxxxxxxxxx> writes:
>
> > On Sun, Mar 12, 2023 at 7:13 PM Huang, Ying <ying.huang@xxxxxxxxx> wrote:
> >>
> >> Yosry Ahmed <yosryahmed@xxxxxxxxxx> writes:
> >>
> >> <snip>
> >> >
> >> > My current idea is to have one xarray that stores the swap_descs
> >> > (which include swap_entry, swapcache, swap_count, etc), and only for
> >> > rotating disks have an additional xarray that maps swap_entry ->
> >> > swap_desc for cluster readahead, assuming we can eliminate all other
> >> > situations requiring a reverse mapping.
> >> >
> >> > I am not sure how having separate xarrays help? If we have one xarray,
> >> > might as well save the other lookups on put everything in swap_desc.
> >> > In fact, this should improve the locking today as swapcache /
> >> > swap_count operations can be lockless or very lightly contended.
> >>
> >> The condition of the proposal is "reverse mapping cannot be avoided for
> >> enough situation".  So, if reverse mapping (or cluster readahead) can be
> >> avoided for enough situations, I think your proposal is good.  Otherwise,
> >> I propose to use 2 xarrays.  You don't need another reverse mapping
> >> xarray, because you just need to read the next several swap_entry into
> >> the swap cache for cluster readahead.  swap_desc isn't needed for
> >> cluster readahead.
> >
> > swap_desc would be needed for cluster readahead in my original
> > proposal as the swap cache lives in swap_descs. Based on the current
> > implementation, we would need a reverse mapping (swap entry ->
> > swap_desc) in 3 situations:
> >
> > 1) __try_to_reclaim_swap(): when trying to find an empty swap slot and
> > failing, we fallback to trying to find swap entries that only have a
> > page in the swap cache (no references in page tables or page cache)
> > and free them. This would require a reverse mapping.
> >
> > 2) swapoff: we need to swap in all entries in a swapfile, so we need
> > to get all swap_descs associated with that swapfile.
> >
> > 3) swap cluster readahead.
> >
> > For (1), I think we can drop the dependency of a reverse mapping if we
> > free swap entries once we swap a page in and add it to the swap cache,
> > even if the swap count does not drop to 0.
>
> Now, we will not drop the swap cache even if the swap count becomes 0 if
> swap space utility < 50%.  Per my understanding, this avoid swap page
> writing for read accesses.  So I don't think we can change this directly
> without necessary discussion firstly.


Right. I am not sure I understand why we do this today, is it to save
the overhead of allocating a new swap entry if the page is swapped out
again soon? I am not sure I understand this statement "this avoid swap
page
writing for read accesses".

>
>
> > For (2), instead of scanning page tables and shmem page cache to find
> > swapped out pages for the swapfile, we can scan all swap_descs
> > instead, we should be more efficient. This is one of the proposal's
> > potential advantages.
>
> Good.
>
> > (3) is the one that would still need a reverse mapping with the
> > current proposal. Today we use swap cluster readahead for anon pages
> > if we have a spinning disk or vma readahead is disabled. For shmem, we
> > always use cluster readahead. If we can limit cluster readahead to
> > only rotating disks, then the reverse mapping can only be maintained
> > for swapfiles on rotating disks. Otherwise, we will need to maintain a
> > reverse mapping for all swapfiles.
>
> For shmem, I think that it should be good to readahead based on shmem
> file offset instead of swap device offset.
>
> It's possible that some pages in the readahead window are from HDD while
> some other pages aren't.  So it's a little hard to enable cluster read
> for HDD only.  Anyway, it's not common to use HDD for swap now.
>
> >>
> >> > If the point is to store the swap_desc directly inside the xarray to
> >> > save 8 bytes, I am concerned that having multiple xarrays for
> >> > swapcache, swap_count, etc will use more than that.
> >>
> >> The idea is to save the memory used by reverse mapping xarray.
> >
> > I see.
> >
> >>
> >> >> >>
> >> >> >> > Keep in mind that the current overhead is 1 byte O(max swap pages) not
> >> >> >> > O(swapped). Also, 1 byte is assuming we do not use the swap
> >> >> >> > continuation pages. If we do, it may end up being more. We also
> >> >> >> > allocate continuation in full 4k pages, so even if one swap_map
> >> >> >> > element in a page requires continuation, we will allocate an entire
> >> >> >> > page. What I am trying to say is that to get an actual comparison you
> >> >> >> > need to also factor in the swap utilization and the rate of usage of
> >> >> >> > swap continuation. I don't know how to come up with a formula for this
> >> >> >> > tbh.
> >> >> >> >
> >> >> >> > Also, like Johannes said, the worst case overhead (32 bytes if you
> >> >> >> > count the reverse mapping) is 0.8% of swapped memory, aka 8M for every
> >> >> >> > 1G swapped. It doesn't sound *very* bad. I understand that it is pure
> >> >> >> > overhead for people not using zswap, but it is not very awful.
> >> >> >> >
> >> >> >> >>
> >> >> >> >> It seems what you really need is one bit of information to indicate
> >> >> >> >> this page is backed by zswap. Then you can have a seperate pointer
> >> >> >> >> for the zswap entry.
> >> >> >> >
> >> >> >> > If you use one bit in swp_entry_t (or one of the available swap types)
> >> >> >> > to indicate whether the page is backed with a swapfile or zswap it
> >> >> >> > doesn't really work. We lose the indirection layer. How do we move the
> >> >> >> > page from zswap to swapfile? We need to go update the page tables and
> >> >> >> > the shmem page cache, similar to swapoff.
> >> >> >> >
> >> >> >> > Instead, if we store a key else in swp_entry_t and use this to lookup
> >> >> >> > the swp_entry_t or zswap_entry pointer then that's essentially what
> >> >> >> > the swap_desc does. It just goes the extra mile of unifying the
> >> >> >> > swapcache as well and storing it directly in the swap_desc instead of
> >> >> >> > storing it in another lookup structure.
> >> >> >>
> >> >> >> If we choose to make sizeof(struct swap_desc) == 8, that is, store only
> >> >> >> swap_entry in swap_desc.  The added indirection appears to be another
> >> >> >> level of page table with 1 entry.  Then, we may use the similar method
> >> >> >> as supporting system with 2 level and 3 level page tables, like the code
> >> >> >> in include/asm-generic/pgtable-nopmd.h.  But I haven't thought about
> >> >> >> this deeply.
> >> >> >
> >> >> > Can you expand further on this idea? I am not sure I fully understand.
> >> >>
> >> >> OK.  The goal is to avoid the overhead if indirection isn't enabled via
> >> >> kconfig.
> >> >>
> >> >> If indirection isn't enabled, store swap_entry in PTE directly.
> >> >> Otherwise, store index of swap_desc in PTE.  Different functions (e.g.,
> >> >> to get/set swap_entry in PTE) are implemented based on kconfig.
> >> >
> >> >
> >> > I thought about this, the problem is that we will have multiple
> >> > implementations of multiple things. For example, swap_count without
> >> > the indirection layer lives in the swap_map (with continuation logic).
> >> > With the indirection layer, it lives in the swap_desc (or somewhere
> >> > else). Same for the swapcache. Even if we keep the swapcache in an
> >> > xarray and not inside swap_desc, it would be indexed by swap_entry if
> >> > the indirection is disabled, and by swap_desc (or similar) if the
> >> > indirection is enabled. I think maintaining separate implementations
> >> > for when the indirection is enabled/disabled would be adding too much
> >> > complexity.
> >> >
> >> > WDYT?
> >>
> >> If we go this way, swap cache and swap_count will always be indexed by
> >> swap_entry.  swap_desc just provides a indirection to make it possible
> >> to move between swap devices.
> >>
> >> Why must we index swap cache and swap_count by swap_desc if indirection
> >> is enabled?  Yes, we can save one xarray indexing if we do so, but I
> >> don't think the overhead of one xarray indexing is a showstopper.
> >>
> >> I think this can be one intermediate step towards your final target.
> >> The changes to current implementation can be smaller.
> >
> > IIUC, the idea is to have two xarrays:
> > (a) xarray that stores a pointer to a struct containing swap_count and
> > swap cache.
> > (b) xarray that stores the underlying swap entry or zswap entry.
> >
> > When indirection is disabled:
> > page tables & page cache have swap entry directly like today, xarray
> > (a) is indexed by swap entry, xarray (b) does not exist. No reverse
> > mapping needed.
> >
> > In this case we have an extra overhead of 12-16 bytes (the struct
> > containing swap_count and swap cache) vs. 24 bytes of the swap_desc.
> >
> > When indirection is enabled:
> > page tables & page cache have a swap id (or swap_desc index), xarray
> > (a) is indexed by swap id,
>
> xarray (a) is indexed by swap entry.


How so? With the indirection enabled, the page tables & page cache
have the swap id (or swap_desc index), which can point to a swap entry
or a zswap entry -- which can change when the page is moved between
zswap & swapfiles. How is xarray (a) indexed by the swap entry in this
case? Shouldn't be indexed by the abstract swap id so that the
writeback from zswap is transparent?

>
>
> > xarray (b) is indexed by swap id as well
> > and contain swap entry or zswap entry. Reverse mapping might be
> > needed.
>
> Reverse mapping isn't needed.


It would be needed if xarray (a) is indexed by the swap id. I am not
sure I understand how it can be indexed by the swap entry if the
indirection is enabled.

>
>
> > In this case we have an extra overhead of 12-16 bytes + 8 bytes for
> > xarray (b) entry + memory overhead from 2nd xarray + reverse mapping
> > where needed.
> >
> > There is also the extra cpu overhead for an extra lookup in certain paths.
> >
> > Is my analysis correct? If yes, I agree that the original proposal is
> > good if the reverse mapping can be avoided in enough situations, and
> > that we should consider such alternatives otherwise. As I mentioned
> > above, I think it comes down to whether we can completely restrict
> > cluster readahead to rotating disks or not -- in which case we need to
> > decide what to do for shmem and for anon when vma readahead is
> > disabled.
>
> We can even have a minimal indirection implementation.  Where, swap
> cache and swap_map[] are kept as they ware before, just one xarray is
> added.  The xarray is indexed by swap id (or swap_desc index) to store
> the corresponding swap entry.
>
> When indirection is disabled, no extra overhead.
>
> When indirection is enabled, the extra overhead is just 8 bytes per
> swapped page.
>
> The basic migration support can be build on top of this.
>
> I think that this could be a baseline for indirection support.  Then
> further optimization can be built on top of it step by step with
> supporting data.


I am not sure how this works with zswap. Currently swap_map[]
implementation is specific for swapfiles, it does not work for zswap
unless we implement separate swap counting logic for zswap &
swapfiles. Same for the swapcache, it currently supports being indexed
by a swap entry, it would need to support being indexed by a swap id,
or have a separate swap cache for zswap. Having separate
implementation would add complexity, and we would need to perform
handoffs of the swap count/cache when a page is moved from zswap to a
swapfile.

>
>
> >>
> >> >> >> >>
> >> >> >> >> Depending on how much you are going to reuse the swap cache, you might
> >> >> >> >> need to have something like a swap_info_struct to keep the locks happy.
> >> >> >> >
> >> >> >> > My current intention is to reimplement the swapcache completely as a
> >> >> >> > pointer in struct swap_desc. This would eliminate this need and a lot
> >> >> >> > of the locking we do today if I get things right.
> >> >> >> >
> >> >> >> >>
> >> >> >> >> > Another potential concern is readahead. With this design, we have no
> >> >> >> >>
> >> >> >> >> Readahead is for spinning disk :-) Even a normal swap file with an SSD can
> >> >> >> >> use some modernization.
> >> >> >> >
> >> >> >> > Yeah, I initially thought we would only need the swp_entry_t ->
> >> >> >> > swap_desc reverse mapping for readahead, and that we can only store
> >> >> >> > that for spinning disks, but I was wrong. We need for other things as
> >> >> >> > well today: swapoff, when trying to find an empty swap slot and we
> >> >> >> > start trying to free swap slots used only by the swapcache. However, I
> >> >> >> > think both of these cases can be fixed (I can share more details if
> >> >> >> > you want). If everything goes well we should only need to maintain the
> >> >> >> > reverse mapping (extra overhead above 24 bytes) for swap files on
> >> >> >> > spinning disks for readahead.
> >> >> >> >
> >> >> >> >>
> >> >> >> >> Looking forward to your discussion.
> >> >>
> >> >> Per my understanding, the indirection is to make it easy to move
> >> >> (swapped) pages among swap devices based on hot/cold.  This is similar
> >> >> as the target of memory tiering.  It appears that we can extend the
> >> >> memory tiering (mm/memory-tiers.c) framework to cover swap devices too?
> >> >> Is it possible for zswap to be faster than some slow memory media?
> >> >
> >> >
> >> > Agree with Chris that this may require a much larger overhaul. A slow
> >> > memory tier is still addressable memory, swap/zswap requires a page
> >> > fault to read the pages. I think (at least for now) there is a
> >> > fundamental difference. We want reclaim to eventually treat slow
> >> > memory & swap as just different tiers to place cold memory in with
> >> > different characteristics, but otherwise I think the swapping
> >> > implementation itself is very different.  Am I missing something?
> >>
> >> Is it possible that zswap is faster than a really slow memory
> >> addressable device backed by NAND?  TBH, I don't have the answer.
> >
> > I am not sure either.
> >
> >>
> >> Anyway, do you need a way to describe the tiers of the swap devices?
> >> So, you can move the cold pages among the swap devices based on that?
> >
> > For now I think the "tiers" in this proposal are just zswap and normal
> > swapfiles. We can later extend it to support more explicit tiering.
>
> IIUC, in original zswap implementation, there's 1:1 relationship between
> zswap and normal swapfile.  But now, you make demoting among swap
> devices more general.  Then we need some general way to specify which
> swap devices are fast and which are slow, and the demoting relationship
> among them.  It can be memory tiers or something else, but we need one.


I think for this proposal, there are only 2 hardcoded tiers. Zswap is
fast, swapfile is slow. In the future, we can support more dynamic
tiering if the need arises.

>
>
> Best Regards,
> Huang, Ying
>





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux