-
Notifications
You must be signed in to change notification settings - Fork 336
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
Ruby with jemalloc #182
Comments
We'd like to do the same thing, and have started down the path of building our own ruby docker image with jemalloc support. That involves a whole bunch of copy & pasting of So it would be great if this option could be included as an option for the images published on docker hub. And I think a lot of other ruby users would find this valuable. |
@jonmoter could you open PR, in [WIP] status I will also contribute to this PR and add my stuff |
If anyone is looking to run this now, I've forked this repository, merged #192, and added a public/automated docker hub that can be found here: https://hub.docker.com/r/swipesense/ruby-jemalloc We've been using this in production for a couple weeks now and have seen great results. I will maintain that docker hub and repo until this repo implements this request. |
@jorihardman amazing work.. can you open the issue register + any plans to support Alpine? |
@ashleyhull-versent thanks for the alpine PR. Images are being built as a type this. |
We're still hesitant to add this to the image without a recommendation by Ruby upstream. In the meantime, you can trivially add support in your own Dockerfile without recompiling ruby through the magic of FROM ruby:2.6
RUN apt-get update && apt-get install libjemalloc1 && rm -rf /var/lib/apt/lists/*
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1
# gleaned from a few sources
# https://github.com/jemalloc/jemalloc/wiki/Getting-Started
# https://brandonhilkert.com/blog/reducing-sidekiq-memory-usage-with-jemalloc/ And done, ruby now uses jemalloc. 🎉 🌮 |
@yosifkit I tried using FROM ruby:2.4.2
RUN apt-get update && apt-get install -y libjemalloc-dev libjemalloc1
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1
... Then, inside the container: > echo $LD_PRELOAD
/usr/lib/x86_64-linux-gnu/libjemalloc.so.1
> ruby -r rbconfig -e "puts RbConfig::CONFIG['LIBS']"
-lpthread -ldl -lcrypt -lm Any idea why jemalloc isn't listed? 😿 Edit: ruby:2.6 won't work either. |
@ftuyama in Ruby 2.6 I had to look for |
I am having trouble with jemalloc not being loaded as well. @tjwallace I am using Ruby 2.6 and I got nothing in |
Using a docker image where ruby is compiled using jemalloc, jemalloc is actually in > ruby -r rbconfig -e "puts RbConfig::CONFIG['MAINLIBS']"
-lz -lpthread -lrt -lrt -ljemalloc -ldl -lcrypt -lm But I couldn't load it with |
The whole point of LD_PRELOAD would be that Ruby isn't even aware it's
being used -- it should be completely transparent to Ruby.
|
Normally when you do the following (when you see output) ruby should be using jemalloc.
|
Nice @butsjoh! I tested using @yosifkit's example above with ___ Begin jemalloc statistics ___
Version: 3.6.0-0-g46c0af68bd248b04df75e4f92d5fb804c3d75340
Assertions disabled
Run-time option settings:
opt.abort: false
opt.lg_chunk: 22
opt.dss: "secondary"
opt.narenas: 48
opt.lg_dirty_mult: 3
opt.stats_print: true
opt.junk: false
opt.quarantine: 0
opt.redzone: false
opt.zero: false
opt.tcache: true
opt.lg_tcache_max: 15
CPUs: 12
Arenas: 48
Pointer size: 8
Quantum size: 16
Page size: 4096
Min active:dirty page ratio per arena: 8:1
Maximum thread-cached size class: 32768
Chunk size: 4194304 (2^22)
Allocated: 37482352, active: 38195200, mapped: 46137344
Current active ceiling: 41943040
chunks: nchunks highchunks curchunks
11 11 11
huge: nmalloc ndalloc allocated
1 0 33554432
arenas[0]:
assigned threads: 1
dss allocation precedence: disabled
dirty pages: 1133:100 active:dirty, 1 sweep, 3 madvises, 265 purged
allocated nmalloc ndalloc nrequests
small: 2486128 36132 13694 70467
large: 1441792 157 51 666
total: 3927920 36289 13745 71133
active: 4640768
mapped: 8388608
bins: bin size regs pgs allocated nmalloc ndalloc nrequests nfills nflushes newruns reruns curruns
0 8 501 1 12976 1725 103 2022 19 2 4 2 4
1 16 252 1 30672 2175 258 3118 25 5 8 7 8
2 32 126 1 137600 5400 1100 11084 54 11 39 50 35
3 48 84 1 249984 7728 2520 9328 92 30 62 135 62
4 64 63 1 120960 5670 3780 13134 90 60 43 191 30
5 80 50 1 84000 4550 3500 9348 91 70 29 189 27
6 96 84 2 183648 2016 103 2932 29 4 24 3 23
7 112 72 2 30800 324 49 493 8 5 4 2 4
8 128 63 2 91520 1068 353 3702 20 7 13 13 12
9 160 51 2 78080 508 20 2011 12 2 10 0 10
10 192 63 3 41472 312 96 464 8 5 6 2 4
11 224 72 4 38304 270 99 304 6 5 5 4 3
12 256 63 4 42240 297 132 411 7 5 6 3 3
13 320 63 5 443200 1471 86 1826 33 3 23 4 22
14 384 63 6 46080 218 98 255 6 5 3 1 2
15 448 63 7 150976 376 39 461 8 3 7 1 6
16 512 63 8 58368 186 72 230 6 6 2 0 2
17 640 51 8 111360 901 727 8303 22 16 6 33 6
18 768 47 9 62208 149 68 149 7 6 3 1 2
19 896 45 10 43904 111 62 86 4 5 3 0 2
20 1024 63 16 73728 123 51 231 5 6 2 0 2
21 1280 51 16 52480 100 59 93 4 6 1 0 1
22 1536 42 16 49152 83 51 112 4 5 2 0 1
23 1792 38 17 21504 50 38 49 4 5 1 0 1
24 2048 65 33 73728 105 69 158 4 6 1 0 1
25 2560 52 33 79360 97 66 72 5 6 1 0 1
26 3072 43 33 49152 63 47 66 3 4 1 0 1
27 3584 39 35 28672 56 48 25 4 6 1 0 1
large: size pages nmalloc ndalloc nrequests curruns
4096 1 22 5 117 17
8192 2 38 7 353 31
12288 3 11 2 48 9
16384 4 55 13 98 42
20480 5 1 1 1 0
24576 6 5 2 5 3
28672 7 1 1 1 0
32768 8 3 1 22 2
36864 9 3 3 3 0
[2]
49152 12 2 2 2 0
[2]
61440 15 7 7 7 0
[4]
81920 20 1 0 1 1
[3]
98304 24 2 1 2 1
[4]
118784 29 3 3 3 0
[18]
196608 48 1 1 1 0
[8]
233472 57 1 1 1 0
[198]
1048576 256 1 1 1 0
[762]
--- End jemalloc statistics --- |
I am not an expert on the matter but that is what is saw other people saying about it to check if it using it. I do not fully understand yet how installing jemalloc on the system and setting LD_PRELOAD affects other software except ruby. So if anybody can explain me that? :) @tianon You mentioned that it should work transparently for ruby by setting LD_PRELOAD but does it then affect other software as well as opposed to compile it with ruby? |
Yeah, it will likely make most applications switch to jemalloc if they're invoked as a sub-process of Ruby (or invoked with the environment variable set), although that could be avoided by explicitly resetting that environment variable when spawning the subprocess from Ruby. |
I assume this is still broken on alpine? could anybody confirm this? |
Not sure if there are still issues with running Ruby/jemallloc on Alpine (the |
As stated in this comment (jemalloc/jemalloc#1443 (comment)), Alpine uses musl libc which internally uses malloc and there are no plans to support jemalloc for now. |
this seems to work in my env, with Rails 5.2 and Ruby 2.5.3 and docker, thanks! |
If i try from 2.5 FROM ruby:2.5 libjemalloc1 is not an available package but libjemalloc2. If I isntall the latest then it does not appear when running ruby -r rbconfig -e "puts RbConfig::CONFIG['LIBS']" nor ruby -r rbconfig -e "puts RbConfig::CONFIG['MAINLIBS']" |
You'll also need to set |
Same issue here @tianon I tried that, but no changes |
😕 FROM ruby:3.0-buster
RUN apt-get update && apt-get install libjemalloc2 && rm -rf /var/lib/apt/lists/*
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 $ docker run -it --rm --env MALLOC_CONF=stats_print:true 11636dada43a ruby -e 'exit'
___ Begin jemalloc statistics ___
Version: "5.1.0-0-g61efbda7098de6fe64c362d309824864308c36d4"
Build-time option settings
config.cache_oblivious: true
config.debug: false
config.fill: true
config.lazy_lock: false
config.malloc_conf: ""
config.prof: true
config.prof_libgcc: true
config.prof_libunwind: false
config.stats: true
config.utrace: false
config.xmalloc: false
Run-time option settings
opt.abort: false
opt.abort_conf: false
opt.retain: true
opt.dss: "secondary"
opt.narenas: 48
opt.percpu_arena: "disabled"
opt.metadata_thp: "disabled"
opt.background_thread: false (background_thread: false)
opt.dirty_decay_ms: 10000 (arenas.dirty_decay_ms: 10000)
opt.muzzy_decay_ms: 10000 (arenas.muzzy_decay_ms: 10000)
opt.junk: "false"
opt.zero: false
opt.tcache: true
opt.lg_tcache_max: 15
opt.thp: "default"
opt.prof: false
opt.prof_prefix: "jeprof"
opt.prof_active: true (prof.active: false)
opt.prof_thread_active_init: true (prof.thread_active_init: false)
opt.lg_prof_sample: 19 (prof.lg_sample: 0)
opt.prof_accum: false
opt.lg_prof_interval: -1
opt.prof_gdump: false
opt.prof_final: false
opt.prof_leak: false
opt.stats_print: true
opt.stats_print_opts: ""
Profiling settings
prof.thread_active_init: false
prof.active: false
prof.gdump: false
prof.interval: 0
prof.lg_sample: 0
Arenas: 48
Quantum size: 16
Page size: 4096
Maximum thread-cached size class: 32768
Number of bin size classes: 36
Number of thread-cache bin size classes: 41
Number of large size classes: 196
Allocated: 38019880, active: 38617088, metadata: 3151800 (n_thp 0), resident: 42512384, mapped: 45674496, retained: 7278592
Background threads: 0, num_runs: 0, run_interval: 0 ns
n_lock_ops n_waiting n_spin_acq n_owner_switch total_wait_ns max_wait_ns max_n_thds
background_thread 4 0 0 1 0 0 0
ctl 2 0 0 1 0 0 0
prof 0 0 0 0 0 0 0
arenas[0]:
assigned threads: 1
uptime: 47998680
dss allocation precedence: "secondary"
decaying: time npages sweeps madvises purged
dirty: 10000 187 0 0 0
muzzy: 10000 0 0 0 0
allocated nmalloc ndalloc nrequests
small: 2413352 28339 5535 60829
large: 35606528 82 31 82
total: 38019880 28421 5566 60911
active: 38617088
mapped: 45674496
retained: 7278592
base: 3123120
internal: 28680
metadata_thp: 0
tcache_bytes: 287624
resident: 42512384
n_lock_ops n_waiting n_spin_acq n_owner_switch total_wait_ns max_wait_ns max_n_thds
large 10 0 0 1 0 0 0
extent_avail 403 0 0 3 0 0 0
extents_dirty 712 0 0 3 0 0 0
extents_muzzy 284 0 0 3 0 0 0
extents_retained 567 0 0 3 0 0 0
decay_dirty 8 0 0 1 0 0 0
decay_muzzy 8 0 0 1 0 0 0
base 433 0 0 3 0 0 0
tcache_list 4 0 0 1 0 0 0
bins: size ind allocated nmalloc ndalloc nrequests curregs curslabs regs pgs util nfills nflushes nslabs nreslabs n_lock_ops n_waiting n_spin_acq n_owner_switch total_wait_ns max_wait_ns max_n_thds
8 0 12792 1651 52 2047 1599 4 512 1 0.780 18 2 4 0 28 0 0 1 0 0 0
16 1 43360 2750 40 3771 2710 11 256 1 0.962 29 1 11 0 44 0 0 1 0 0 0
32 2 165600 5700 525 13167 5175 41 128 1 0.986 61 6 42 29 113 0 0 1 0 0 0
48 3 230400 6500 1700 9353 4800 19 256 3 0.986 65 17 22 58 110 0 0 1 0 0 0
64 4 131072 3264 1216 9367 2048 32 64 1 1 51 19 32 138 105 0 0 1 0 0 0
80 5 62240 956 178 2509 778 4 256 5 0.759 23 5 4 6 35 0 0 1 0 0 0
96 6 116352 1650 438 3020 1212 10 128 3 0.946 18 6 12 11 41 0 0 1 0 0 0
112 7 120848 1100 21 1281 1079 5 256 7 0.842 14 3 5 0 25 0 0 1 0 0 0
128 8 59136 464 2 1514 462 15 32 1 0.962 16 1 15 0 35 0 0 1 0 0 0
160 9 51360 450 129 1892 321 3 128 5 0.835 7 5 4 0 20 0 0 1 0 0 0
192 10 32256 256 88 305 168 3 64 3 0.875 6 4 4 1 18 0 0 1 0 0 0
224 11 28448 225 98 336 127 1 128 7 0.992 5 5 1 0 14 0 0 1 0 0 0
256 12 62976 252 6 442 246 16 16 1 0.960 18 2 16 0 39 0 0 1 0 0 0
320 13 388160 1232 19 1628 1213 19 64 5 0.997 24 2 19 2 48 0 0 1 0 0 0
384 14 60672 192 34 366 158 5 32 3 0.987 8 3 5 2 19 0 0 1 0 0 0
448 15 94528 272 61 298 211 4 64 7 0.824 8 5 5 0 22 0 0 1 0 0 0
512 16 48640 104 9 215 95 12 8 1 0.989 14 4 13 3 35 0 0 1 0 0 0
640 17 73600 736 621 7484 115 8 32 5 0.449 29 22 10 39 66 0 0 1 0 0 0
768 18 26112 56 22 130 34 3 16 3 0.708 5 6 3 1 17 0 0 1 0 0 0
896 19 40320 88 43 85 45 2 32 7 0.703 5 4 3 1 16 0 0 1 0 0 0
1024 20 47104 55 9 153 46 12 4 1 0.958 6 4 14 2 29 0 0 1 0 0 0
1280 21 44800 64 29 117 35 3 16 5 0.729 6 5 4 0 19 0 0 1 0 0 0
1536 22 19968 30 17 74 13 3 8 3 0.541 4 4 5 3 18 0 0 1 0 0 0
1792 23 21504 36 24 51 12 2 16 7 0.375 5 5 2 1 15 0 0 1 0 0 0
2048 24 69632 50 16 414 34 18 2 1 0.944 6 4 26 0 47 0 0 1 0 0 0
2560 25 35840 32 18 40 14 3 8 5 0.583 6 5 5 2 21 0 0 1 0 0 0
3072 26 27648 20 11 31 9 3 4 3 0.750 5 5 6 2 22 0 0 1 0 0 0
3584 27 7168 13 11 7 2 1 8 7 0.250 4 4 2 1 14 0 0 1 0 0 0
4096 28 49152 23 11 217 12 12 1 1 1 5 6 23 0 48 0 0 1 0 0 0
5120 29 20480 16 12 267 4 1 4 5 1 4 5 4 1 19 0 0 1 0 0 0
6144 30 36864 22 16 18 6 4 2 3 0.750 4 5 10 4 28 0 0 1 0 0 0
7168 31 14336 14 12 3 2 1 4 7 0.500 3 3 5 0 18 0 0 1 0 0 0
8192 32 114688 25 11 140 14 14 1 2 1 5 5 25 0 49 0 0 1 0 0 0
10240 33 30720 12 9 71 3 2 2 5 0.750 2 3 6 0 18 0 0 1 0 0 0
12288 34 24576 17 15 14 2 2 1 3 1 3 4 17 0 42 0 0 1 0 0 0
14336 35 0 12 12 2 0 0 2 7 1 2 3 6 0 20 0 0 1 0 0 0
large: size ind allocated nmalloc ndalloc nrequests curlextents
16384 36 720896 56 12 80 44
20480 37 0 1 1 1 0
24576 38 24576 3 2 3 1
28672 39 28672 1 0 1 1
32768 40 0 2 2 14 0
40960 41 0 3 3 3 0
49152 42 49152 2 1 2 1
---
65536 44 0 6 6 6 0
81920 45 81920 1 0 1 1
98304 46 98304 1 0 1 1
---
131072 48 0 2 2 2 0
---
262144 52 0 1 1 1 0
---
393216 54 0 1 1 1 0
---
1048576 60 1048576 1 0 1 1
---
33554432 80 33554432 1 0 1 1
---
--- End jemalloc statistics --- |
FWIW - We've been running jemalloc 5.2.1 in production (for the better part of a year) using the |
@butsjoh @tianon I have the same question! We experiment with it and compare two options: (a) Ruby with statically linked It's early to make conclusions, but we started to see some improvements with latency, especially from ruby gems that dependent on C++ libraries so require compilation like mysql2 (https://github.com/brianmario/mysql2/tree/master/ext/mysql2) and openssl (https://github.com/ruby/openssl/tree/master/ext/openssl) and pretty much anything that involves network sockets. Based on prelimenary testing results non-Ruby processes stick with default memory allocator when we only statically linked Ruby with |
Is there a recommendation of which I see in the messages above that Can I use, for example, |
We’re using |
3.0.2 on alpine 3.14 seems to work too (requires "manual" jemalloc build tho) FROM ruby:3.0.2-alpine3.14 AS builder
RUN apk add build-base
RUN wget -O - https://github.com/jemalloc/jemalloc/releases/download/5.2.1/jemalloc-5.2.1.tar.bz2 | tar -xj && \
cd jemalloc-5.2.1 && \
./configure && \
make && \
make install
FROM ruby:3.0.2-alpine3.14
COPY --from=builder /usr/local/lib/libjemalloc.so.2 /usr/local/lib/
ENV LD_PRELOAD=/usr/local/lib/libjemalloc.so.2
RUN MALLOC_CONF=stats_print:true ruby -e "exit"
# ... your stuffs ^ this one is multistage, but does not have to be. |
|
@skhanna1011, Adding |
Without an explicit upstream recommendation for using I believe https://bugs.ruby-lang.org/issues/14718 is probably the best (upstream) place to watch for more on this topic. |
Jemalloc is back in the alpine repository for 3.17. If you use that variant there is no need for manual builds anymore. RUN apk --no-cache add jemalloc
ENV LD_PRELOAD=/usr/lib/libjemalloc.so.2 Or use jemalloc.sh which automatically sets up LD_PRELOAD for a single process: MALLOC_CONF=stats_print:true jemalloc.sh ruby -e "exit" https://pkgs.alpinelinux.org/package/v3.17/main/x86_64/jemalloc |
If you don't to use
|
In case anyone else wants to have a Dockerfile that runs on different architectures. Co-workers run it on x86_64 while i run it on aarch64. This now works on both without the need to adjust directory or throw around docker build arguments.
|
At least on Debian and Debian derivatives an exact path doesn't seem to be required. If you $ ldconfig -v 2> /dev/null | grep linux-gnu
/lib/aarch64-linux-gnu:
/usr/lib/aarch64-linux-gnu:
$ ldconfig -v 2> /dev/null | grep libjemalloc
libjemalloc.so.2 -> libjemalloc.so.2 Therefore the following should work across architectures: ENV LD_PRELOAD=libjemalloc.so.2 And indeed that is the behaviour we see in production across aarch64 and x86_64, i.e. you can refer to the library in $ export | grep LD_PRELOAD
declare -x LD_PRELOAD="libjemalloc.so.2"
$ MALLOC_CONF=stats_print:true ruby -e "exit"
___ Begin jemalloc statistics ___
.... |
Here is a collection of info on ruby+Jemalloc5 https://gist.github.com/jjb/9ff0d3f622c8bbe904fe7a82e35152fc |
Using LD_PRELOAD with Ruby > 3.0 (tried 3.1, 3.2 and 3.3) and mini_racer causes segfaults, statically linked seems to be okay though. |
I would like to create a ruby version compiled with jemalloc. Is this something the community needs? Is it encouraged to make an official contribution. If, so I can try to create an official contribution.
The text was updated successfully, but these errors were encountered: