Jump to page: 1 2
Thread overview
Re: Slow code, slow
Feb 23, 2018
H. S. Teoh
Feb 23, 2018
Rubn
Feb 26, 2018
H. S. Teoh
Feb 26, 2018
ketmar
Feb 26, 2018
ketmar
Feb 26, 2018
H. S. Teoh
Feb 26, 2018
ketmar
Feb 26, 2018
H. S. Teoh
Feb 26, 2018
ketmar
Feb 26, 2018
H. S. Teoh
Feb 26, 2018
ketmar
Feb 27, 2018
Stefan Koch
Feb 27, 2018
Stefan Koch
Feb 27, 2018
ketmar
Feb 27, 2018
ketmar
Feb 26, 2018
ketmar
Feb 26, 2018
H. S. Teoh
February 23, 2018
On Fri, Feb 23, 2018 at 08:35:44PM +0000, Rubn via Digitalmars-d wrote: [...]
> It's not that big of a slow down. Using "fast" you don't import any modules so they never have to be parsed. That's pretty much all of phobos you don't have to parse in that example. That's just the initial cost too. In a big project this won't make a difference.

Wrong.  This code was reduced from a bigger module (1600+ lines of code) containing the offending function.  If I write that function with a straight loop, the entire module compiles in about 0.4 seconds.  If I change that function to use Phobos algorithms, the compilation time slows down to more than 1 second.


> You create a tiny example that is irrelevant to the larger scale, that takes 0.3 seconds longer to compile.  It's a magnitude slower cause in your fast example it's literately only parsing 5 lines of code instead of hundreds of lines like it is in your slow example.

Please measure before you make statements like that.  You're assuming I wrote that example out of thin air, but it's actually code reduced from a larger module where changing a single function more than doubles the compilation time of the *entire module*.  Parsing is actually extremely fast, esp. with the DMD front end.  The slowdown is caused by the way the compiler handles templates (and possibly the way Phobos uses exponential templates in some places).

And this is only a smaller example of a single module.  I do have code across multiple modules that take horrendously long to compile because of heavy template use.


T

-- 
If blunt statements had a point, they wouldn't be blunt...
February 23, 2018
On Friday, 23 February 2018 at 20:52:47 UTC, H. S. Teoh wrote:
> On Fri, Feb 23, 2018 at 08:35:44PM +0000, Rubn via Digitalmars-d wrote: [...]
>> It's not that big of a slow down. Using "fast" you don't import any modules so they never have to be parsed. That's pretty much all of phobos you don't have to parse in that example. That's just the initial cost too. In a big project this won't make a difference.
>
> Wrong.  This code was reduced from a bigger module (1600+ lines of code) containing the offending function.  If I write that function with a straight loop, the entire module compiles in about 0.4 seconds.  If I change that function to use Phobos algorithms, the compilation time slows down to more than 1 second.

I don't know what else you are doing, but if you aren't using phobos or any of it's functions in there other than those few lines of code. Then yah you'll get the same result.

>> You create a tiny example that is irrelevant to the larger scale, that takes 0.3 seconds longer to compile.  It's a magnitude slower cause in your fast example it's literately only parsing 5 lines of code instead of hundreds of lines like it is in your slow example.
>
> Please measure before you make statements like that.  You're assuming I wrote that example out of thin air, but it's actually code reduced from a larger module where changing a single function more than doubles the compilation time of the *entire module*.  Parsing is actually extremely fast, esp. with the DMD front end.  The slowdown is caused by the way the compiler handles templates (and possibly the way Phobos uses exponential templates in some places).
>
> And this is only a smaller example of a single module.  I do have code across multiple modules that take horrendously long to compile because of heavy template use.
>
>
> T

I did measure it, adding another instigation of the templates using a different type adds a fraction of the time. Not another 0.3 seconds.


February 26, 2018
On Sat, Feb 24, 2018 at 09:43:35AM +0000, Stefan Koch via Digitalmars-d wrote: [...]
> This particular slowdown happens because there are somehow depdencies
> on std.format.format which is instantiated.
> Which has a ton of dependencies itself.

Aha!  That explains it.  Thanks, Stefan, for the accurate diagnosis. :-)

Now the next problem is: how to trim the fat off std.format ...


T

-- 
What is Matter, what is Mind? Never Mind, it doesn't Matter.
February 26, 2018
H. S. Teoh wrote:

> On Sat, Feb 24, 2018 at 09:43:35AM +0000, Stefan Koch via Digitalmars-d wrote:
> [...]
>> This particular slowdown happens because there are somehow depdencies
>> on std.format.format which is instantiated.
>> Which has a ton of dependencies itself.
>
> Aha!  That explains it.  Thanks, Stefan, for the accurate diagnosis. :-)
>
> Now the next problem is: how to trim the fat off std.format ...

no wai. it is just Too General to be slim. what can be done, though, is `std.format.lite` module (or something), that supports only a very small subset of "big format" features, like simply printing numbers, arrays, and unconditionally calling `.toString` on structs/classes, and a very restricted set of formatting options. that should cover alot of use cases. 'cause most of the time people only need something like `%3d %s` and such.
February 26, 2018
H. S. Teoh wrote:

> On Sat, Feb 24, 2018 at 09:43:35AM +0000, Stefan Koch via Digitalmars-d wrote:
> [...]
>> This particular slowdown happens because there are somehow depdencies
>> on std.format.format which is instantiated.
>> Which has a ton of dependencies itself.
>
> Aha!  That explains it.  Thanks, Stefan, for the accurate diagnosis. :-)
>
> Now the next problem is: how to trim the fat off std.format ...

p.s.: and ditch type safety. 'cause `foo(T...) (T args)` is a major slowdown -- it is a template. ;-)
February 26, 2018
H. S. Teoh wrote:

> On Sat, Feb 24, 2018 at 09:43:35AM +0000, Stefan Koch via Digitalmars-d wrote:
> [...]
>> This particular slowdown happens because there are somehow depdencies
>> on std.format.format which is instantiated.
>> Which has a ton of dependencies itself.
>
> Aha!  That explains it.  Thanks, Stefan, for the accurate diagnosis. :-)
>
> Now the next problem is: how to trim the fat off std.format ...

p.p.s.: or replace it with `void fmtlite (...) {}` thingy. this way we can still have type safety, but get rid of templates.
February 26, 2018
On Mon, Feb 26, 2018 at 08:38:39PM +0200, ketmar via Digitalmars-d wrote:
> H. S. Teoh wrote:
> 
> > On Sat, Feb 24, 2018 at 09:43:35AM +0000, Stefan Koch via Digitalmars-d
> > wrote:
> > [...]
> > > This particular slowdown happens because there are somehow depdencies on std.format.format which is instantiated.  Which has a ton of dependencies itself.
> > 
> > Aha!  That explains it.  Thanks, Stefan, for the accurate diagnosis. :-)
> > 
> > Now the next problem is: how to trim the fat off std.format ...
> 
> p.s.: and ditch type safety. 'cause `foo(T...) (T args)` is a major
> slowdown -- it is a template. ;-)

Actually, I think this is the classic example of why the compiler should improve the way it implements templates.

In my mind, even C's printf API is sucky, because it involves runtime parsing of what's usually a static string, over and over again. What we *really* want is for something like:

	writeln("blah %d bluh %s", i, s);

to be translated into something like:

	stdout.putString("blah ");
	stdout.putInt(i);
	stdout.putString(" bluh ");
	stdout.putString(s);

I.e., there should not be Yet Another Template with Yet Another Ridiculously Long Argument List Type Encoded In The Mangled Name, along with needless marshalling of function arguments on the stack, branching to some other part of the code (potentially causing an instruction cache miss), tons of copy-pasta for calling the same old functions for outputting strings and formatting integers, and incurring Yet Another Branch Hazard when the function finally returns.

And there should definitely be no silly runtime parsing of format strings and all of that useless dance.

The latest Phobos does support compile-time format strings, but all that does currently is to forward to the silly runtime parsing code (not to mention coming with its own baggage of additional templates to do the compile-time format string checking).

Basically, the whole stupid function call should just be completely inlined and any external template function bodies thrown out the window, because chances are you'll never call format() again with exactly the same parameters somewhere else in the code.

I haven't checked if ldc will actually do this level of inlining, but dmd certainly won't with its overly-conservative inliner.  And besides, it's a stupid waste of compiler resources to have to generate all of that template code every single time format() is called, only to have the optimizer basically undo half of the work.  There should be some way in the language to express format() in a way that doesn't involve tons of template bloat and wasted function body copy-pasta.


T

-- 
Meat: euphemism for dead animal. -- Flora
February 26, 2018
On Mon, Feb 26, 2018 at 08:42:22PM +0200, ketmar via Digitalmars-d wrote: [...]
> p.p.s.: or replace it with `void fmtlite (...) {}` thingy. this way we can still have type safety, but get rid of templates.

Given the huge amount of templates in your typical, average D code, I think it's a much more worthwhile effort to improve the way the compiler implements templates instead. :-D


T

-- 
Leather is waterproof.  Ever see a cow with an umbrella?
February 26, 2018
H. S. Teoh wrote:

> On Mon, Feb 26, 2018 at 08:38:39PM +0200, ketmar via Digitalmars-d wrote:
>> H. S. Teoh wrote:
>> 
>>> On Sat, Feb 24, 2018 at 09:43:35AM +0000, Stefan Koch via Digitalmars-d
>>> wrote:
>>> [...]
>>>> This particular slowdown happens because there are somehow
>>>> depdencies on std.format.format which is instantiated.  Which has
>>>> a ton of dependencies itself.
>>> Aha!  That explains it.  Thanks, Stefan, for the accurate diagnosis. :-)
>>> Now the next problem is: how to trim the fat off std.format ...
>> p.s.: and ditch type safety. 'cause `foo(T...) (T args)` is a major
>> slowdown -- it is a template. ;-)
>
> Actually, I think this is the classic example of why the compiler should
> improve the way it implements templates.
>
> In my mind, even C's printf API is sucky, because it involves runtime
> parsing of what's usually a static string, over and over again. What we
> *really* want is for something like:
>
> 	writeln("blah %d bluh %s", i, s);
>
> to be translated into something like:
>
> 	stdout.putString("blah ");
> 	stdout.putInt(i);
> 	stdout.putString(" bluh ");
> 	stdout.putString(s);
>
> I.e., there should not be Yet Another Template with Yet Another
> Ridiculously Long Argument List Type Encoded In The Mangled Name, along
> with needless marshalling of function arguments on the stack, branching
> to some other part of the code (potentially causing an instruction cache
> miss), tons of copy-pasta for calling the same old functions for
> outputting strings and formatting integers, and incurring Yet Another
> Branch Hazard when the function finally returns.
>
> And there should definitely be no silly runtime parsing of format
> strings and all of that useless dance.

i once wrote such thing (for fun, using "Functional Programming With Templates"). it was fun to do, and freakin' slow due to template bloat. ;-) but yes, it generates a string mixin, and in runtime there was no format string parsing.

still, we can be either smart, or have fast compile times, but not both. T_T

p.s.: oops. just found that i cannot pass structs with dtors to `(...)` functions. not fun at all.
February 26, 2018
On Mon, Feb 26, 2018 at 09:03:14PM +0200, ketmar via Digitalmars-d wrote:
> H. S. Teoh wrote:
[...]
> > In my mind, even C's printf API is sucky, because it involves runtime parsing of what's usually a static string, over and over again. What we *really* want is for something like:
> > 
> > 	writeln("blah %d bluh %s", i, s);
> > 
> > to be translated into something like:
> > 
> > 	stdout.putString("blah ");
> > 	stdout.putInt(i);
> > 	stdout.putString(" bluh ");
> > 	stdout.putString(s);
[...]
> i once wrote such thing (for fun, using "Functional Programming With
> Templates"). it was fun to do, and freakin' slow due to template
> bloat. ;-)
> but yes, it generates a string mixin, and in runtime there was no
> format string parsing.

The problem is not the Phobos implementation.  The problem is that the compiler's way of handling templates and CTFE needs to be improved.  We seriously need to muster some manpower to help Stefan finish newCTFE, and then we need to take a serious look at improving the current implementation of templates.


> still, we can be either smart, or have fast compile times, but not both. T_T
[...]

I'll like to disagree. :-D  There's got to be a way to do this that doesn't have to compromise either way.  I mean, this is not like we're doing rocket science here, or solving an NP complete problem.  It's a straightforward way of recognizing a particular code pattern and applying 1-to-1 mappings.  The general case of completely arbitrary templates can still fallback to the current implementation.  The point is to optimize for specific template usage patterns that are common and yields big speedups, but still leave the door open for weirder, but less common, template code.


T

-- 
Fact is stranger than fiction.
« First   ‹ Prev
1 2