Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cabal flag for linking with jemalloc ? #45

Closed
ulidtko opened this issue May 30, 2023 · 2 comments
Closed

Cabal flag for linking with jemalloc ? #45

ulidtko opened this issue May 30, 2023 · 2 comments

Comments

@ulidtko
Copy link
Contributor

ulidtko commented May 30, 2023

Hi again @phadej πŸ‘‹

Asking for opinion before a PR.

In followup to haskellari/postgresql-simple#114 β€” I've found a heavy heap fragmentation issue in my LO-intense workload β€” and determined that it's not the Haskell heap which got fragmented, but rather the C malloc one.

loRead :: Connection -> LoFd -> Int -> IO (Maybe B.ByteString)
loRead connection (LoFd !fd) !maxlen
= withConn connection $ \c -> do
buf <- mallocBytes maxlen
len_ <- c_lo_read c fd buf (fromIntegral maxlen)
let len = fromIntegral len_
if len < 0
then do
free buf
return Nothing
else do
bufre <- reallocBytes buf len
buffp <- newForeignPtr finalizerFree bufre
return $! Just $! B.fromForeignPtr buffp 0 len

☝️ Here, the reallocBytes call, while releasing the extra unused space under maxLen β€” will create differing-length allocations, which depend on LO sizes. So if I do tens of thousands of varying-size LO reads β€” this puts stress onto malloc to handle fragmentation well.

image

The fixed graph on the left β€” is exact same test running against exact same Haskell executable, but with LD_PRELOAD=jemalloc.so. The baseline on the right β€” with stock allocator in libc6 2.35-0ubuntu3.1 on Ubuntu 22.04.2 LTS.

Would you approve adding a flag jemalloc to the cabal-file here?

https://jemalloc.net/ to perhaps save you a search query πŸ˜…

@phadej
Copy link
Collaborator

phadej commented May 30, 2023

Would you approve adding a flag jemalloc to the cabal-file here?

No. mallocBytes comes from base, and I don't have to worry about how it works & whether different allocators would conflict.

@ulidtko
Copy link
Contributor Author

ulidtko commented May 30, 2023

No. mallocBytes comes from base, and I don't have to worry about how it works & whether different allocators would conflict.

Okay, got it πŸ‘ Fair enough, good to know, thanks for reply πŸ™

I'm closing the issue then.

Had just one question β€” whether the LO buffers could be allocated on Haskell heap instead of C heap?
But will self-answer.

There's this mallocForeignPtrBytes API β€” it's fairly old, base-4.0.0.0 has it β€” conceptually equivalent to mallocBytes _ >>= newForeignPtr finalizerFree, but backed by newPinnedByteArray# instead.

Superficially it seems usable here β€” but it's not straightforward, due to unknown-beforehand allocation length which the reallocBytes call handles. So, without a realloc variation for bytearray-ForeignPtr's (which I don't seeΒΉ), we'll either "slop-leak" unused trailing memory, or will need buffer copying.


ΒΉ shrinkMutableByteArray# exists, but isn't threaded through to ForeignPtr API.

@ulidtko ulidtko closed this as completed May 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants