membrane

Ben Sless 2022-03-31T12:23:55.787339Z

Trying to play with viscous locally, how can I bring skia in as a dependency?

Ben Sless 2022-05-22T11:07:41.200589Z

@smith.adriane I'm happy to report this works and now I have a new fun one for you: try inspecting some pathological data structure like a tools.analyzer output then resize the window, program becomes functionally unresponsive

Ben Sless 2022-05-22T11:09:55.519549Z

scratch that, resizing just behaves weird now

phronmophobic 2022-05-22T17:27:03.261499Z

@ben.sless Interesting. Just tried some tools.analyzer output and didn't notice anything weird. Is there a repro I can follow? Big hairy data structures like tools.analyzer output are the kinds of data that viscous was made for so if that use case isn't working well, I'd like to fix it! The only datastructures I would consider truly pathological are infinitely empty sequences like (filter (constantly false) (range)) since there's no way to inspect it without calling first which loops forever.

Ben Sless 2022-05-22T17:32:42.895039Z

It's every data structure, actually. Resize is just laggy

phronmophobic 2022-05-22T17:33:19.144709Z

when you say resize, is that resizing the window or the viscous view?

Ben Sless 2022-05-22T17:33:34.071019Z

The viscous view

Ben Sless 2022-05-22T17:33:50.680959Z

Window resize is snappy

phronmophobic 2022-05-22T17:34:33.171249Z

Is it slow for both skia and java2d or just skia backend?

Ben Sless 2022-05-22T17:35:37.245339Z

Only checked skia

phronmophobic 2022-05-22T17:36:04.840669Z

And do you recall if it was slow when shrinking and growing?

phronmophobic 2022-05-22T17:36:16.320519Z

or possibly just growing?

Ben Sless 2022-05-22T17:36:22.249029Z

Both

phronmophobic 2022-05-22T17:37:57.921059Z

and just to double check, do you know if the data structures you were inspecting were fully realized?

phronmophobic 2022-05-22T17:39:09.635799Z

Were any other operations laggy or just grow/shrink? • hovering over child data structures • navigating • popping • etc

Ben Sless 2022-05-23T05:03:55.142359Z

I think they were I can try to record a demo today

🙏 1
phronmophobic 2022-05-23T05:55:03.954629Z

that would be great

Ben Sless 2022-05-23T05:57:57.941739Z

You'll probably be sleeping by the time I record it

👍 1
phronmophobic 2022-03-31T16:14:47.535729Z

Skia isn't required. If Skia isn't available, it should use java swing to display everything. If you do want to use the skialib backend, you just need the skialib dependency that matches your OS and architecture. One of: • com.phronemophobic.membrane/skialib-linux-x86-64 {:mvn/version "0.9.31.0-beta"}com.phronemophobic.membrane/skialib-macosx-aarch64 {:mvn/version "0.9.31.0-beta"}com.phronemophobic.membrane/skialib-macosx-x86-64 {:mvn/version "0.9.31.0-beta"} You can also just add all 3 with no issue.

Ben Sless 2022-04-01T05:44:50.867209Z

I have them on the class path but the toolkit isn't loaded

phronmophobic 2022-04-01T05:49:22.832069Z

the skia toolkit? or any toolkit?

Ben Sless 2022-04-01T05:50:13.765169Z

The skia toolkit, it starts with java2d instead

phronmophobic 2022-04-01T05:50:48.130479Z

can you load (require 'membrane.skia) at the repl?

Ben Sless 2022-04-01T05:51:52.004529Z

Tried it, not found

Ben Sless 2022-04-01T05:52:26.746419Z

I can try to repro exactly when I'm at the computer and create a repository

phronmophobic 2022-04-01T05:53:42.358889Z

ok, I think I found the issue

phronmophobic 2022-04-01T05:54:25.337089Z

(defonce toolkit
  #?(:clj
     (if-let [tk (resolve 'membrane.skia/toolkit)]
       @tk
       @(requiring-resolve 'membrane.java2d/toolkit))
     :cljs
     nil))
pretty sure the resolve for skia should be requiring-resolve instead of resolve 😞

phronmophobic 2022-04-01T05:54:50.777349Z

err

phronmophobic 2022-04-01T05:55:06.653109Z

maybe I did that on purpose

phronmophobic 2022-04-01T05:55:29.089469Z

so that it only uses skia if that namespace has already been loaded

Ben Sless 2022-04-01T05:56:01.430729Z

Aha, so requiring resolve should fix it?

phronmophobic 2022-04-01T05:56:20.792219Z

right but that would almost always use skia

phronmophobic 2022-04-01T05:56:37.640449Z

because I think the skia namespace loads even if skialib isn't available

phronmophobic 2022-04-01T05:57:04.657419Z

I think I did this as a hack because I didn't expect anyone else besides me to use the skia version

phronmophobic 2022-04-01T05:57:19.622219Z

and I like to default to skia

Ben Sless 2022-04-01T05:58:27.268219Z

Java2d looks terrible on Ubuntu 😄

😆 1
phronmophobic 2022-04-01T05:59:32.285409Z

generally, loading a namespace isn't a big deal, but some UI libraries (cough AWT, GLFW) expect to be the only UI library to be running

phronmophobic 2022-04-01T06:03:25.990449Z

hmmm, the issue is that I cheated and made monospaced, cell-width and cell-height top level defs. The right way to do it is to pass those values as arguments.

phronmophobic 2022-04-01T06:09:42.752319Z

I can fix this, but I think my brain might be a little too tired to fix it tonight. I should be able to fix it tomorrow.

phronmophobic 2022-04-01T06:11:32.647769Z

if you're running the code base locally, you can work around it by changing the toolkit definition in viscous.cljc to:

(require 'membrane.skia)
(defonce toolkit membrane.skia/toolkit)

phronmophobic 2022-04-01T06:12:11.071609Z

or just requiring membrane.skia anywhere before the toolkit in viscous.cljc gets initialized

Ben Sless 2022-05-23T08:14:21.373809Z

@smith.adriane here you go

Ben Sless 2022-05-23T08:48:48.758339Z

Did some very rough profiling

Ben Sless 2022-05-23T08:51:32.099509Z

I have flame graphs to share

Ben Sless 2022-05-23T08:52:16.662519Z

key insight is that path->spec dominates

Ben Sless 2022-05-23T09:08:29.957889Z

paths keep getting recompiled. Can work be front-loaded?

phronmophobic 2022-05-23T17:59:32.411829Z

@ben.sless thanks for the extra info! 🙏 Yep, that's no bueno. I'm pretty surprised that it's showing path->spec as eating so many cycles. I'm sure path->spec could be more efficient, but that same code runs fine on my machine and in the browser, https://phronmophobic.github.io/viscous/. How are you starting the inspector? Are you specifying your own version of specter? Is anything being printed to stdout? I think I remember you saying you were running on linux? I'll see if I can reproduce that locally. I'm pretty puzzled by the symptoms so far. My initial guess is that some part of the event handling is running several times more often than it should be.

Ben Sless 2022-05-23T18:18:31.397429Z

I ran this

(require 'membrane.skia)
(defonce toolkit membrane.skia/toolkit)
Then the example from README

👍 1
Ben Sless 2022-05-23T18:19:02.223039Z

Let me try to clear my cpcache

phronmophobic 2022-05-23T18:20:07.735799Z

Let me double check running the example from the README. That's not how I usually run it.

Ben Sless 2022-05-23T18:21:20.249819Z

same after clearing cpcache

Ben Sless 2022-05-23T18:28:05.460089Z

anyway, I find the paths get recompiled constantly and it hits a dynamic var thing in specter which incurs a clojure.core/walk which takes forever and a half and generates more garbage than all social media combined

phronmophobic 2022-05-23T18:28:22.182819Z

impressive

Ben Sless 2022-05-23T18:28:51.517029Z

on-mouse-move 😄

Ben Sless 2022-05-23T18:29:26.175859Z

Some dark magic in defui could probably help with precompiling them

Ben Sless 2022-05-23T18:29:46.481329Z

in the end you're just emitting specter navigators, yes?

phronmophobic 2022-05-23T18:29:48.890059Z

Right, so the question is why this is slow for you, but runs well enough in clj and cljs locally

Ben Sless 2022-05-23T18:30:14.591949Z

Let me be paranoid for a second, I'll clone viscous again

phronmophobic 2022-05-23T18:30:55.447789Z

I'm not assuming that you're doing anything weird. I'm assuming membrane is doing something weird on linux

phronmophobic 2022-05-23T18:31:26.002629Z

like calling on-mouse-move several times for each event for some reason

phronmophobic 2022-05-23T18:32:04.046819Z

or having on-mouse-move trigger a redraw which triggers an on-mouse-move or something

Ben Sless 2022-05-23T18:34:25.062779Z

okay, I managed to recreate on a fresh clone

Ben Sless 2022-05-23T18:34:48.166829Z

If I do this first, then load an example, it's laggy

(require 'membrane.skia)
(defonce toolkit membrane.skia/toolkit)

Ben Sless 2022-05-23T18:34:58.494149Z

If I just load the viscous namespace it works fine

Ben Sless 2022-05-23T18:35:18.179119Z

How can I tell which toolkit was used?

phronmophobic 2022-05-23T18:35:44.575069Z

it should say if you print com.phronemophobic.viscous/toolkit

Ben Sless 2022-05-23T18:36:38.745439Z

Right, so it lags for skia and not for java2d

phronmophobic 2022-05-23T18:38:44.873749Z

ok, I have an idea. one sec

phronmophobic 2022-05-23T18:41:14.090099Z

ok, nevermind. I'm confused again

Ben Sless 2022-05-23T18:43:58.249769Z

What sort of profiling information can I get you that'll help?

Ben Sless 2022-05-23T18:45:23.944439Z

I can produce everything from JFR recording to GC and JIT logs

phronmophobic 2022-05-23T18:45:49.563329Z

I'd love to see the clojure -Stree for the project

phronmophobic 2022-05-23T18:46:04.480959Z

just to make sure that we're using the same versions of things

Ben Sless 2022-05-23T18:46:39.133929Z

org.clojure/clojure 1.10.3
  . org.clojure/spec.alpha 0.2.194
  . org.clojure/core.specs.alpha 0.2.56
com.phronemophobic.membrane/skialib-linux-x86-64 0.9.31.0-beta
com.phronemophobic/membrane 0.9.31.8-beta
  . cnuernber/dtype-next 8.041
    . org.ow2.asm/asm 9.0
    . insn/insn 0.5.2
      . org.ow2.asm/asm 9.0
    . camel-snake-kebab/camel-snake-kebab 0.4.2
    . it.unimi.dsi/fastutil 8.2.1
    . org.xerial.larray/larray-mmap 0.4.1
      . org.xerial.larray/larray-buffer 0.4.1
    . org.apache.commons/commons-math3 3.6.1
    . org.roaringbitmap/RoaringBitmap 0.9.0
      . org.roaringbitmap/shims 0.9.0
    . com.github.wendykierp/JTransforms 3.1
      X org.apache.commons/commons-math3 3.5 :older-version
      . pl.edu.icm/JLargeArrays 1.5
        X org.apache.commons/commons-math3 3.5 :older-version
    . techascent/tech.resource 5.04
      . org.clojure/tools.logging 1.1.0
    . com.google.guava/guava 30.1.1-jre
      . com.google.guava/failureaccess 1.0.1
      . com.google.guava/listenablefuture 9999.0-empty-to-avoid-conflict-with-guava
      . com.google.code.findbugs/jsr305 3.0.2
      . org.checkerframework/checker-qual 3.8.0
      . com.google.errorprone/error_prone_annotations 2.5.1
      . com.google.j2objc/j2objc-annotations 1.3
  . org.apache.commons/commons-text 1.9
    . org.apache.commons/commons-lang3 3.11
  . net.n01se/clojure-jna 1.0.0
    X net.java.dev.jna/jna 4.0.0 :older-version
  . net.java.dev.jna/jna 5.10.0
  . com.rpl/specter 1.1.3
    . riddley/riddley 0.1.12
  . org.clojure/core.async 1.4.627
    . org.clojure/tools.analyzer.jvm 1.2.0
      . org.clojure/tools.analyzer 1.1.0
      . org.clojure/core.memoize 1.0.236
        . org.clojure/core.cache 1.0.207
          . org.clojure/data.priority-map 1.0.0
      X org.ow2.asm/asm 5.2 :older-version
      . org.clojure/tools.reader 1.3.2
Now you'll tell me I'm using a bad version of skia linux

phronmophobic 2022-05-23T18:47:56.979679Z

nope, that's the latest one

phronmophobic 2022-05-23T18:48:12.573709Z

I guess it might still be bad, but if it is, there's not a better one yet

Ben Sless 2022-05-23T18:48:31.655429Z

😿

Ben Sless 2022-05-23T18:48:39.242469Z

tragic

phronmophobic 2022-05-23T18:48:41.191549Z

com.google.guava/listenablefuture 9999.0-empty-to-avoid-conflict-with-guava
😆

phronmophobic 2022-05-23T18:49:31.109289Z

So one of the things that is different is that locally, I use the monospaced Menlo font, but it should fall back to the system's monospaced if that's not available

Ben Sless 2022-05-23T18:50:22.336779Z

I doubt that's it

phronmophobic 2022-05-23T18:50:26.129669Z

however, the way to load the default monospaced font differs between java2d and skia. there's a way to do that correctly, but viscous currently does it the wrong way

Ben Sless 2022-05-23T18:50:51.732729Z

really?

Ben Sless 2022-05-23T18:52:14.625159Z

That wasn't it. Tried with a font I have installed, same

Ben Sless 2022-05-23T18:52:31.964649Z

Looks nicer, though 🙂

phronmophobic 2022-05-23T18:52:40.164169Z

and it actually use the new font? nice

Ben Sless 2022-05-23T18:52:51.194249Z

yup, Source Code Pro

Ben Sless 2022-05-23T18:52:59.046959Z

If it's going to be slow, it can at least be nice to look at

😆 1
phronmophobic 2022-05-23T18:53:28.015229Z

the spacing might be wrong since the sizes are hard-coded when the namespaces is loaded

phronmophobic 2022-05-23T18:53:30.449659Z

fonts are annoying

phronmophobic 2022-05-23T18:54:25.377239Z

ok, so there's some other difference between java2d and skia that is slowing things down a lot

Ben Sless 2022-05-23T18:54:50.582889Z

There's a reason I stay away from UI/UX. You stumble in dark, bang little toe against couch. You had an experience. You're welcome

Ben Sless 2022-05-23T18:55:21.946809Z

Yes, I can try to profile a bit, shake the Java tree, see what beans fall out

phronmophobic 2022-05-23T18:58:08.580709Z

so if I could test this locally, I would just run something like:

(require '[membrane.ui :as ui])
(require '[membrane.skia :as backend]
 ;'[membrane.java2d :as backend]
 )

(def pos (atom nil))
(defn test-mouse-move []
  (ui/on
   :mouse-move
   (fn [pos']
     (println pos)
     (reset! pos pos')
     nil)
   [(ui/with-style ::ui/style-stroke
      (ui/rectangle 400 400))
    (ui/label @pos)]))

(backend/run #'test-mouse-move)

phronmophobic 2022-05-23T18:58:15.731539Z

and see if it's doing anything weird

phronmophobic 2022-05-23T18:58:56.462369Z

see if 1) that minimal app is slow and 2) if it's printing out the same position multiple times.

Ben Sless 2022-05-23T19:01:29.505119Z

1. yes 2. no

phronmophobic 2022-05-23T19:02:11.374819Z

ok, so this isn't calling path->spec anywhere so the problem is elsewhere

Ben Sless 2022-05-23T19:05:58.798839Z

Cool

Ben Sless 2022-05-23T19:06:33.892719Z

I also added

(def ticker (java.util.concurrent.atomic.AtomicLong. 0))
(defn tick!
  ^long [^java.util.concurrent.atomic.AtomicLong n]
  (let [m (.get n)
        l (System/currentTimeMillis)]
    (.set n l)
    (- l m)))

Ben Sless 2022-05-23T19:06:46.813699Z

I get pretty constant 25ms refresh rate

Ben Sless 2022-05-23T19:07:00.707289Z

for the callback getting invoked, not the redraw

Ben Sless 2022-05-23T19:08:13.167049Z

Is it capped at 40fps?

phronmophobic 2022-05-23T19:10:21.569279Z

right now, it only redraws when there's an event. there's other ways to setup, but I think that's what it should be doing now

phronmophobic 2022-05-23T19:10:46.104119Z

40 fps isn't impressive, but it shouldn't be unusable

Ben Sless 2022-05-23T19:11:00.046729Z

okay

Ben Sless 2022-05-23T19:11:22.225199Z

It's getting a bit late so I'm tapping out for today, I'll profile it tomorrow in more detail and let you know if I found something weird

phronmophobic 2022-05-23T19:11:36.955279Z

ok, thanks again!

phronmophobic 2022-05-23T22:06:36.069419Z

fyi, I tried to reproduce locally, but it seemed to run fine. fwiw, I'm running linux inside of virtualbox so it might not be the best environment to reproduce.

phronmophobic 2022-05-24T06:14:52.597309Z

Not sure how interested you are in falling down this rabbit hole with me, so obviously, feel free to ignore. To recap, the main symptom we have is sluggish UI and key difference we have is seems to work except on some linuxs with skia. I know sluggishness is generally debugged with profiling, but there's almost no platform specific code inside of membrane. Most of the platform specific code is inside of the skia graphics library and the glfw windowing library. At this point, I'm assuming that the skia and glfw libraries are correct and that the problem is that I've written some non-portable code that uses those libraries incorrectly. I think it's much more likely that the problem is with the glfw integration rather than the skia integration. If the bug is an integration issue, profiling may or may not be that helpful. > I get pretty constant 25ms refresh rate This is pretty weird since I think the events happen on the same thread as the repaint (membrane doesn't particularly care, but I know mac OS does and I think it's the same on linux). So if events were triggering every 25ms, you would expect the screen to update regularly as well.

phronmophobic 2022-05-24T06:14:55.142869Z

Another theory is that the screen isn't being redrawn for some reason. This snippet should print on every redraw:

(require '[membrane.ui :as ui])
(require '[membrane.skia :as backend]
 ;'[membrane.java2d :as backend]
 )

(def pos (atom nil))

(defn on-draw [f]
  (ui/no-events
   (reify
     ui/IOrigin
     (-origin [elem]
       [0 0])
     ui/IBounds
     (-bounds [elem]
       [0 0])
     backend/IDraw
     (draw [this]
       (f)))))

(defn test-mouse-move []
  (ui/on
   :mouse-move
   (fn [pos']
     #_(println pos')
     (reset! pos pos')
     nil)
   [(ui/with-style ::ui/style-stroke
      (ui/rectangle 400 400))
    (on-draw #(println "draw!"))
    (ui/label @pos)]))

(backend/run #'test-mouse-move)

phronmophobic 2022-04-01T23:43:38.473889Z

@ben.sless fyi, just updated viscous on github. As long as you require membrane.skia before opening the inspector, it should use membrane.skia now.