December 02, 2017
On 29 November 2017 at 03:18, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On 11/28/2017 9:27 AM, Jacob Carlborg wrote:
>>
>> Why would druntime be a barrier for you for those projects?
>
>
> When the C version is 90K and the translated D version is 1200K, it is a barrier. It's a barrier for others, as well.
>

Did you add an extra 0 here for the D version?

> Another barrier for me has turned out to be the way assert() works in D. It just is not lightweight, and it visibly slows down dmd to have assert's turned on internally. The amount of machinery involved with it in druntime is way overblown. Hence, asserts in dmd are turned off, and that wound up causing me a lot of problems recently. There are even initiatives to add writefln like formatting to asserts. With betterC, asserts became lightweight and simple again.
>

I find this assertion hard to believe (pun not intended).  Unless you
are omitting some extra check (invariant calls?), whether you are
using D's assert or C's assert, both have the same runtime cost.

> Andrei's been directing some work on using templates more in druntime to reduce this, such as Lucia's work. Martin has done some work with array ops, too.
>
> Exception handling support has been a bloat problem, too. DMC++ is built with all exceptions turned off. I've been writing PRs for dmd to greatly improve things so that it can generate similar code for RAII. (Exceptions require druntime.)
>
> BetterC is a door-opener for an awful lot of areas D has been excluded from, and requiring druntime is a barrier for that.

It's not a door opener, and druntime is not a barrier.
December 02, 2017
On 30 November 2017 at 04:29, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On 11/29/2017 7:15 PM, Jonathan M Davis wrote:
>>
>> I wouldn't have expected assertions to cost much more than however much it
>> costs to evaluate the expression being asserted unless the assertion
>> fails.
>> Now, even that can slow down a program a fair bit, depending on what's
>> being
>> asserted and how many assertions there are, but it's not something that I
>> would have expected to vary particular between C and D. It doesn't
>> surprise
>> me that the generated code would be larger than you'd get for the same
>> assertions in C because how assertions are handled when they fail is quite
>> different, but I would expect the assertions themselves to cost about the
>> same in terms of performance as long as they don't fail. What's going on
>> that's making them so much worse?
>
>
> The code *size* causes problems because it pushes the executing code out of the cache. Another issue (I should check this again) was doing null checks on member function calls, which is not necessary since if they're null it'll seg fault.
>

This is only a problem if you (dmd) are not able to move code blocks
into hot and cold paths?
December 02, 2017
On 1 December 2017 at 04:23, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On 11/30/2017 3:51 PM, Nicholas Wilson wrote:
>>
>> On Thursday, 30 November 2017 at 18:18:41 UTC, Jonathan M Davis wrote:
>>>
>>> But I have a hard time believing that the cost of assertions relates to constructing an AssertError unless the compiler is inlining a bunch of stuff at the assertion site. If that's what's happening, then it would increase the code size around assertions and potentially affect performance.
>>>
>>> - Jonathan M Davis
>>
>>
>> Indeed, if DMD is not marking the conditional call to _d_assert (or
>> whatever it is) 'cold' and the call itself `pragma(inline, false)` then it
>> needs to be changed to do so.
>
>
> Instead of speculation, let's look at what actually happens:
>
> ---------------------------------
>   void test(int i) {
>     assert(i, "message");
>   }
> ---------------------------------
> dmd -c -m64 -O test
> obj2asm -x test.obj
> ---------------------------------
>
> __a6_746573742e64:
>         db      074h,065h,073h,074h,02eh,064h,000h      ;test.d.
> __a7_6d657373616765:
>         db      06dh,065h,073h,073h,061h,067h,065h,000h ;message.
>
> _D4test4testFiZv:
> 0000:           push    RBP
> 0001:           mov     RBP,RSP
> 0004:           sub     RSP,040h
> 0008:           mov     010h[RBP],ECX
> 000b:           cmp     dword ptr 010h[RBP],0
> 000f:           jne     $+3Ah
> --- start of inserted assert failure code ---
> 0011:           mov     R8D,5                     // line number
> 0017:           lea     RAX,FLAT:_BSS[00h][RIP]
> 001e:           mov     -018h[RBP],RAX            // filename.ptr
> 0022:           mov     qword ptr -020h[RBP],6    // filename.length
> 002a:           lea     RDX,-020h[RBP]            // &filename[]
> 002e:           lea     RCX,FLAT:_BSS[00h][RIP]
> 0035:           mov     -8[RBP],RCX               // msg.ptr
> 0039:           mov     qword ptr -010h[RBP],7    // msg.length
> 0041:           lea     RCX,-010h[RBP]            // &msg[]
> 0045:           call      L0
> --- end of inserted assert failure code ---
> 004a:           mov     RSP,RBP
> 004d:           pop     RBP
> 004e:           ret
> -------------------------------------------
>

Wouldn't it be more optimal if dmd instead emitted the following?

---------------------------------

__a6_746573742e64:
        db      074h,065h,073h,074h,02eh,064h,000h      ;test.d.
__a7_6d657373616765:
        db      06dh,065h,073h,073h,061h,067h,065h,000h ;message.

_D4test4testFiZv:
0000:           push    RBP
0001:           mov     RBP,RSP
0004:           sub     RSP,040h
0008:           mov     010h[RBP],ECX
000b:           cmp     dword ptr 010h[RBP],0
000f:           je     $+3Ah               ;  <--- Using `je` instead of `jne`
0011:           mov     RSP,RBP
0014:           pop     RBP
0015:           ret
--- start of inserted assert failure code ---
...
> --- end of inserted assert failure code ---
-------------------------------------------
December 02, 2017
On 1 December 2017 at 04:23, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> 26 bytes of inserted Bloaty McBloatface code and 15 bytes of data. My proposal:
>
> _D4test4testFiZv:
> 0000:           push    RBP
> 0001:           mov     RBP,RSP
> 0004:           sub     RSP,040h
> 0008:           mov     010h[RBP],ECX
> 000b:           cmp     dword ptr 010h[RBP],0
> 000f:           jne     $+01h
> 0011:           hlt                                // look ma, 1 byte!
> 0012:           mov     RSP,RBP
> 0015:           pop     RBP
> 0016:           ret
>
> 1 byte of inserted code, and the data strings are gone as well.

But then you need to bloat your program with debug info in order to understand what, why, and how things went wrong.

Not worth it IMO.
December 02, 2017
On 12/2/2017 4:38 AM, Iain Buclaw wrote:
> But then you need to bloat your program with debug info in order to
> understand what, why, and how things went wrong.

Most of the time (for me) that isn't necessary, because the debugger still shows where it failed and that's enough.

Besides, you can always rerun the test case with a debug build.

> Not worth it IMO.

I assumed that many would feel that way, hence making it an option.

It's still better than running with NO asserts because of the bloat, which is the problem I was addressing.

December 02, 2017
On 12/2/2017 4:13 AM, Iain Buclaw wrote:
> On 29 November 2017 at 03:18, Walter Bright via Digitalmars-d
> <digitalmars-d@puremagic.com> wrote:
>> On 11/28/2017 9:27 AM, Jacob Carlborg wrote:
>>>
>>> Why would druntime be a barrier for you for those projects?
>>
>>
>> When the C version is 90K and the translated D version is 1200K, it is a
>> barrier. It's a barrier for others, as well.
>>
> 
> Did you add an extra 0 here for the D version?

No. I used the sizes for MicroEmacs in C vs MicroEmacs in D. (I translated the former into the latter.)

With BetterC, I've been able to create virtually identical binaries for C and D.


>> Another barrier for me has turned out to be the way assert() works in D. It
>> just is not lightweight, and it visibly slows down dmd to have assert's
>> turned on internally. The amount of machinery involved with it in druntime
>> is way overblown. Hence, asserts in dmd are turned off, and that wound up
>> causing me a lot of problems recently. There are even initiatives to add
>> writefln like formatting to asserts. With betterC, asserts became
>> lightweight and simple again.
> I find this assertion hard to believe (pun not intended).  Unless you
> are omitting some extra check (invariant calls?), whether you are
> using D's assert or C's assert, both have the same runtime cost.

asserts are significantly larger in D. One reason is the filename string is passed as a D string, which is 2 pushes. A C string is one push.

Consider that D asserts throw an exception. Where's the catch going to be, if you're linking the D code into a C program? And the D personality function, needed for D exception unwinding, is in druntime.


>> BetterC is a door-opener for an awful lot of areas D has been excluded from,
>> and requiring druntime is a barrier for that.
> It's not a door opener, and druntime is not a barrier.

If you have a C program, and want to add a D function to it, you really don't want to add druntime as well. BetterC enables people to provide D addon libraries for people who have C main programs.

There's a point to making incremental use of D as low cost as possible.

December 03, 2017
On Saturday, 2 December 2017 at 23:44:39 UTC, Walter Bright wrote:
> On 12/2/2017 4:38 AM, Iain Buclaw wrote:
>> But then you need to bloat your program with debug info in order to
>> understand what, why, and how things went wrong.
>
> Most of the time (for me) that isn't necessary, because the debugger still shows where it failed and that's enough.
>
> Besides, you can always rerun the test case with a debug build.

+1
To me, the current D assert is useless, and I prefer to use a C-like equivalent, that "crash" the program without unwinding the stack. Then I can inspect the cause of the crash on a debugger, with access to the current context (variable contents, etc.), is it from a (core file) or by running the program on the debugger. That way I do find the bug(s) much faster.  More generally treating errors (ie bugs) as unrecoverable exceptions is a mistake in IMHO. I prefer a call to the C function abort() that leaves the context intact.

December 03, 2017
On Saturday, 2 December 2017 at 23:44:39 UTC, Walter Bright wrote:
> On 12/2/2017 4:38 AM, Iain Buclaw wrote:
>> But then you need to bloat your program with debug info in order to
>> understand what, why, and how things went wrong.
>
> Most of the time (for me) that isn't necessary, because the debugger still shows where it failed and that's enough.
>
> Besides, you can always rerun the test case with a debug build.

Ehm, if it’s a simple reproducable tool.
Good luck debugging servers like that.


December 03, 2017
On 2017-12-03 08:29, Richard Delorme wrote:

> +1
> To me, the current D assert is useless, and I prefer to use a C-like equivalent, that "crash" the program without unwinding the stack. Then I can inspect the cause of the crash on a debugger, with access to the current context (variable contents, etc.), is it from a (core file) or by running the program on the debugger.

Ideally druntime should identify if it's running inside a debugger and adapt accordingly.

-- 
/Jacob Carlborg
December 03, 2017
On 11/30/2017 7:43 PM, Adam D. Ruppe wrote:
> int 3, on the other hand, is explicitly for debugging - which is what we want asserts to be.

https://github.com/dlang/dmd/pull/7391