View mode: basic / threaded / horizontal-split · Log in · Help
September 22, 2012
Re: Review of Andrei's std.benchmark
On 2012-09-21 21:59, Andrei Alexandrescu wrote:

> I think you have discovered a major issue. Ideas on how to attack this?

The standard way to solve this would be to move the initialization code 
from a static constructor to a function what will be called and do the 
initialization lazy. But since this several layers of string mixins what 
will make it more complicated.

Can you give a short example of how the mixed in code will look like?

-- 
/Jacob Carlborg
September 22, 2012
Re: Review of Andrei's std.benchmark
On Friday, 21 September 2012 at 20:43:13 UTC, Jonathan M Davis 
wrote:
> On Friday, September 21, 2012 15:59:31 Andrei Alexandrescu 
> wrote:
>> On 9/19/12 4:11 PM, "Øivind" wrote:
>> > New question for you :)
>> > 
>> > To register benchmarks, the 'scheduleForBenchmarking' mixin 
>> > inserts a
>> > shared static initializer into the module. If I have a 
>> > module A and a
>> > module B, that both depend on eachother, than this will 
>> > probably not
>> > work..? The runtime will detect the init cycle and fail with 
>> > the
>> > following error:
>> > 
>> > "Cycle detected between modules with ctors/dtors"
>> > 
>> > Or am I wrong now?
>> 
>> I think you have discovered a major issue. Ideas on how to 
>> attack this?
>
> Some of us have been asking for ages for the ability to mark a 
> static
> constructor as not depending on anything so that the runtime 
> _doesn't_ think
> that there's a circular dependency, but Walter has been against 
> the idea when
> it's been brought up. That would _really_ help here.
>
> Without redesigning std.benchmark so that it doesn't use static 
> constructors,
> I don't know how you can fix that. Normally, if you really need 
> a static
> constructor, you go through the pain of creating a separate 
> module which does
> the initialization for you (like std.stdio does). But that 
> won't work in this
> case, because you're mixing it in. So, unless you can redesign 
> it so that
> std.benchmark doesn't require static constructors, it may have 
> to be a
> limitation of std.benchmark that it can't be used where it 
> would create a
> circular dependency.
>
> Unfortunately, the circular dependency issue makes static 
> constructors almost
> useless outside of isolated cases, even though they rarely 
> actually have
> circular dependencies. It's one of the few places in D that I'd 
> say that
> there's a major design flaw.
>
> - Jonathan M Davis


Is there a way to solve the dependency issue without forbidding 
static constructors in modules with cyclic dependencies?

I.e. for two modules with static init referencing eachother, an 
analysis of the static init code could be used to detect circular 
dependencies instead of the import statements?
September 22, 2012
Re: Review of Andrei's std.benchmark
On 9/22/12 8:28 AM, "Øivind" wrote:
> Is there a way to solve the dependency issue without forbidding static
> constructors in modules with cyclic dependencies?

I think an idea just occurred to me. The rules for static ctors and 
dtors were invented before "import" was allowed inside a scope. We could 
have taken advantage of that.

Say we restrict symbol visibility inside static cdtors to ONLY symbols 
within the current module. If some static cdtor needs a symbol from a 
different module, it must import it explicitly (even if the current 
module already imports it).

In this setup it should be possible to compute, in a fine-grained 
manner, the dependencies of static cdtors.

Unfortunately that would be a breaking change.


Andrei
September 22, 2012
Re: Review of Andrei's std.benchmark
On Saturday, 22 September 2012 at 13:03:06 UTC, Andrei 
Alexandrescu wrote:
> On 9/22/12 8:28 AM, "Øivind" wrote:
>> Is there a way to solve the dependency issue without 
>> forbidding static
>> constructors in modules with cyclic dependencies?
>
> I think an idea just occurred to me. The rules for static ctors 
> and dtors were invented before "import" was allowed inside a 
> scope. We could have taken advantage of that.
>
> Say we restrict symbol visibility inside static cdtors to ONLY 
> symbols within the current module. If some static cdtor needs a 
> symbol from a different module, it must import it explicitly 
> (even if the current module already imports it).
>
> In this setup it should be possible to compute, in a 
> fine-grained manner, the dependencies of static cdtors.
>
> Unfortunately that would be a breaking change.
>
>
> Andrei

It gets a bit ugly maybe, but we could do a mix of the proposals 
that have come before and this one, e.g. add a @nocycliccheck (or 
similar) to the static constructor,  and in that case only allow 
access to current module and those imorted inside the ctor scope..
September 22, 2012
Re: Review of Andrei's std.benchmark
On Saturday, 22 September 2012 at 13:25:47 UTC, Øivind wrote:
> On Saturday, 22 September 2012 at 13:03:06 UTC, Andrei 
> Alexandrescu wrote:
>> On 9/22/12 8:28 AM, "Øivind" wrote:
>>> Is there a way to solve the dependency issue without 
>>> forbidding static
>>> constructors in modules with cyclic dependencies?
>>
>> I think an idea just occurred to me. The rules for static 
>> ctors and dtors were invented before "import" was allowed 
>> inside a scope. We could have taken advantage of that.
>>
>> Say we restrict symbol visibility inside static cdtors to ONLY 
>> symbols within the current module. If some static cdtor needs 
>> a symbol from a different module, it must import it explicitly 
>> (even if the current module already imports it).
>>
>> In this setup it should be possible to compute, in a 
>> fine-grained manner, the dependencies of static cdtors.
>>
>> Unfortunately that would be a breaking change.
>>
>>
>> Andrei
>
> It gets a bit ugly maybe, but we could do a mix of the 
> proposals that have come before and this one, e.g. add a 
> @nocycliccheck (or similar) to the static constructor,  and in 
> that case only allow access to current module and those imorted 
> inside the ctor scope..

We would probably not call it '@nycycliccheck' since you propose 
to still do these checks, but only local imports :) Would need 
another name for it.
September 22, 2012
Re: Review of Andrei's std.benchmark
On 2012-09-22, 15:28, Øivind wrote:

>> It gets a bit ugly maybe, but we could do a mix of the proposals that  
>> have come before and this one, e.g. add a @nocycliccheck (or similar)  
>> to the static constructor,  and in that case only allow access to  
>> current module and those imorted inside the ctor scope..
>
> We would probably not call it '@nycycliccheck' since you propose to  
> still do these checks, but only local imports :) Would need another name  
> for it.

@noglobalimports. :p

-- 
Simen
September 22, 2012
Re: Review of Andrei's std.benchmark
On 2012-09-22, 15:04, Andrei Alexandrescu wrote:

> On 9/22/12 8:28 AM, "Øivind" wrote:
>> Is there a way to solve the dependency issue without forbidding static
>> constructors in modules with cyclic dependencies?
>
> I think an idea just occurred to me. The rules for static ctors and  
> dtors were invented before "import" was allowed inside a scope. We could  
> have taken advantage of that.
>
> Say we restrict symbol visibility inside static cdtors to ONLY symbols  
> within the current module. If some static cdtor needs a symbol from a  
> different module, it must import it explicitly (even if the current  
> module already imports it).
>
> In this setup it should be possible to compute, in a fine-grained  
> manner, the dependencies of static cdtors.
>
> Unfortunately that would be a breaking change.

That *is* neat. I guess putting it on the deprecation path could work.
This is a change we'd really, *really* like to see.

-- 
Simen
September 22, 2012
Re: Review of Andrei's std.benchmark
On 9/19/12 3:13 AM, Jacob Carlborg wrote:
> On 2012-09-17 23:13, Jens Mueller wrote:
>
>> Post all feedback to this thread. Constructive feedback is very much
>> appreciated.
>>
>> To conclude in more Andrei like words: Happy destruction!
>
> * Why is "scheduleForBenchmarking" a string? Can't it be a template mixin?

Good point, I'll look into it.

> * What's the most appropriate way of just timing a block of code?
> Something like this:
>
> auto time = benchmark!({ /* some code */ })(1);
>
> If that's the case then I suggest setting a default value of "1" for the
> "n" parameter.

A default value of n would depend on the speed of the function and the 
granularity of the system's timer. That overload of benchmark is 
imperfect (rather rigid) but we must keep it for backwards compatibility.

> * If I want to format the printed result differently, say in HTML, how
> would I do that? Should I use the "benchmark" function and iterate the
> BenchmarkResult array?

That is correct. printBenchmarks() does not use any magic - it just 
looks at that same array.

> * BTW why doesn't benchmark return the BenchmarkResult array?

Will look into it.

> * Is this module so important to keep it as a top level module? I'm
> thinking something like a utility package or a time/date package. How
> about std.util.benchmark?

Not sure.



Andrei
September 22, 2012
Re: Review of Andrei's std.benchmark
>> - It is very strange that the documentation of printBenchmarks 
>> uses
>> neither of the words "average" or "minimum", and doesn't say 
>> how many
>> trials are done.... I suppose the obvious interpretation is 
>> that it
>> only does one trial, but then we wouldn't be having this 
>> discussion
>> about averages and minimums right? Øivind says tests are run 
>> 1000
>> times... but it needs to be configurable per-test (my idea: 
>> support a
>> _x1000 suffix in function names, or _for1000ms to run the test 
>> for at
>> least 1000 milliseconds; and allow a multiplier when when 
>> running a
>> group of benchmarks, e.g. a multiplier argument of 0.5 means 
>> to only
>> run half as many trials as usual.) Also, it is not clear from 
>> the
>> documentation what the single parameter to each benchmark is 
>> (define
>> "iterations count".)
>
> I don't think it's a good idea because the "for 1000 ms" 
> doesn't say anything except how good the clock resolution was 
> on the system. I'm as strongly convinced we shouldn't print 
> useless information as I am we should print useful information.

I am puzzled about what you think my suggestion meant. I am 
suggesting allowing the user to configure how long benchmarking 
takes. Some users might want to run their benchmark for an hour 
to get stable and reliable numbers; others don't want to wait and 
want to see results ASAP. Perhaps the *same* user will want to 
run benchmarks quickly while developing them and then do a "final 
run" with more trials once their benchmark suite is complete. 
Also, some individual benchmark functions will take microseconds 
to complete; others may take seconds to complete. All I'm 
suggesting are simple ways to avoid wasting users' time, without 
making std.benchmark overly complicated.
September 22, 2012
Re: Review of Andrei's std.benchmark
On Saturday, September 22, 2012 09:04:09 Andrei Alexandrescu wrote:
> On 9/22/12 8:28 AM, "Øivind" wrote:
> > Is there a way to solve the dependency issue without forbidding static
> > constructors in modules with cyclic dependencies?
> 
> I think an idea just occurred to me. The rules for static ctors and
> dtors were invented before "import" was allowed inside a scope. We could
> have taken advantage of that.
> 
> Say we restrict symbol visibility inside static cdtors to ONLY symbols
> within the current module. If some static cdtor needs a symbol from a
> different module, it must import it explicitly (even if the current
> module already imports it).
> 
> In this setup it should be possible to compute, in a fine-grained
> manner, the dependencies of static cdtors.
> 
> Unfortunately that would be a breaking change.

It's a nice thought, but it wouldn't work. If nothing else .di files completely 
ruin it.

1. I don't think that it's actually required that static constructors be in a 
.di file. So, the compiler couldn't know for sure whether the modules being 
imported had static constructors.

2. Even if all static constructors had to be in a .di file, local imports ruin 
it, because the function bodies (which can definitely be elided from .di files) 
could contain local imports to modules which have static constructors and 
cause circular dependencies.

- Jonathan M Davis
3 4 5 6 7 8
Top | Discussion index | About this forum | D home