January 05, 2019
On Sat, Jan 5, 2019 at 7:45 PM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 1/5/2019 2:05 PM, Manu wrote:
> > How much truth is in here?
>
> There's a lot of triggering on the word "GC". At some level, it doesn't matter how good or bad the GC is, it's "GC is bad". Even if your code never calls the GC.
>
>
> > What is this business about write barriers making the GC fast? Is that actually fact, or are there other hurdles?
>
> Here's an explanation:
>
> https://stackoverflow.com/questions/19154607/how-actually-card-table-and-writer-barrier-works
>
> There are many more if you google "gc write barrier".
>
> The penalty, of course, is extra code gets run for every write through a pointer.
>
> The benefits exceed the penalties for a language where all dynamic allocation is done via the GC. But for D, where quite a lot of it is not, it isn't so clear. What is clear is that if you're going to compare speed with C++, having those write barriers in there is going to be a serious penalty, because they'll be there even if you don't use the GC.
>
>  > Where's the ARC stuff? What happened to opAddRef/opRelease?
>
> Andrei, Razvan, and I have decided that the most pragmatic way forward to support reference counting is to support copy constructors ala C++. C++ is clearly successful with this approach, and Andrei/Razvan concluded that D's postblit just doesn't cut it. Razvan has a proposal for copy constructors, and an implementation PR that has fallen a bit behind his latest proposal.

Hmnm, that's pretty disappointing... as a C++ user who has been doing
C++ ref counting for years, I would say that, while maybe it is
*kinda* successful, it's not at all satisfying, and it's one major
reason I've been pushing it in D for the last 8-9 years.
Ref counting in C++ is a sloppy hack. I really just want the compiler
to emit opInc and opDec appropriately on either sides of a reference
assignment, and let me take it from there.
Also, with escape analysis, we can elide such calls very effectively,
and we can't do that using the C++ strategy.

I think it's disappointing to embrace C++'s hacky 'solution', we could do better.
January 05, 2019
On Sat, Jan 5, 2019 at 10:55 PM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 1/5/2019 8:52 PM, Neia Neutuladh wrote:
> > The only other way I know of to implement a write barrier is to insert some code on every pointer write. GC-as-a-library would require you to use their pointer type instead of the builtin, and I expect most C++ devs would rather just use a reference counting pointer type instead.
>
> Microsoft tried this with their "Managed C++" variant of C++, where they had two fundamental pointer types. It was a laudable effort, but failed to gain traction. D learns from that mistake :-)

I was very much 'there' when this was rejected by the community. I
don't think it 'failed to gain traction' despite trying, so much as it
was just plain rejected or dismissed.
And not for any particularly good reason. It went like this among the
~hundreds of programmers I interacted with at the time.
1. "Managed C++" is code for "lame C#", or just "C# interop layer"
2. C++ users want absolutely nothing to do with C#, and nothing to do
with the word 'managed'
3. C# users want absolutely nothing to do with C++
4. The feature didn't stand alone as a C++ feature
5. Even if it did, it was limited to windows, and to MS compilers.
Completely not-portable.

It's obvious why it failed. I don't think comment on the merit of the
design has any relevance at all to that particular story.
The particulars of the design and whether it was good or not couldn't
have had less affect on the feature being ignored and/or rejected.

> > Either the speed has improved, or they're just eating the time cost.
>
> The fact that Java/Go/etc. use inserted write gates suggest the speed hasn't improved, which leaves eating the cost.

Could D insert such code, and also effectively elide it where @nogc is
used (or inferred)?
If we can help the GC in common code, but still have the expressive
power we need to elide that extra work where we know it's not
necessary, then it might be reasonable to consider.
January 06, 2019
On 1/5/2019 11:58 PM, Manu wrote:
> I was very much 'there' when this was rejected by the community. I
> don't think it 'failed to gain traction' despite trying, so much as it
> was just plain rejected or dismissed.
> And not for any particularly good reason. It went like this among the
> ~hundreds of programmers I interacted with at the time.
> 1. "Managed C++" is code for "lame C#", or just "C# interop layer"
> 2. C++ users want absolutely nothing to do with C#, and nothing to do
> with the word 'managed'
> 3. C# users want absolutely nothing to do with C++
> 4. The feature didn't stand alone as a C++ feature
> 5. Even if it did, it was limited to windows, and to MS compilers.
> Completely not-portable.

I had a lot of experience with multiple pointer types from the DOS world. While it works, it is a constant headache. With every .. single .. pointer one had to decide near*? far*? ss*? cs*? huge*? and Zortech's vptr*? and of course every .. single .. data .. structure had the same issues, and no, they could not interoperate.

Programmers (myself included) were very happy to abandon that way of doing things.


> It's obvious why it failed. I don't think comment on the merit of the
> design has any relevance at all to that particular story.
> The particulars of the design and whether it was good or not couldn't
> have had less affect on the feature being ignored and/or rejected.

It had a large effect in my experience. I'm an expert on near/far/etc, and I don't miss it like I don't miss EBCDIC. I was kinda glad to see Managed C++ fail, so I wouldn't get any pressure to implement it.

(I also recall programmers looking at it, and respond "two kinds of pointers? Blech." Not just me.)


>>> Either the speed has improved, or they're just eating the time cost.
>>
>> The fact that Java/Go/etc. use inserted write gates suggest the speed hasn't
>> improved, which leaves eating the cost.
> 
> Could D insert such code, and also effectively elide it where @nogc is
> used (or inferred)?

@nogc code means no allocations happen, not that there are no pointers to the gc in the code. It's orthogonal.


> If we can help the GC in common code, but still have the expressive
> power we need to elide that extra work where we know it's not
> necessary, then it might be reasonable to consider.

If we could do that, we wouldn't need GC, the compiler could figure out the last use of each pointer. With all the research into GCs, nobody has ever figured that out.

January 06, 2019
On 1/5/2019 11:48 PM, Manu wrote:
> Hmnm, that's pretty disappointing... as a C++ user who has been doing
> C++ ref counting for years, I would say that, while maybe it is
> *kinda* successful, it's not at all satisfying, and it's one major
> reason I've been pushing it in D for the last 8-9 years.
> Ref counting in C++ is a sloppy hack. I really just want the compiler
> to emit opInc and opDec appropriately on either sides of a reference
> assignment, and let me take it from there.
> Also, with escape analysis, we can elide such calls very effectively,
> and we can't do that using the C++ strategy.
> 
> I think it's disappointing to embrace C++'s hacky 'solution', we could
> do better.

So far, we've failed at every attempt at it.

January 06, 2019
On Sun, Jan 6, 2019 at 12:55 AM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> > It's obvious why it failed. I don't think comment on the merit of the
> > design has any relevance at all to that particular story.
> > The particulars of the design and whether it was good or not couldn't
> > have had less affect on the feature being ignored and/or rejected.
>
> It had a large effect in my experience. I'm an expert on near/far/etc, and I don't miss it like I don't miss EBCDIC. I was kinda glad to see Managed C++ fail, so I wouldn't get any pressure to implement it.
>
> (I also recall programmers looking at it, and respond "two kinds of pointers?
> Blech." Not just me.)

But now we have heaps of pointers... just that they have ugly names.
Now we have std::unique_ptr<T>, std::shared_ptr<T>, std::auto_ptr<T>,
std::weak_ptr<T>
These are all just as equally 'multiple kinds of pointers' as `T^` was
for ARC pointers, except they have hideous names, instead of a nice
concise 1-byte syntax.

It's all irrelevant though, Nobody's asking for multiple pointer types
in D. All I want from language support for ARC in D, is an opInc/opDec
function which are called appropriately around assignments, and elided
appropriately.
copy ctor's can't offer this functionality.
January 06, 2019
On Sun, Jan 6, 2019 at 1:25 AM Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 1/5/2019 11:48 PM, Manu wrote:
> > Hmnm, that's pretty disappointing... as a C++ user who has been doing
> > C++ ref counting for years, I would say that, while maybe it is
> > *kinda* successful, it's not at all satisfying, and it's one major
> > reason I've been pushing it in D for the last 8-9 years.
> > Ref counting in C++ is a sloppy hack. I really just want the compiler
> > to emit opInc and opDec appropriately on either sides of a reference
> > assignment, and let me take it from there.
> > Also, with escape analysis, we can elide such calls very effectively,
> > and we can't do that using the C++ strategy.
> >
> > I think it's disappointing to embrace C++'s hacky 'solution', we could do better.
>
> So far, we've failed at every attempt at it.

Why did opInc/opDec fail? It was never available in any experimental form, I was never able to try it out. I've been waiting eagerly for almost a decade...
January 06, 2019
On Sat, 2019-01-05 at 22:54 -0800, Walter Bright via Digitalmars-d wrote: […]
> The fact that Java/Go/etc. use inserted write gates suggest the speed
> hasn't
> improved, which leaves eating the cost.
[…]

Java GC continues to change and improve in leaps and bounds, both speed and latency. And indeed a lack of "stop the world time". The G1 GC that was seen as the very best there could be two Java versions ago has been surpassed again with Shenandoah. JVM GC people just keep coming up with ways of killing off GC cost.

-- 
Russel.
===========================================
Dr Russel Winder      t: +44 20 7585 2200
41 Buckmaster Road    m: +44 7770 465 077
London SW11 1EN, UK   w: www.russel.org.uk



January 06, 2019
On Sunday, 6 January 2019 at 09:40:25 UTC, Manu wrote:

> But now we have heaps of pointers... just that they have ugly names.
> Now we have std::unique_ptr<T>, std::shared_ptr<T>, std::auto_ptr<T>,
> std::weak_ptr<T>
> These are all just as equally 'multiple kinds of pointers' as `T^` was
> for ARC pointers, except they have hideous names, instead of a nice
> concise 1-byte syntax.

Not much to add to this discussion other than "Where's my ARC???"

But, the impression I got from digging around UWP code for Quantum Break is that T^ is just syntactic sugar for a COM pointer. So C++ Windows programmers have had different types of pointers for much longer than C++11.

If Microsoft had just come out and said "They're COM pointers" there'd have been far less gnashing of teeth.
January 06, 2019
On Saturday, 5 January 2019 at 22:05:19 UTC, Manu wrote:
> How much truth is in here?

The truth of oft-repeated mantras?

http://www.infognition.com/blog/2014/the_real_problem_with_gc_in_d.html taught us how small our heap should be to keep performance.

The situation has improved since with -betterC, -profile=gc, allocators, @nogc. Piece of knowledge too (avoid void[]).

The D GC doesn't seem to stop people from implementing fast systems.
When we disabled GC completely and went completely manual, we got zero speed improvement, only memory usage decrease. GC is surprinsingly affordable.
January 06, 2019
On Sat, 05 Jan 2019 23:58:55 -0800, Manu wrote:
> Could D insert such code, and also effectively elide it where @nogc is
> used (or inferred)?

Write barriers are how the GC maintains the graph of which memory points to which other memory, so it is very difficult to avoid them.

You don't need to include them for writes to non-pointers. For injected runtime calls, this means any non-pointer. For mprotect(), it means the entire block of memory must be pointer-free.

You could use @nogc as a means to prove that you don't have to call the "pointer was written" code multiple times for the same address. The compiler has to prove that it's the same address, that no other thread could have written to that data, and that the GC couldn't have run in between. But D as is can't prove any of that.