Skip to content

zu2: what is left of the anonymous budget once the log pages are mapped #767

Description

@tamnd

#759 takes the log pages out of anonymous memory. This is what is left, worked out from the code, so that the next thing to cut is picked by arithmetic rather than by guess.

At a million ycsb records on server2, zu2 held 1152.6 MiB of anonymous memory against lmdb's 17.6. Almost all of that is log pages, and with map_settled and a bound they become a mapping of the file the kernel can drop. Then the anonymous total is these four:

  • The mutable window. mutable_pages at 4 MiB a page, 16 MiB at the default of four. Fixed, and it has to be anonymous: those are the pages an in place update writes to.
  • The scan plane. Measured on server2, 56.0 MiB over 1000000 keys, 58.7 bytes a key. A node is an 8 byte header, then 8 bytes a link with a geometric height at p=1/4 so about 10.7 bytes on average, then the key inline, in an 8 byte aligned bump arena. For a 23 byte ycsb key that is about 42 bytes of node and the rest is alignment and arena.
  • The index. A bucket is SLOTS 8 byte entries, 64 bytes, and the table doubles, so a million keys sit in a table of 262144 buckets, 16.8 MiB, and a doubling holds both tables at once for as long as it takes to drain.
  • The cold tier and whatever the sessions hold.

So roughly 90 to 110 MiB of anonymous memory a million records, call it 90 to 110 bytes a key. That is ten times better than 1152 and five times worse than lmdb, and the largest single line is the scan plane at more than half.

What to do about the scan plane is a design question with a real trade in it, which is why this is an issue rather than a change:

  1. Keep the key by address rather than inline. Eight bytes for a log address instead of the key, and every comparison in a search reads the record. Cheap while the page is resident and a pread when it is not, which is exactly the case a bound makes common. This trades the memory for read amplification on the scan path and needs measuring before it is believed.
  2. Hold a prefix inline and the address behind it. Most comparisons finish inside the prefix and only a tie reads the record. More code, and the win depends on the key distribution, which for ycsb is a common prefix and a counter, the worst case for a short prefix.
  3. Put the arena chunks in a file of their own and map them. The same trick Every resident page is anonymous memory, so zu2 holds 65x more of it than lmdb and the kernel cannot reclaim any of it #757 plays on the log pages, and the arena never moves, which is what makes it possible at all. The chunks would have to be written before they can be mapped, so this is a real piece of work.
  4. Leave it. 56 MiB a million keys is not what makes a resident set 1152 MiB, and the honest answer may be that after memory_pages evicts mapped pages, which gives back no anonymous memory and costs a pread #759 the memory column is no longer where the gap is.

Blocked on the #759 numbers, and the first thing to do here is measure rather than choose: run the four arm A/B with the per plane figures printed, so the four lines above are measured on a host rather than counted off the source.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    perfPerformance and resource budgetsstorageStorage engines and file formats

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions