Fork me on GitHub
#off-topic
<
2024-02-07
>
jpmonettas15:02:26

does anybody has experience working with jvm SoftReferences and tuning GCs for different freeing patterns? More in 🧵 ...

🙌 1
jpmonettas15:02:54

I have been experimenting with SoftReference for my execution recording stuff, so when the heap is not large enough and memory is running low it can discard some recorded values and avoid an OOME. The problem I'm seeing is that SoftReferences do get discarded, the first full GC discards a lot of them but each GC pass releases less and less of them. So it gets in a situation where the GC runs very frequently while a memory sample shows there are a lot of SoftReferences that can be released as you can see in the picture. This avoids the crashing but makes everything super slow.

jpmonettas15:02:01

I played with -XX:SoftRefLRUPolicyMSPerMB and different VMs like Graal and Openjdk but I see similar behaviors :man-shrugging:

phronmophobic16:02:00

I'm not an expert on SoftReferences, but I don't think the graph shows that there a lot of SoftReferences that can be released, only that there are a lot of SoftReferences. It's possible that not all the references are softly reachable.

phronmophobic16:02:11

> An object is softly reachable if it is not strongly reachable but can be reached by traversing a soft reference. You probably already checked this, but have you double checked that the referenced objects aren't strongly reachable from other parts of the code?

jpmonettas17:02:03

yeah, I checked but I can be missing something. Recordings consist of a bunch of ExprTrace objects in a ArrayList, each of them pointing to references, and I changed the strong references by SoftReferences, but it is true that they are values that the application being recorded is using, so some of them will be strong

phronmophobic17:02:07

Also, if you're building some sort of cache, I highly recommend https://github.com/ben-manes/caffeine/

jpmonettas17:02:50

no, it is not a cache, it is the timeline recording of http://www.flow-storm.org

jpmonettas17:02:33

I'll have to keep playing with it

phronmophobic17:02:05

One way to check is to do an .hprof heap dump:

(defn heap-dump
  "Dumps the heap to the outputFile file in the same format as the hprof heap dump.

  `output-path` - the system-dependent filename
  `live?` - if true dump only live objects i.e. objects that are reachable from others"
  [output-path live?]
  (let [b ^HotSpotDiagnosticMXBean
        (ManagementFactory/newPlatformMXBeanProxy
         (ManagementFactory/getPlatformMBeanServer)
         "com.sun.management:type=HotSpotDiagnostic"
         HotSpotDiagnosticMXBean)]
    (.dumpHeap b output-path live?)))

jpmonettas17:02:47

yeah, that is the same as clicking heap dump on visualVM

👍 1
jpmonettas17:02:27

will have to create examples with smaller heap, since 15Gb heap is going to be slow to dump and analyze I think

1
jpmonettas18:02:12

there is definitely something funky going on in my code

jpmonettas18:02:26

I simulated a similar situation with this

(ns user
  (:import [java.lang.ref SoftReference]
           [java.util ArrayList]))

(def coll (ArrayList.))

(defn make-entity [size]
  (long-array size))

(def max-entities (* 1024 1024 30) ) ;; 30Gb of entities

(defn run []
  (loop [i 0]
    (when (< i max-entities)
      (let [e (make-entity 1024)] ;; 1 Kb entity
        (.add ^ArrayList coll (SoftReference. e))

        (when (zero? (mod i 100000)) (println "Created " i "entities")))
      (recur (inc i)))))

jpmonettas18:02:44

and I get a much more healthy pattern

clojure-spin 1
jpmonettas18:02:51

and I'm starting to think there is probably nothing wrong with my code, but with the nature of what I'm trying to do and the kind of execution I'm recording. So maybe SoftReferences aren't going to make this situation better after all

jpmonettas11:02:30

I figured out the problem here, wasn't on my code, and wasn't bad jvm behavior, the whole thing was kind of dumb. The original problem is that I was accumulating millions of entities of ~ 56 bytes each, and I wrapped them in SoftReferences which are 40 bytes each, so even when the original entities got discarded under mem pressure I was replacing them with something that has almost the same size facepalm . Lesson learned use SoftReferences with big enough things, like in the simulation above.

1
🙌 1
jpmonettas11:02:50

Lesson two, if I'm going to simulate something, simulate the right thing

🙌 1
vemv11:02:47

In case it's of any use, I've been running this patch in Clojure itself for a few years https://gist.github.com/vemv/23720829a6e56c9a8e9cfb9173defa21 it certainly made the GC characteristics much better (of course, this is an unrelated use case - often the tools that are great of X aren't for Y)

p-himik15:02:45

What's the best way to create an interactive document that has the following features? • Can be hosted on a static website • Allows regular HTML embeds (at least images, videos) • Allows adding executable changeable CLJS code snippets

borkdude16:02:11

For interactive Clojure code snippets I'd recommend clojure-mode (a CodeMirror mode). Two demo pages that use that: https://babashka.org/sci.configs/ https://squint-cljs.github.io/squint/

p-himik16:02:43

Right. But that's a bit... manual. An ideal experience would be something like Clerk but that spits out an HTML file, maybe with a bunch of other static resources.

borkdude16:02:55

Maybe ask in #C035GRLJEP8 - there are some people who compiled clerk with their own CLJS libs so you can use them from SCI which makes it interactive client side

p-himik16:02:09

Ah, will do, thanks.

elken17:02:28

Clerk can spit out a HTML file :)

💯 1
borkdude17:02:52

I also made a tiny lib once that used SCI + codemirror/clojure-mode + markdown: https://github.com/borkdude/cljs-showcase This is how it looks. Not that pretty, I kept it minimal: https://borkdude.github.io/cljs-showcase/

borkdude17:02:15

I think you can do something similar with clerk, to show an inline editor where you can eval some stuff

p-himik17:02:49

Thanks! Mulling it over... Maybe I'll end up not needing allowing evaluation at all.

Chris McCormick17:02:26

Just want to say what you described sounds like something I have wanted several times. Some kind of lightweight ClojureScript notebook that runs entirely client side. Not sure if that's exactly what you meant.

p-himik17:02:43

Yeah, pretty much.

mkvlr17:02:30

@U9EQP1K0X don’t you have a clerk notebook that does that laying around?

chromalchemy21:02:09

Isnt Clay/Kindly doing this? (Not sure about the eval part)

chucklehead03:02:23

if you end up building something with squint, it's diy, but for a side project I was playing around with a different workflow and used https://github.com/borkdude/bun-squint-loader and https://github.com/BjornTheProgrammer/bun-plugin-html to put together a bun "build" that compiles/minifies/inlines any CLJS referenced by the html entrypoint.

chucklehead03:02:39

The actual project is a broken WIP, but you can see an example of the build process here: https://github.com/casselc/clj-passkey-demo. The public folder compiles to a single inlined-everything static HTML file that's around 12KB gzipped.

1
Andrea07:02:12

@U2FRKM4TW, @U5H74UNSF you mean the experiment with clojure-nested-in-markdown experiment with clerk viewers? https://snapshots.nextjournal.com/clojure-mode/build/5d88847aecd253e047f36565e0455bfec7f4964d/livedoc/index.html (ux is not optimal and we have to improve its performance by probably squintify its sources, please scroll to the Usage section)

👍 1
Andrea08:02:49

styles are broken, sorry...

jackrusher09:02:07

If you want entirely client-side, you could consider maria.cloud as well 🙂

👍 1
👀 1
p-himik09:02:59

Ah! That's pretty much it. I knew I've seen it somewhere. Thanks!

👍 1
jackrusher09:02:58

We’re close to releasing v2 of Maria, btw. 🤞:skin-tone-2:

mauricio.szabo20:02:00

Folks, some help with code: I'm trying to detect prefixes for autocomplete for generic languages. Basically, supposing I have a suggestion and something written in a text editor, I want to know what to replace. The problem is - different languages have different meanings on what is a word. For example, if I type in Clojure my-i and a suggestion my-ideaappears, I know I have to replace the whole my-i prefix; in Javascript, for example, that would not be true; i-i with a suggestion idea needs to replace the second i and not the whole thing. Any idea on how to detect this? thinking-face

p-himik20:02:29

So you want to have a language-agnostic behavior that's based on language-specific constructs. That's like wanting to eat peanut butter while having a severe allergy to peanuts. :) If you don't want to write rules for every language out there, you can add a user-level ability to customize such rules. In this case, it seems that you only need a rule to determine valid tokens.

1
Noah Bogart20:02:59

you're basically describing vim's 'iskeyword' setting, which deals with this on a per file-type basis: https://neovim.io/doc/user/options.html#'iskeyword'

mauricio.szabo21:02:22

I mean, I'm trying to integrate with LSP, which supposedly needs to be language-agnostic 🤷

Noah Bogart21:02:48

what are you trying to integrate? lsp usually sends ranges, right?

mauricio.szabo22:02:10

No, LSP can send ranges, but it's not mandatory (and AFAIK only one server that I integrated so far sends ranges)

👍 1
mauricio.szabo15:02:31

I... might have solved with a horrible idea. Basically, I got all suggestions and mapped all non-word chars; then I generated a regex with that info, searched for the current word under the cursor with that regex, and called that "the prefix" laughcry

Noah Bogart15:02:05

omg do you do that on every keystroke?

Noah Bogart15:02:08

that's very clever tho