January 15, 2021
On Friday, 15 January 2021 at 07:35:00 UTC, H. S. Teoh wrote:
> (1) Refactored one function called from an inner loop to reuse a buffer instead of allocating a new one each time, thus eliminating a large amount of garbage from small allocations;
> <...>
> The result was about 40-50% reduction in runtime, which is close to about a 2x speedup.

I think this message needs to be signal boosted. Most of the time GC is not the problem. The problem is sloppy memory usage. If you allocate a lot of temporary objects your performance will suffer even if you use malloc and free. If you write code that tries to use stack allocation as much as possible, doesn't copy data around, reuses buffers then it will be faster than manual memory management that doesn't do that. And thats with a "slow" GC.
January 15, 2021
On Friday, 15 January 2021 at 19:49:34 UTC, Ola Fosheim Grøstad wrote:
> On Friday, 15 January 2021 at 19:37:12 UTC, Guillaume Piolat wrote:
>> A small GC heap is sufficient.
>> There is this blog post where there was a quantitative measure of the sub-1ms D GC heap size.
>
> That's ok for a small game, but not for applications that grow over time or projects where the requirement spec is written (and continually added to) by customers. But for enthusiast projects, that can work.
>
> Many open source projects (and also some commercial ones) work ok for small datasets, but tank when you increase the dataset. So "match and mix" basically means use it for prototyping, but do-not-rely-on-it-if-you-can-avoid-it.
>
> Switching to ARC looks more attractive, scales better and the overhead is more evenly distributed. But it probably won't happen.

Isn't it more theoretical/imaginary/hypothetical than something really measured from a real-world use case? Almost all large software use cases I've seen used mix and match.

(BTW ARC is also another form of GC)

Unreal game engine https://mikelis.net/garbage-collection-in-ue4-a-high-level-overview/

Unity (of course) https://docs.unity3d.com/Manual/UnderstandingAutomaticMemoryManagement.html

> Legends have it that almost every major software project in ANY system language ends up writing custom allocators and containers.


January 15, 2021
On Friday, 15 January 2021 at 21:15:29 UTC, aberba wrote:
> On Friday, 15 January 2021 at 19:49:34 UTC, Ola Fosheim Grøstad wrote:
>> [...]
>
> Isn't it more theoretical/imaginary/hypothetical than something really measured from a real-world use case? Almost all large software use cases I've seen used mix and match.
>
> (BTW ARC is also another form of GC)
>
> Unreal game engine https://mikelis.net/garbage-collection-in-ue4-a-high-level-overview/
>
> Unity (of course) https://docs.unity3d.com/Manual/UnderstandingAutomaticMemoryManagement.html
>
>> [...]


TL;DR:

> In summation, the garbage collection system is a robust part of Unreal Engine that affords C++ programmers a lot of safety from memory leaks, as well as convenience. With this high-level discussion, I was aiming to introduce the system at a conceptual level, and I hope I have achieved that.
January 15, 2021
On Friday, 15 January 2021 at 21:15:29 UTC, aberba wrote:
> Isn't it more theoretical/imaginary/hypothetical than something really measured from a real-world use case? Almost all large software use cases I've seen used mix and match.

No?! Chrome has a garbage collector because JavaScript acquire resources in a somewhat chaotic manner, but they have fine tuned it and only call it when the call stack is short.

High quality game engines have similarly fine tuned collection, and not really a big sweeping conservative scan that lock down threads.

> (BTW ARC is also another form of GC)

By GC in this thread we speak of tracing GC. Generally, in informal contexts GC always means tracing GC, even among academics.

> Legends have it that almost every major software project in ANY system language ends up writing custom allocators and containers.

Containers certainly, allocators, sometimes. But that is not necessarily related to handling ownership. You can write your own allocator and still rely on a standard ownership mechanism.




January 15, 2021
On Fri, Jan 15, 2021 at 09:04:13PM +0000, welkam via Digitalmars-d-learn wrote:
> On Friday, 15 January 2021 at 07:35:00 UTC, H. S. Teoh wrote:
> > (1) Refactored one function called from an inner loop to reuse a
> > buffer instead of allocating a new one each time, thus eliminating a
> > large amount of garbage from small allocations;
> > <...>
> > The result was about 40-50% reduction in runtime, which is close to
> > about a 2x speedup.
> 
> I think this message needs to be signal boosted. Most of the time GC is not the problem. The problem is sloppy memory usage. If you allocate a lot of temporary objects your performance will suffer even if you use malloc and free.

As the joke goes, "you can write assembly code in any language". :-D  If you code in a sloppy way, it doesn't matter what language you write in, your program will still suck.  No amount of compiler magic will be able to help you.  The solution is not to blame this or that, it's to learn how to use what the language offers you effectively.


> If you write code that tries to use stack allocation as much as possible, doesn't copy data around, reuses buffers then it will be faster than manual memory management that doesn't do that. And thats with a "slow" GC.

And with D, it's actually easy to do this, because D gives you tools like slices and by-value structs.  Having slices backed by the GC is actually a very powerful combination that people seem to overlook: it means you can freely refer to data by slicing the buffer.  Strings being slices, as opposed to null-terminated, is a big part of this.  In C, you cannot assume anything about how the memory of a buffer is managed (unless you allocated it yourself); as a result, in typical C code strcpy's, strdup's are everywhere.  Want a substring?  You can't null-terminate the parent string without affecting code that still depends on it; solution? strdup.  Want to store a string in some persistent data structure?  You can't be sure the pointer will still be valid (or that the contents pointed to won't change); solution? strdup, or strcpy.  Want to parse a string into words?  Either you modify it in-place (e.g. strtok), invalidating any other references to it, or you have to make new allocations of every segment.  GC or no GC, this will not lead to a good place, performance-wise.

I could not have written fastcsv if I had to work under the constraints of C's null-terminated strings under manual memory management.  Well, I *could*, but it would have taken 10x the amount of effort, and the API would be 5x uglier due to the memory management paraphrenalia required to do this correctly in C.  And to support lazy range-based iteration would require a whole new set of API's in C just for that purpose.  In D, I can simply take slices of the input -- eliminating a whole bunch of copying.  And backed by the GC -- so the code doesn't have to be cluttered with memory management paraphrenalia, but can have a simple, easy-to-use API compatible across a large range of use cases. Lazy iteration comes "for free", no need to introduce an entire new API. It's a win-win.

All that's really needed is for people to be willing to drop their C/C++/Java coding habits, and write D the way it's meant to be written: with preference for stack-allocated structs and by-value semantics, using class objects only for more persistent data. Use slices for maximum buffer reuse, avoid needless copying. Use compile-time introspection to generate code statically where possible instead of needlessly recomputing stuff at runtime.  Don't fear the GC; embrace it and use it to your advantage.  If it becomes a bottleneck, refactor that part of the code.  No need to rewrite the entire project the painful way; most of the time GC performance issues are localised and have relatively simple fixes.


T

-- 
Once the bikeshed is up for painting, the rainbow won't suffice. -- Andrei Alexandrescu
January 15, 2021
On Friday, 15 January 2021 at 21:18:55 UTC, aberba wrote:
> TL;DR:
>
>> In summation, the garbage collection system is a robust part of Unreal Engine that affords C++ programmers a lot of safety from memory leaks, as well as convenience. With this high-level discussion, I was aiming to introduce the system at a conceptual level, and I hope I have achieved that.

What is your conceptual level? You haven't described what it does, and does not do. But yes, frameworks need that allow "scripting" in some shape or form (compiled or not) has to hide internal structures and intricacies and provide some convenience.

However, you write your own from scratch you can often times build the marking into an existing pass, so you get it for free. Not uncommon for people who write code that modify graphs.

There is a big difference between writing a dedicated collector for a dedicated graph, and a general ownership mechanism for the whole program.



January 15, 2021
On Friday, 15 January 2021 at 21:49:07 UTC, H. S. Teoh wrote:
> On Fri, Jan 15, 2021 at 09:04:13PM +0000, welkam via Digitalmars-d-learn wrote:
>> [...]
>
> As the joke goes, "you can write assembly code in any language". :-D  If you code in a sloppy way, it doesn't matter what language you write in, your program will still suck.  No amount of compiler magic will be able to help you.  The solution is not to blame this or that, it's to learn how to use what the language offers you effectively.
>
>
>> [...]
>
> And with D, it's actually easy to do this, because D gives you tools like slices and by-value structs.  Having slices backed by the GC is actually a very powerful combination that people seem to overlook: it means you can freely refer to data by slicing the buffer.  Strings being slices, as opposed to null-terminated, is a big part of this.  In C, you cannot assume anything about how the memory of a buffer is managed (unless you allocated it yourself); as a result, in typical C code strcpy's, strdup's are everywhere.  Want a substring?  You can't null-terminate the parent string without affecting code that still depends on it; solution? strdup.  Want to store a string in some persistent data structure?  You can't be sure the pointer will still be valid (or that the contents pointed to won't change); solution? strdup, or strcpy.  Want to parse a string into words?  Either you modify it in-place (e.g. strtok), invalidating any other references to it, or you have to make new allocations of every segment.  GC or no GC, this will not lead to a good place, performance-wise.
>
> I could not have written fastcsv if I had to work under the constraints of C's null-terminated strings under manual memory management.  Well, I *could*, but it would have taken 10x the amount of effort, and the API would be 5x uglier due to the memory management paraphrenalia required to do this correctly in C.  And to support lazy range-based iteration would require a whole new set of API's in C just for that purpose.  In D, I can simply take slices of the input -- eliminating a whole bunch of copying.  And backed by the GC -- so the code doesn't have to be cluttered with memory management paraphrenalia, but can have a simple, easy-to-use API compatible across a large range of use cases. Lazy iteration comes "for free", no need to introduce an entire new API. It's a win-win.
>
> All that's really needed is for people to be willing to drop their C/C++/Java coding habits, and write D the way it's meant to be written: with preference for stack-allocated structs and by-value semantics, using class objects only for more persistent data. Use slices for maximum buffer reuse, avoid needless copying. Use compile-time introspection to generate code statically where possible instead of needlessly recomputing stuff at runtime.  Don't fear the GC; embrace it and use it to your advantage.  If it becomes a bottleneck, refactor that part of the code.  No need to rewrite the entire project the painful way; most of the time GC performance issues are localised and have relatively simple fixes.
>
>
> T

I agree that the GC is useful, but it is a serious hindrance on the language not having an alternative other than really bad smart pointers (well written but hard to know their overhead) and malloc and free. I don't mind using the GC for my own stuff, but it's too difficult to avoid it at the moment for the times when it gets in the way.

I think the way forward is some robust move semantics and analysis like Rust. I suppose ideally we would have some kind of hidden ARC behind the scenes but I don't know how that would play with structs.

One more cynical argument for having a modern alternative is that it's a huge hindrance on the languages "cool"Ness in the next generation of programmers and awareness is everything (most people won't have heard of D)
January 15, 2021
On Friday, 15 January 2021 at 22:13:01 UTC, Max Haughton wrote:
> I think the way forward is some robust move semantics and analysis like Rust. I suppose ideally we would have some kind of hidden ARC behind the scenes but I don't know how that would play with structs.

If they are heap allocated then you just put the reference count at a negative offset (common strategy).

You need pointer types for it, but that is not a big issue if the strategy is to support both the old GC and ARC.  You basically just need to get library authors that support ARC to mark their library code in some way.


January 16, 2021
On Friday, 15 January 2021 at 19:49:34 UTC, Ola Fosheim Grøstad wrote:
>
> Many open source projects (and also some commercial ones) work ok for small datasets, but tank when you increase the dataset. So "match and mix" basically means use it for prototyping, but do-not-rely-on-it-if-you-can-avoid-it.

It's certainly true that in team dynamics, without any reward, efficiency can be victim to a tragedy of commons.

Well, any software invariant is harder to hold if the shareholders don't care.
(be it "being fast", or "being correct", or other invariants).


January 17, 2021
On Saturday, 16 January 2021 at 00:20:16 UTC, Guillaume Piolat wrote:
> It's certainly true that in team dynamics, without any reward, efficiency can be victim to a tragedy of commons.
>
> Well, any software invariant is harder to hold if the shareholders don't care.
> (be it "being fast", or "being correct", or other invariants).

Yes, although for Open Source I think the "mental model" you talked about is more of an issue. How many people working on DMD has good mental model of it? It is a bit easier for programs like Gimp that can be "plugin" style. I guess Phobos is also "plugin" style, so it is easier to improve Phobos than DMD, because of the "mental model" issue.

Maybe Open Source projects should be designed more for simple mental models (with "plugins") than for high throughput too. Maybe we can have languages that are better for Open Source by making it easier to make extensions of the software with only local impacts.

Maybe it would be better for DMD to move away from "thread local" thinking and instead have a thread pool and stackless actors. Then tie local non-incremental garbage collection to actors. Useful for application development and servers, but not so useful for audio-plugins. So, you would probably not want it...