Re: poudriere: swap_pager: out of swap space

From: Mark Millard <marklmi_at_yahoo.com>
Date: Mon, 15 Jan 2024 11:15:45 UTC
On Jan 15, 2024, at 00:07, Lexi Winter <lexi@le-fay.org> wrote:

> Mark Millard:
>> You seem to be under the impression that "Inact" means "page is not
>> dirty" and so can be freed without being written out to the swap
>> space.
> 
> indeed, i was, because this is how sysutils/htop displays memory usage:
> 
> top(1)
> 
> Mem: 8502M Active, 15G Inact, 1568M Laundry, 5518M Wired, 1343M Buf, 690M Free
> 
> htop(1):
> 
>  Mem[||||||||||||||||||||||||||||||||||||||||||                          13.7G/31.9G]
> 
> i'm vaguely annoyed, but also not surprised, to find out that htop is
> wrong here...

htop is not native to FreeBSD, unlike top. So making it fit is
odd because Inact can be a mix of dirty and clean pages.

>> Inact pages can be dirty and such pages can not be freed without
>> being written out to the swap space first. If the swap space
>> ends up filled, dirty pages that are not in active use stay or
>> propogate into the Inact or Laundry states, accumulating there
>> (for later potential use).
> 
> so, how are Inact pages created?

They are just non-wired pages that have not been accessed
in a sufficiently recent time, no matter if dirty vs. if
clean. (Wired pages are never written to swap space while
they are wired.)

Buf pages (as top shows) are clean but can be active
or inactive: it is not an independent category. But
it counts only pages used for buffers/caches. There
could be other clean pages not counted.

FreeBSD does not page out active pages. Thus, a program
that keeps all of the non-wired RAM Active will not
page out to the swap space and can lead to OOM kills.
There is a parameter that indirectly controls the
time before such OOM kills happen: vm.pageout_oom_seq
that has a default value of 12. Larger figures increase
the time it takes for such OOM kills to happen. I use
120 to avoid OOM kills in my range of contexts: delays
long enough for things to complete in my contexts. (I
reference time to simplify the details.)

> does this happen from filesystem
> writes, or something else?

All non-wired memory is subject to potentially being
Inactive. It is not limited to file system memory at
all.

> is there somewhere this that is documented?

Inactive pages that are not dirty are freed based on
memory pressure. Inactive pages that are dirty can not
be freed without loss of information. Inactive can be
an arbitrary mix of dirty and clean pages. Only dirty
pages are potentially moved to Laundry.

I have seen wording indicating that all dirty pages
are in the laundry --mixed in the same text that
such pages are first inactive. The observed behavior
is that the/some dirty pages that have not been
accessed in a sufficiently recent time go inactive
first and later can move to the Laundry --and the
pages that are written to the swap space did make
it into the Laundry first.

One place to read a description is:

https://klarasystems.com/articles/exploring-swap-on-freebsd/

Part of its text is:

QUOTE
The active and inactive queues contain both clean and dirty pages. When reclaiming memory to alleviate a shortage, the page daemon will free clean pages from the head of the inactive queue. Dirty pages must first be cleaned by paging them out to swap or a file system. This is a lot of work, so the page daemon moves them to the laundry queue for deferred processing. The laundry queue is managed by a dedicated thread, the laundry thread, which is responsible for deciding when and how much to page out.
END QUOTE

There is a description of top's output as well:

https://klarasystems.com/articles/explaining-top1-on-freebsd/

but it is not clear about the dirty vs. clean status of
Inact vs. Laundry, where Laundry need not cover all dirty
pages. Nor is it clear about Buf counting a mix of Active
and Inactive pages in its count in general.

===
Mark Millard
marklmi at yahoo.com