November 17, 2021
On Wednesday, 17 November 2021 at 14:01:31 UTC, Adam D Ruppe wrote:
> On Wednesday, 17 November 2021 at 13:50:59 UTC, Ola Fosheim Grøstad wrote:
>> Your whole instance might boot on 256-512MiB.
>
> I've had no trouble running normal D on that right now.
>
> Though one thing that would be nice is this function:
>
> https://github.com/dlang/druntime/blob/master/src/core/internal/gc/os.d#L218
>
> Notice the Linux implementation....... lol.

wtf
November 17, 2021

On Wednesday, 17 November 2021 at 14:01:31 UTC, Adam D Ruppe wrote:

>

On Wednesday, 17 November 2021 at 13:50:59 UTC, Ola Fosheim Grøstad wrote:

>

Your whole instance might boot on 256-512MiB.

I've had no trouble running normal D on that right now.

Ok, but it depends on how much garbage you create. For instance if you want to process very large images on the same instance you might run into trouble. Although I guess you could preallocate a large buffer at boot and only do one image at the same time. But if you need to buffer many large data items at the same time you can run into fragmentation issues. This is not so uncommon as you often might want to cache files in memory. I guess one option here is to use weak pointers and let the GC evict items from the cache, but then we need weak pointers… Ok, can be a library type maybe, but then we are back to ownership and borrowing.

With precise collection you have some chance to reduce fragmentation. For instance if you collect when no requests are pending then you should ideally have no fragmentation. But a proper GC language can do compaction… so that is a GC advantage. D cannot really offer compaction even in theory?

I think cloud services should have a dedicated runtime.

In short: It is not so trivial if you want to offer advantages over other languages. A primitive GC, is just that, primitive.

>

https://github.com/dlang/druntime/blob/master/src/core/internal/gc/os.d#L218

Notice the Linux implementation....... lol.

Ouch. If you know the instance size I guess you also could hardcode the limit and just claim all the memory you ever want at startup.

But, I don't think web-services really is an area where D should try to be highly competitive, that is much more of a high level programming arena.

I guess some services can benefit from system level programming in 2021, but in the long run, no.

November 17, 2021
On Wednesday, 17 November 2021 at 14:39:02 UTC, Imperatorn wrote:
> On Wednesday, 17 November 2021 at 14:01:31 UTC, Adam D Ruppe wrote:
>> Notice the Linux implementation....... lol.
>
> wtf

I guess they assumed a large swap disk… :)

November 17, 2021
On Wednesday, 17 November 2021 at 14:50:49 UTC, Ola Fosheim Grøstad wrote:
> On Wednesday, 17 November 2021 at 14:39:02 UTC, Imperatorn wrote:
>> On Wednesday, 17 November 2021 at 14:01:31 UTC, Adam D Ruppe wrote:
>>> Notice the Linux implementation....... lol.
>>
>> wtf
>
> I guess they assumed a large swap disk… :)

Also why is os_physical_mem using another function which is in turn not used when checking low mem?
November 17, 2021

On Wednesday, 17 November 2021 at 13:44:39 UTC, Adam D Ruppe wrote:

>

On Wednesday, 17 November 2021 at 12:14:46 UTC, tchaloupka wrote:

>
  • it's hard to tell anyone that GC in D is fine when you look at techempower benchmark and searching the vibe-d (or anything in D) somewhere up where it should be and isn't (event other GC languages are much higher there)

I'm pretty sure you're the one who benchmarked my cgi.d and it annihilated vibe.d in that test.

Maybe it isn't the GC and vibe is just poorly written?

Yeah, that was me ;-)

In case of the techempower one problem with GC is, that it is tested on a CPU with many cores. For each of them there is one thread to manage clients (using SO_REUSEADDR/SO_REUSEPORT). There would be a problem with a stop the world GC as it would stop all of them. In case of the web server there would be better to use some allocator that just allocates as needed in a scope of currently handled request and discards all of it back on request completion. Something like this is used in nginx module implementation for example.
Or one would need to manage a set of subprocesses to avoid others to be stopped on GC collection.

But then you'll start making workarounds for the GC, start to manage memory manually here and there and then you realize that you would probably be better without the GC in the first place. Sometimes it just won't scale.

GC would also add some syscalls overhead as it uses signals, eventfd, etc.

Of course there would also be places in vibe that are suboptimal, it's not only about the GC. Maybe even fibers alone won't be as lightweight compared to rust/c++. Rust has also a stealing scheduler with waitfree/lockfree queues.

November 17, 2021

On Wednesday, 17 November 2021 at 16:03:29 UTC, tchaloupka wrote:

>

But then you'll start making workarounds for the GC, start to manage memory manually here and there and then you realize that you would probably be better without the GC in the first place. Sometimes it just won't scale.

I wonder if we could make this a bit less painful if we had a thread-local GC by default, and another global GC purely for shared memory.

So new Class() might only stop the current thread, while new shared Class() might stop the world.

November 17, 2021

On Wednesday, 17 November 2021 at 16:27:10 UTC, SealabJaster wrote:

>

I wonder if we could make this a bit less painful if we had a thread-local GC by default, and another global GC purely for shared memory.

GC should not be thread-local. It should be local to the computation. The computation has to be able to move between threads to get proper balanced load and high throughput.

The big advantage here is that for most computations you probably don't have to collect at all. You just release the heap when the computation is completed. This can be very fast if you separate objects with destructors from those without.

>

So new Class() might only stop the current thread, while new shared Class() might stop the world.

No. new Class() will:

  1. try to collect its own heap if possible

  2. try to collect the heaps of inactive pending computations if possible

  3. try to grab more memory form the OS if possible

  4. trigger a collection of the shared heap

  5. put the computation to sleep and wait for other computations to release memory

That does not help much for those that want low latency and predictable performance. You also don't want to freeze computations that do not use sharedat all, and freezing the world on new shared is not acceptable for low latency computations anyway.

You need to use RC on shared to get decent performance.

November 17, 2021

On Wednesday, 17 November 2021 at 16:47:10 UTC, Ola Fosheim Grøstad wrote:

>

The big advantage here is that for most computations you probably don't have to collect at all. You just release the heap when the computation is completed. This can be very fast if you separate objects with destructors from those without.

Interesting concept. Thanks for the detailed response.

November 17, 2021

On 11/17/21 7:14 AM, tchaloupka wrote:

>
  • have you tried to write a shared D lib used from some other language from multiple threads? I know that you must register/unregister threads in GC, but it just hasn't work for me reliably in any way and you would have to track the lifetime of the thread in the calling language - not pleasant experience at all, no tutorials of how to do that properly that actually works - it's some years old experience now so maybe something has changed
  • as GC is stop the world kind, only way to make it to not intervene with you and still use it in other places is make a thread (with a @nogc function) that is not registered in the GC and make some own mechanism to exchange data between GC and @nogc threads (as std.concurrency won't help you here)
  • GC won't magically stop the leaks. Nowadays one want's to have a long running service that just works. But try that with a 'flagship' vibe-d framework and you probably get this experience

I have to say, the second I see "How to X with DLL" in this forum, I mark as read and continue. D has a horrible story on DLLs, and it's been like that for as long as I can remember. If there is some infrastructure project that needs attention, it's DLLs. You are right that betterC and importC are useless if using D from C is nigh impossible or so difficult even the experts can't tell you the answer.

HOWEVER -- there is no excuse for the runtime hanging when a possible error is detected from a system call. Your linked discussion was not resolved how it should have been. Either the runtime should deal with that result properly, or it should crash the application completely. Not properly handling system call errors deep in the runtime is not acceptable.

If no bug has been filed on this, please do.

>

  * I don't like much when GC.stats reports something like: 239MB free from 251MB used memory that is a lot of unused space in a microservice world (and we had a cases when OS just OOM killed the service as it just grows indefinitely regardles there is a majority of free space in GC - as GC.stats says)

I believe the GC can be tuned to reduce this, as long as you haven't at one point needed that much memory at once.

However, it is worth noting that GC (in any language) generally does require more memory than manual allocation or reference counting. D does not have the ability to use a moving GC, because of the type system, which makes compacting GC impossible unfortunately.

>

    * one of the cases that caused a lot of unnecessary small allocations was something like this row["count"].as!long when reading the columns from a database. Seems like a totally normal way right? But there is much more to it. As it (dpq2 library) uses libpq internally that addresses columns by their index, it uses C method with char* column name to get it and so is using toStringz that allocates, for every single use of that column for every single row being read. You can imagine where it goes handling some complex queries on thousands of rows. And that is not something that a programmer like 'original me' wants to care about, he just wants to use the available libraries and get the work done, that is what GC should help with right?

Oof, the dpq2 library should fix that (probably malloc/free the temporary C string). Have you filed a bug on that?

>

  * there are leaks caused by druntime bugs itself (for example https://issues.dlang.org/show_bug.cgi?id=20680)

After those and some other experiences with GC I just became a bit GC phobic (I'm ok with GC for CLI tools, scripts, short running programs, no problem with that there) and try to avoid it as much as I can. But when you want to get shit done you can't write all on your own, but use the libraries that get you there with no much hassle between.

If I can separate the use cases here, using D as a main application, on a normal modern server/desktop, I have found using the GC to be a non-issue.

There are problems clearly with:

  • using D with GC as a plugin
  • using GC in a memory/resource constrained environment

Does that sound fair?

>

Overall my 2 cents on D state:

  • druntime relies too much on the GC
      * no Fiber usable in @betterC or @nogc
      * no Thread usable in @betterC or @nogc
      * etc.

I think it's more of an either-or. Using D on constrained environments likely needs a separate runtime that is catered to those environments.

I might be wrong, and a reasonable base that can deal with both is possible, but it hasn't materialized in the 14+ years that I've been using D.

>
  • no async/await - it's hard to find a modern language without it, D is one of them and there doesn't seem to be any interest in it by the leadership (it would deserve a workgroup to work on it)

This I have to disagree on, I'm not used to async/await, but I absolutely love fiber-based i/o where I don't have to deal with those (i.e. vibe-core or mecca).

There are also library solutions to it, which might be good enough, I don't know.

A good demonstration of how async/await can help D other than "because I'm used to it" would be great to see.

>

  * but I'm afraid even if it would potentially be added to the language it would still use the GC as GC is great..

This doesn't make sense, as I believe async/await in languages enables the compiler to rewrite your functions into a state machine. How it stores the state might not need GC usage, because the compiler is in control of the state creation and the state usage.

I wouldn't expect it to need more GC abilities than scope(exit) does.

>
  • pure tooling compared to others - I'm using VSCode in linux (sorry I'm lazy to learn vim in a way I'd be effective with it), it somewhat works, but code completion breaks too often for me (I'm used to it over the years, but I can imagine it doesn't look good to newcomers)

If you refer to UFCS and/or templates, I'm not sure how solvable a problem this is.

>
  • dub and code.dlang.org doesn't seems to be too official, and being cared about

It is official, it does not receive enough care.

>
  • it's hard to tell anyone that GC in D is fine when you look at techempower benchmark and searching the vibe-d (or anything in D) somewhere up where it should be and isn't (event other GC languages are much higher there)

More solid web frameworks are needed for sure. D can shine in this area, it just needs some champions for it.

>
  • I think there are 2 sorts of group in D community - one more low level that won't like to use GC much, and GC 'likers', for whom GC is just 'good enough'

There are fundamental tradeoffs that are ingrained in these choices. If you want @safe code, you need GC, some reference counting scheme, or rust-style borrow checking.

There are people who don't care about any of these, and don't care about @safe code. If you want @safe though, you have to pick one, and the GC is a perfectly good option for that.

Having the other options is a nice possibility, but I would be very much against removing the GC, or refactoring everything so I have to think about non-GC options.

>

  * I'm afraid that there can't be consensus of what D should look as those groups has different priorities and points of view

D does pretty well letting you choose a lot of things. Even the GC has some choice in it, but for sure the ecosystem for it isn't there. Most other languages don't let you make these choices.

>
  • most libraries on code.dlang.org are high level, and mostly when you want to use betterC or avoid GC, you are on your own. That is a problem when you just want to use some component and be done (if there is no C alternative or it would mean to write a more idiomatic wrapper for it).

Such is life. If you want an ecosystem built around a certain paradigm or low level design choice, you have to either create it or get others to join you in that paradigm.

D does give you the opportunity to do that, it certainly does take a lot of critical mass to do that.

-Steve

November 17, 2021
On Wednesday, 17 November 2021 at 02:32:21 UTC, H. S. Teoh wrote:
> On Wed, Nov 17, 2021 at 01:57:23AM +0000, zjh via Digitalmars-d wrote:
>> [...]
>
> Why bend over backwards to please the GC-phobic crowd?  They've already made up their minds, there's no convincing them.
>
> [...]

I 100% agree with this. There are more important things that need improvement. GC and no-GC work well enough in D (Exceptions are the only thing that needs a bit of extra work with @nogc).