Live data from Hacker News

Crystal: Fast as C, Slick as Ruby

blog.codeship.com

291–300 of 439 posts

Re: Crystal: Fast as C, Slick as Ruby

#291
post #278

Earlier quoted context omitted.

"GCs are complex and require lots of end-user tuning --" And they tend to be very memory hungry. Often, the memory overhead is the difference between running a program or having a bunch of browser's tabs open.

The GCs used in go or crystal tend not to eat memory more than 10% more than the peak memory of a c implementation. The perception of GC == hundreds of MBs of memory usage comes from java, where the GC aggressively preallocates, and has the memory baggage of a whole vm too. I rarely see crystal or go programs use excesses of memory.

I can't talk about Crystal and Go because the lack of experience with them. But the described issue is not only for Java (i.e I have seen it in Node too).

Since memory deallocation is not deterministic, there have to be a tradeoff between lazy scheduling (which increase memory consumption) or frequent scheduling (which has a performance overhead).

You can do a fine tuning between those variables but that means that a high performant with a low memory footprint system is a very challenging thing to make using a tracing garbage collection (the ones in Java and Node).

Re: Crystal: Fast as C, Slick as Ruby

#292
post #148

Earlier quoted context omitted.

Crystal seems to be targeted at a domain where ruby is not fast enough. That includes domains where GC is a problem. A tracing GC means that you either have to deal with potentially long GC pauses or you need a lot of extra free memory at all times to give the GC time to catch up before running out of memory [1]. Go says it can achieve 10ms max pause time using 20% of your CPU cores provided you give it 100% extra me…

For the JVM Shenandoah GC [1] can do so as well (or at least very low consistent pauses) and is available via EA builds or the OpenJDK in fedora 24 [2]. This is with pointer happy java code, not with special effort to have pointer less data. [1] http://openjdk.java.net/jeps/189 [2] https://fedoraproject.org/wiki/Changes/Shenandoah

> The key to performing concurrent evacuation is having the Java Threads and the GC threads agree on the location of objects. This is accomplished in Shenandoah by the use of a Brooks forwarding pointer. All reads by the Java Threads indirect through this forwarding pointer. All writes to objects in targeted regions must first copy the object and then write to the object in its new location.

I'm a bit surprised that indirection is efficient enough to be worth the trouble (since you need reads and writes to branch for the indirected-object case), but I can't argue with results.

Re: Crystal: Fast as C, Slick as Ruby

#293
post #8

From this post, Crystal appears to have some of the things many people have been lusting after in Rust: sophisticated metaprogramming, fewer sigils, a bigger standard library, fibers/coroutines/whatever-they're-called-now. But it still has a GC :(. Rust has completely spoiled me with making it easy to minimize dynamic memory allocation and copies, and to know (almost always) deterministically when something will go a…

The biggest problem with GC, it seems, is some sort of non-determinism that it introduces in the program's behavior. Otherwise, garbage collection, being 'lazy', is, in fact, more efficient way of releasing unused memory compared to how it is usually done in C and, especially, C++, where memory is released 'eagerly' (e.g. as part of the destructor), thus wasting precious machine cycles on something that may not be even necessary at all.

Re: Crystal: Fast as C, Slick as Ruby

#294
post #8

From this post, Crystal appears to have some of the things many people have been lusting after in Rust: sophisticated metaprogramming, fewer sigils, a bigger standard library, fibers/coroutines/whatever-they're-called-now. But it still has a GC :(. Rust has completely spoiled me with making it easy to minimize dynamic memory allocation and copies, and to know (almost always) deterministically when something will go a…

The biggest problem with GC, it seems, is some sort of non-determinism that it introduces in the program's behavior. Otherwise, garbage collection, being 'lazy', is, in fact, more efficient way of releasing unused memory compared to how it is usually done in C and, especially, C++, where memory is released 'eagerly' (e.g. as part of the destructor), thus wasting precious machine cycles on something that may not be ev…

> wasting precious machine cycles on something that may not be even necessary at all.

I'm not familiar with very many scenarios where one has a garbage collector but doesn't need to free some piece of memory when it's no longer used. Could you clarify what you mean here?

Re: Crystal: Fast as C, Slick as Ruby

#295
post #265
post #256

Earlier quoted context omitted.

> It's crazy I can't tell Java and NodeJS "use the memory you need". Define the 'memory you need'? You know the computer doesn't have a cristal ball to know what latency vs memory usage trade off you want..

"Until the OS refuses to give you more" Just like every compiled, non-GC program gets. It's annoying af to fiddle with interpreter/VM "maximum heap sizes".

Alas, "until the OS refuses to give you more" is also not a meaningful signal anymore.

https://en.wikipedia.org/wiki/Memory_overcommitment

Re: Crystal: Fast as C, Slick as Ruby

#296
post #14

Earlier quoted context omitted.

It is significantly better than undefined behaviour, as it results in a noisy failure rather than silently incorrect results. Compile-time failures are best, sure, but I'll always take an exception over what is essentially data corruption.

> It is significantly better than undefined behaviour, as it results in a noisy failure rather than silently incorrect results. This might be true in a deterministic setting, since the likelihood that a test suite will find the error is very high. But in a non-deterministic concurrent setting, throwing an exception that might be only caught once in a blue moon is just as bad as not doing anything about errors.

An occasional exception and silent corruption the rest of the time is still a lot better than silent corruption all the time - it's much easier to notice in the first place, and as long as you have one instance of the exception you have a stack trace to start from. And in practice the JVM/standard library throws ConcurrentModificationExecption pretty reliably.

Re: Crystal: Fast as C, Slick as Ruby

#297

Earlier quoted context omitted.

That's hardly any better than undefined behavior. It's not the program you want to write, under any possible circumstance, and the language should tell you so.

Pedantically, it's defined behavior, and doesn't use an interpreter lock. Granted, I'm completely head over heels for Rust, and I agree completely that ConcurrentModificationException is a crappy answer, but it is defined behavior (AFAIK).

It's not defined. The library/VM is very good at throwing ConcurrentModificationException in practice, but it's specified as a best-effort thing, not to be relied upon.

Re: Crystal: Fast as C, Slick as Ruby

#298
post #52

Earlier quoted context omitted.

Yeah it's weird how Rust has suddenly made me look for no GC languages everywhere I look. It opened up a whole new desire to not accept no for an answer in that regard. I have this burning thought in the back of my head that there just has to be a simpler way to offer it than Rust does it too.

Memory management is difficult, extremely difficult, to get correct in the way rust does. I don't think I've seen a leak or bad dereference in years. The only way it really manages this is by tying references into what amounts to a proof assistant. Every simpler method of which I can think either sacrifices capability (e.g. no references at all; only raii + copy on write) or it becomes a GC with all its wonderful tra…

> If you don't have latency, memory restrictions, or embedding requirements

Add power consumption to that list.

Re: Crystal: Fast as C, Slick as Ruby

#299
post #6

The claim is "fast as C", so I was surprised that the performance comparison was with Ruby, not with C. On my machine, the Ruby Fibonacci program executes in 47.5s, while a corresponding C program executes in 0.88s - that's a factor 54 difference, while the article reports a factor 35 for Crystal. That's good, but what causes the difference? This benchmark is pretty much all function call overhead, so I doubt it's re…

> I doubt it's representative of real performance-sensitive code

Two data points (one-off timings of a few lines of code doing the same work load) just don't make for a comparison we should spend time bothering about.

Whatever you think of the benchmarks game, I don't see why we need to waste time with comparisons that don't meet that low standard:

- a few different tasks

- more than a code snippet

- a few repeat measurements

- a few different workloads

Re: Crystal: Fast as C, Slick as Ruby

#300
post #290
post #262

Earlier quoted context omitted.

> But most likely - you simply do not need a language without a GC. Absolutely. That doesn't mean I can't want predictable performance or deterministic destruction. I also think it's a shame that we waste so much electricity and rare earth minerals on keeping ourselves from screwing up (i.e. on the overhead of managed runtimes and GCs). Before, I'd have argued that it was just necessary. Having spent a bunch of time…

The C++ advantage will not be so much after Java 10 comes out and finally have the value types and reified generics the language should have had since beginning. Also I am yet to see any large scale production deployment of those Hadoop alternatives. But it might still be like 5 years from now, so who knows how it will evolve.

Re: deployments, I expect that would take some time for a transition to occur. The first post date on the ScyllaDB blog is from February 2015 (http://www.scylladb.com/2015/02/20/seastar/), and it looks like it wasn't until September 2015 that they specifically started publishing benchmarks of the database itself as opposed to the network I/O library they built for it (http://www.scylladb.com/2015/09/22/watching_scylla_serve_1m/).

I look forward to those changes coming to Java, and I think that stack-based value types could do a lot for the language. That said, the Scylla folks seem to have gotten a lot of their performance gains from CPU/thread affinity and async I/O (http://www.scylladb.com/2016/03/18/generalist-engineer-cassa...). NIO is pretty great in Java-land, IIRC, but CPU/thread affinity is, I imagine, hard to pull off with a garbage collector.

Another thing I'm curious about w.r.t. value types in Java -- hasn't C# had those for a while? If so, and if your claim that value types will provide large performance benefits is true, why isn't C# always blowing Java away in benchmarks? Perhaps it is and I'm just not seeing them. Perhaps Java's escape analysis is already pretty good and solve the 60/70/80% case? Perhaps I'm not well versed enough in the subject to understand the interactions here.

Post reply on HN