Live data from Hacker News

4x Smaller, 50x Faster

blog.asciinema.org

191–200 of 205 posts

Re: 4x Smaller, 50x Faster

#191

Earlier quoted context omitted.

This part... > for the high frame-rate, heavy animations this puts a lot of pressure on CPU and memory ...does seem to suggest that the "garbage multiplier" effect of immutability is an ill fit for applications that also create a lot of garbage naturally. Note that this is about as close to an apples-to-apples comparison as we're likely to get - the same application implemented two different ways - so it's not the ap…

Clojure developers are not unaware of the tradeoffs between immutable and mutable data structures. You'll see them use mutable data structures, particularly in tight loops inside functions that take immutable inputs, mutate them, and produce immutable outputs (thereby preserving the promise of immutability, while leveraging the performance of mutability internally). You'll rarely see apps designed like this up-front…

Not being too familiar with Clojure, but being familiar with Erlang, I'm curious whether Clojure has any popular libraries that approach efficient mutability the way the Erlang runtime does.

The Erlang runtime exposes complex mutable resources like ETS tables through opaque handles, where the handle can be freely shared, but the resource backing the handle can never actually be touched by "clients." Instead, the resource backing the handle lives in its own heap, which is owned by a manager object; and accesses to the resources in that heap are done by handing the manager references to data that it then copies into the heap; or querying it by handing it a reference to a key, whereupon the manager will copy data back out and return it.

It's not really the same abstraction as e.g. a Concurrent container-class in the Java stdlib, as it's not implemented through the client ever acquiring (the moral equivalent of) a mutex and then touching the data itself; nor does it involve the client adding object references to an atomic queue, where some async process then weaves those references into the backing object. Neither the client's execution-thread, nor its passed-in data, ever touches the handle's backing data.

Instead, ETS and the like have guarantees almost as if the mutable resources they hold were living in a separate OS process (similar to e.g. data in a nearby Redis instance), where you need to "view" and "update" the resources living in that separate process through commands issued to that server, over a socket, using a wire protocol; where that serialization over the socket guarantees that the data reaching the other end is a copy of your client-owned data, rather than a shared-memory representation of it. The same semantics, but without the actual overhead of serialization or kernel context-switching, because the "other end" is still inside the managed runtime of your OS process.

And, to be clear, Erlang ETS accesses aren't linearized by a "message inbox" queue sitting in-between, the way that regular Erlang inter-actor message-passing is. The ETS table manager can handle multiple concurrent requests to the same table, from different processes, simultaneously, without locking the whole table—just like an RDBMS would. (Instead, it uses row-batch locks for writes, like RDBMSes do.) The concurrency strategy is a concern internal to each particular black-box-with-a-handle, rather than something general to the abstraction. The only thing guaranteed by the black-box-with-a-handle abstraction, is that nobody can mutate the data "inside" the black box without its manager's knowledge, because nobody ever holds a live reference to the data "inside" the black box.

Re: 4x Smaller, 50x Faster

#192
post #189
post #32

Earlier quoted context omitted.

What a boring takeaway from this. Beyond the fact that the immutable data structures proposed by Clojure/script tend to perform very well in a lot of "normal" cases (and in a lot of normal web-app workflows your stuff is immutable, like "query then display the result from an API"), at least to me it feels like asciinema is a very good example of a case where you have tougher-than-average performance requirements. Not…

On the other hand, rewriting the DBMS itself in Rust might. Especially if the DBMS was originally written in Clojure (see: Datomic.)

I'm not Datomic's biggest fan, but you know it's a hosted database with multiple backends, right? A lot of the heavy lifting is delegated to storage like DynamoDB or Postgres.

Re: 4x Smaller, 50x Faster

#193

Earlier quoted context omitted.

I just wonder why not just write straight JS? Adding a layer on top just means you have more complexities and steps to worry about. And clearly, in this case it was a big compromise in terms of performance and bundle size.

Yep, the author learnt their lesson. I bet they won't be using cljs again, not even for non-performant apps.

Perhaps, you should ask a question, why didn't the author reverse the question? Something like "How on earth was my implementation in a JITed language 50x slower on a warmed-up benchmark?" Where is the output of the profiler showing the exact bottlenecks? Of course, you can look at the repo and deduce some stuff, but it is a good habit to mention some key points about the environment such as compiler/ language/ browser versions, compiler settings, the hardware used etc.

Could he use more appropriate data structures? Could he avoid all the schema stuff that doesn't really improve the readability? Could he use better data structures later avoiding slow functions like update-in and migrating the bottlenecks to transducers and transients perhaps?

The author just did a rewrite and that is totally ok. He is trying things out and that is also quite alright. He provided some rather high-level benchmarks that would be really time consuming the reproduce and explain in more detail.

We have looked at the cljs code (e.g. https://github.com/asciinema/vt-clj/blob/master/src/asciinem...) with my colleague and it definitely isn't the best possible Clojure(Script) code around from a readability nor it seems performance standpoint.

To summarize, good that @sickill got a discussion going but it is best to step back and think about it in more depth. We all should apply more of this "extraordinary claims require extraordinary evidence" https://en.wikipedia.org/wiki/Sagan_standard Yes, it is his free time and good explanations/ understanding take time. We should treat the blog entry accordingly. It is a good exercise in critical thinking and code review, if you actually take the time to at least run through the code briefly.

Re: 4x Smaller, 50x Faster

#194
post #183

Earlier quoted context omitted.

Yes they did, maybe take a look at the repo, the core vt layer is rust everything around it is in js(it's not cljs, you might ponder why not).

Well sure, but the important parts aren’t in JS. I can understand the argument that to provide npm library you may need to touch that garbage of a language, I’m just happy others do it for me.

The entire project used to be cljs, so obviously it's done on purpose, that is stated in the article.

Re: 4x Smaller, 50x Faster

#195

Earlier quoted context omitted.

Yep, the author learnt their lesson. I bet they won't be using cljs again, not even for non-performant apps.

Perhaps, you should ask a question, why didn't the author reverse the question? Something like "How on earth was my implementation in a JITed language 50x slower on a warmed-up benchmark?" Where is the output of the profiler showing the exact bottlenecks? Of course, you can look at the repo and deduce some stuff, but it is a good habit to mention some key points about the environment such as compiler/ language/ brows…

Performance was not his only pain point. He also had issues integrating with the JS ecosystem. IMO Clojurescript is not worth extra layer of complexity.

Re: 4x Smaller, 50x Faster

#196
post #194

Earlier quoted context omitted.

Well sure, but the important parts aren’t in JS. I can understand the argument that to provide npm library you may need to touch that garbage of a language, I’m just happy others do it for me.

The entire project used to be cljs, so obviously it's done on purpose, that is stated in the article.

what is done on purpose?

Re: 4x Smaller, 50x Faster

#197
post #46

Earlier quoted context omitted.

Won't make them slower, anyway. There are often performance bottlenecks you didn't know about, and had blamed on database (or whatever) interaction overhead. It will never feel worthwhile to dig into each candidate, because any payback seems too unlikely. Not having left scope for such bottlenecks means you can be confident they are not there. Re-implementing once is a lot less work than diving into each possible bot…

"Any optimization you could do in Rust is probably easier in C++" I think this feeling comes from the fact that it takes longer to learn the basics of Rust compared to C++. However, once one has learned C++ or Rust to a reasonable level, I would argue that Rust is actually easier to use. This is not the same thing but many people make this claim.

> it takes longer to learn the basics of Rust compared to C++.

Does it really? For example I'd think that initialization of objects is a topic that should be in "basics", yet initialization of objects in C++ seems disproportionately complex compared to Rust (at least to me).

Re: 4x Smaller, 50x Faster

#198

Earlier quoted context omitted.

Perhaps, you should ask a question, why didn't the author reverse the question? Something like "How on earth was my implementation in a JITed language 50x slower on a warmed-up benchmark?" Where is the output of the profiler showing the exact bottlenecks? Of course, you can look at the repo and deduce some stuff, but it is a good habit to mention some key points about the environment such as compiler/ language/ brows…

Performance was not his only pain point. He also had issues integrating with the JS ecosystem. IMO Clojurescript is not worth extra layer of complexity.

We are using shadow-cljs https://github.com/thheller/shadow-cljs and that integrates with npm just fine. It doesn't get much easier than that I guess and if you have trouble, you can contact Thomas Heller or other people on the Clojurians Slack-channel.

If I did any app or system, that could be written in Java or JavaScript (browser or Node.js) I would take Clojure or ClojureScript any day. I don't know how to match the comfort and power in a different language. If it turned out e.g. by using a profiler, I just need way better performance in some bottlenecks and after I have exhausted all options that a) a better algorithm b) better technology/ different approach such as Canvas/ WebGL you name it in addition to what Clojure(Script) performance features offer, I would perhaps consider learning to write a module in Rust/ WebAssembly or just use a bit more resources (if this was e.g. a money problem).

Besides embedded, really high-performance stuff, some parts of the infrastructure that need to be as efficient as possible or run without GC or need to talk to very special interfaces or a library, Clojure and ClojureScript or related dialects/ implementations are suited for pretty much everything else I can think of.

We should be thinking about how to implement a Clojure-like language in more places, perhaps even without a GC but with AOT compilation + interpreter for the REPL along the way of Babashka. We should explore how to have a REPL to multiple systems at once and handle them like it was a single machine to some degree. We should be thinking, how to make a running Clojure program interruptible easily (perhaps with an extra setting), like it was a program in the shell. We should think about adding a Clojure-like language to the browser natively so that programs don't have to load it like they do now and that a browser tab could have some kind of REPL that you could authenticate and connect to over a socket. That way, you could rewrite the code of the web app at runtime if allowed by the user. And we definitely should design more APIs in much simpler way working more with data and less with invoking some specific functions. E.g. browser "history" could just be a vector/ array of maps/ objects or whatever instead of some finicky getters and setters that obscure the problem and are just another thing you have to learn to do useful work.

Re: 4x Smaller, 50x Faster

#199
post #163

Earlier quoted context omitted.

> "Ruby and Python interpreters are slow but webapps are IO bound anyway so it doesn't matter" to "how can I get this to handle more than x req/sec, can we get a JIT to speed up our dog slow backend" Turns out that if you write business logic with abandon, you end up with a lot of business logic. Personally I wish that Python, Ruby and the ilk all get replaced with Lua, but also that Lua gets a proper `null`.

and array numbering from zero

No idea why this bothers people so much. How often are you manually indexing into an array with numeric literals?

Re: 4x Smaller, 50x Faster

#200

Earlier quoted context omitted.

Feel free to report a bug here https://github.com/asciinema/asciinema-player/issues/new (including browser version, OS would help a lot). Btw, it's not a product, just a side, hobby project of mine.

Ohhh weird, I thought it was a literal mp4 on the front page haha. Must be one of my browser extensions messing with it!

Ohhh this makes a lot of sense to me now too, I also thought it was an mp4 until reading your comment and thought you were totally insane to have "watched the video" wrong lol. I see now it's an animated terminal rendering via HTML elements, very cool
Post reply on HN