August 31, 2021

On 8/30/21 1:15 PM, Ali Çehreli wrote:

>

On 8/30/21 8:46 AM, rikki cattermole wrote:

>

On 31/08/2021 3:34 AM, jfondren wrote:

>

That D can compile amazingly fast can be shown just by building dmd itself.

"Oh let me recompile dmd" - Stefan

A little gag from this BeerConf and yeah, it builds fast.

The following program takes 10 seconds on my computer. How is that fast? :p

import std.range;
import std.algorithm;

int main() {
  enum ret = 4_000_000.iota.sum;
  // pragma(msg, ret);
  return ret ^ ret;
}

(Of course I am joking: Replacing 'enum' with e.g. 'const' makes it fast.)

However, TIL: pragma(msg) works with 'const' variables! (At least with that one.) Replace 'enum' with 'const' and pragma(msg) computes it at compile time. But... but... 'const' doesn't really mean compile-time... Is that intended? There is some semantic confusion there. :/

initializers sometimes can be computed at compile time. If assigned to a const or immutable variable, the compiler is smart enough to know that the item hasn't changed, and so it can go back to the static initializer for what the value actually is.

what is happening here:

enum ret = 4_000_000.iota.sum;

In this case, you are requesting a compile time constant, and so it runs CTFE here to generate the result.

const ret = 4_000_000.iota.sum;

In this case, since this is inside a function, and not assiged to a global or static variable, it is generated at runtime.

pragma(msg, ret);

However, here we are requesting the value of ret at compile time. The compiler knows that since it's const, it should have the value it's initialized with. So it runs the initializer expression 4_000_000.iota.sum at compile-time, and now it has access to the value. So actually, the CTFE engine runs here instead of at ret's initialization.

If a const variable depended on an expression that could only be computed at runtime (like say with the value of an input parameter), then the pragma(msg) would NOT work.

-Steve

August 31, 2021
On 8/31/21 8:09 AM, Steven Schveighoffer wrote:

> `const ret = 4_000_000.iota.sum;`
>
> In this case, since this is inside a function, and not assiged to a
> global or static variable, it is generated at runtime.
>
> `pragma(msg, ret);`
>
> However, here we are requesting the value of `ret` at compile time. The
> compiler knows that since it's const, it should have the value it's
> initialized with.

[I change my understanding at the end of this post.]

But 'const' is not 'static const'. pragma(msg) is being extra helpful by hoping for the availability of the value. (To me, 'const' means "I promise I will not mutate", which has no relation to compile-time availability.)

> So it runs the *initializer* expression
> `4_000_000.iota.sum` at compile-time, and now it has access to the
> value. So actually, the CTFE engine runs here instead of at `ret`'s
> initialization.

It makes sense but there are two minor disturbances:

1) This is an example of "It went better than I expected".

2) Success is determined by trying.

The following program fails compilation when it gets to 'args.length' after 10 second of compilation:

import std.range;
import std.algorithm;

void main(string[] args) {
  const ret = 4_000_000.iota.sum + args.length;
  pragma(msg, ret);
}

Well, nothing is *wrong* here but concepts are muddled. But then I even more TIL that this is the same for templates:

void foo(int i)() {
}

void main() {
  const i = 42;
  foo!i();    // Compiles
}

You know... Now it feels I knew it all along because CTFE is about expressions, not variables. I need not have a "compile-time variable". Makes sense now. :)

Ali

August 31, 2021

On 8/31/21 11:44 AM, Ali Çehreli wrote:

>

On 8/31/21 8:09 AM, Steven Schveighoffer wrote:

>

const ret = 4_000_000.iota.sum;

In this case, since this is inside a function, and not assiged to a
global or static variable, it is generated at runtime.

pragma(msg, ret);

However, here we are requesting the value of ret at compile time. The
compiler knows that since it's const, it should have the value it's
initialized with.

[I change my understanding at the end of this post.]

But 'const' is not 'static const'. pragma(msg) is being extra helpful by hoping for the availability of the value. (To me, 'const' means "I promise I will not mutate", which has no relation to compile-time availability.)

What static const does is require the execution of the expression at compile time. Why? Because it needs to put that value into the data segment for the linker to use.

The compiler isn't going to do CTFE unless it has to. Because CTFE is expensive. This is why the cases where CTFE is done are explicit. But whether CTFE will work or not depends on whether the code you are executing at compile time can be executed at compile time. And that isn't decided until the expression is run.

> >

So it runs the initializer expression
4_000_000.iota.sum at compile-time, and now it has access to the
value. So actually, the CTFE engine runs here instead of at ret's
initialization.

It makes sense but there are two minor disturbances:

  1. This is an example of "It went better than I expected".

  2. Success is determined by trying.

The following program fails compilation when it gets to 'args.length' after 10 second of compilation:

import std.range;
import std.algorithm;

void main(string[] args) {
  const ret = 4_000_000.iota.sum + args.length;
  pragma(msg, ret);
}

Which actually makes sense :)

CTFE is handed an expression, which is essentially an AST branch that it needs to execute. It executes it until it can't, and then gives you the error. A CTFE error is like a runtime error, except the "runtime" is "compile time".

>

Well, nothing is wrong here but concepts are muddled. But then I even more TIL that this is the same for templates:

void foo(int i)() {
}

void main() {
  const i = 42;
  foo!i();    // Compiles
}

You know... Now it feels I knew it all along because CTFE is about expressions, not variables. I need not have a "compile-time variable". Makes sense now. :)

CTFE to me is taking the parsed tree and executing it. But only when it needs to. The only odd magic part here is, it can "See through" the variable to how it was calculated.

-Steve

September 01, 2021

On Monday, 30 August 2021 at 13:12:09 UTC, rempas wrote:

>

Just trying to compile a sample basic gtk-d project (including the libraries themselves) using ldc2 and optimization "-Os" and seeing how much time this takes, I want to ask if the benchmarks found here about ldc2 are real. Again seeing the gtk-d project taking so much time, It's hard to believe that ldc2 compiles faster that tcc and go. However, this test probably doesn't use optimizations but still.... Ayn thoughts?

LDC is based on LLVM, just like rust/zig, so it's gonna be slow

DMD is the reference compiler, it is what you should use to get fast iteration time, in fast my game with 20+k lines of code compiles in just 0.7 seconds

screenshot

https://i.imgur.com/z7vyRtX.png

I only use, and i recommand you use LDC for your release builds as LLVM has best optimizations

On windows it is a little bit slower but not that much

No matter the language, as long as you factor in templates, if you abuse them, it's gonna slow down your compile times since they need to be computer at compilation time

September 01, 2021

On Wednesday, 1 September 2021 at 22:49:59 UTC, russhy wrote:

>

On Monday, 30 August 2021 at 13:12:09 UTC, rempas wrote:

Just to be precise, 0.7 seconds for a FULL REBUILD :)

Just don't abuse templates

September 01, 2021

On Wednesday, 1 September 2021 at 22:49:59 UTC, russhy wrote:

>

On Monday, 30 August 2021 at 13:12:09 UTC, rempas wrote:

>

Just trying to compile a sample basic gtk-d project (including the libraries themselves) using ldc2 and optimization "-Os" and seeing how much time this takes, I want to ask if the benchmarks found here about ldc2 are real. Again seeing the gtk-d project taking so much time, It's hard to believe that ldc2 compiles faster that tcc and go. However, this test probably doesn't use optimizations but still.... Ayn thoughts?

LDC is based on LLVM, just like rust/zig, so it's gonna be slow

DMD is the reference compiler, it is what you should use to get fast iteration time, in fast my game with 20+k lines of code compiles in just 0.7 seconds

same with the --force dub argument ?

September 01, 2021

On Wednesday, 1 September 2021 at 23:23:16 UTC, user1234 wrote:

>

On Wednesday, 1 September 2021 at 22:49:59 UTC, russhy wrote:

>

On Monday, 30 August 2021 at 13:12:09 UTC, rempas wrote:

>

Just trying to compile a sample basic gtk-d project (including the libraries themselves) using ldc2 and optimization "-Os" and seeing how much time this takes, I want to ask if the benchmarks found here about ldc2 are real. Again seeing the gtk-d project taking so much time, It's hard to believe that ldc2 compiles faster that tcc and go. However, this test probably doesn't use optimizations but still.... Ayn thoughts?

LDC is based on LLVM, just like rust/zig, so it's gonna be slow

DMD is the reference compiler, it is what you should use to get fast iteration time, in fast my game with 20+k lines of code compiles in just 0.7 seconds

same with the --force dub argument ?

it is, i used -f

September 01, 2021

On Wednesday, 1 September 2021 at 23:37:41 UTC, russhy wrote:

>

On Wednesday, 1 September 2021 at 23:23:16 UTC, user1234 wrote:

>

On Wednesday, 1 September 2021 at 22:49:59 UTC, russhy wrote:

>

On Monday, 30 August 2021 at 13:12:09 UTC, rempas wrote:

>

Just trying to compile a sample basic gtk-d project (including the libraries themselves) using ldc2 and optimization "-Os" and seeing how much time this takes, I want to ask if the benchmarks found here about ldc2 are real. Again seeing the gtk-d project taking so much time, It's hard to believe that ldc2 compiles faster that tcc and go. However, this test probably doesn't use optimizations but still.... Ayn thoughts?

LDC is based on LLVM, just like rust/zig, so it's gonna be slow

DMD is the reference compiler, it is what you should use to get fast iteration time, in fast my game with 20+k lines of code compiles in just 0.7 seconds

same with the --force dub argument ?

it is, i used -f

On windows the same project takes 1.8 sec to fully rebuild, windows likes to make things slow.. i wonder if that's because of the linker, i don't know how to check that

September 02, 2021

On Wednesday, 1 September 2021 at 23:56:59 UTC, russhy wrote:

>

On windows the same project takes 1.8 sec to fully rebuild, windows likes to make things slow.. i wonder if that's because of the linker, i don't know how to check that

I could be wrong but Windows has antivirus hooks on file access which slow down things, additionally programs might suffer from malware checks, thus such timings.

Extra thing is dub, it invokes compiler on each build to probe the environment, spawning new process on Windows is slower than on Linux, roughly like 100ms vs 10ms on Linux.

September 02, 2021

On Wednesday, 1 September 2021 at 23:56:59 UTC, russhy wrote:

>

On Wednesday, 1 September 2021 at 23:37:41 UTC, russhy wrote:

>

On Wednesday, 1 September 2021 at 23:23:16 UTC, user1234 wrote:

>

On Wednesday, 1 September 2021 at 22:49:59 UTC, russhy wrote:

>

On Monday, 30 August 2021 at 13:12:09 UTC, rempas wrote:

>

Just trying to compile a sample basic gtk-d project (including the libraries themselves) using ldc2 and optimization "-Os" and seeing how much time this takes, I want to ask if the benchmarks found here about ldc2 are real. Again seeing the gtk-d project taking so much time, It's hard to believe that ldc2 compiles faster that tcc and go. However, this test probably doesn't use optimizations but still.... Ayn thoughts?

LDC is based on LLVM, just like rust/zig, so it's gonna be slow

DMD is the reference compiler, it is what you should use to get fast iteration time, in fast my game with 20+k lines of code compiles in just 0.7 seconds

same with the --force dub argument ?

it is, i used -f

On windows the same project takes 1.8 sec to fully rebuild, windows likes to make things slow.. i wonder if that's because of the linker, i don't know how to check that

File system access is significantly slower on Windows because of case insensitivity, Unicode and more metadata accesses per file. This overhead is far from being negligible when accessing a lot of small files (on NTFS afaicr files < than cluster size are stored inside the special directory structure requiring special operation to extract and other such oddities).