The cost of doing compile time introspection
Timon Gehr via Digitalmars-d
digitalmars-d at puremagic.com
Thu May 11 14:09:05 PDT 2017
On 10.05.2017 16:03, Biotronic wrote:
>>
>
> A few things here - functions.fn would not do what you want, and neither
> would __traits(identifier).
> functions.fn would treat "fn" like a part of name, not a string value,
> so this will make the poor compiler barf.
> __traits(identifier, fn) expects fn to be a symbol, while here it's a
> string. In fact, it's exactly the string you want __traits to return.
> Lastly, you'll still need a mixin, whether it's for __traits(identifier,
> fn) or just fn - they're just strings. Something like this:
>
> static foreach (fn; CFunctions!functions) {
> mixin("typeof(__traits(getMember, functions, fn))* "~fn~";");
> }
Yes, this works and is a few times faster.
It's slightly faster when inlining the condition:
static foreach(fn;__traits(allMembers, functions)){
static if (isFunction!(__traits(getMember, functions, fn)) &&
(functionLinkage!(__traits(getMember, functions, fn)) ==
"C" ||
functionLinkage!(__traits(getMember, functions, fn)) ==
"Windows")){
mixin("typeof(functions."~fn~")* "~fn~";");
}
}
With the DMD debug build, I measured the following times on my machine:
Baselines:
just imports:
0m0.318s
copy-pasted generated code after printing it with pragma(msg, ...):
0m0.341s
Compile-time code generation:
old version:
0m2.569s
static foreach, uninlined:
0m0.704s
static foreach inlined:
0m0.610s
Still not great, but a notable improvement.
isFunction and functionLinkage are slow, so I got rid of them (as well
as the dependency on std.traits):
static foreach(fn;__traits(allMembers, functions)){
static if(fn != "object" && fn != "llvm" && fn != "orEmpty"):
mixin("typeof(functions."~fn~")* "~fn~";");
}
timing:
0m0.350s
(This is not perfect as you'll need to edit the list in case you are
adding more non-c-function members to that module, but I guess it is a
good trade-off.)
You can achieve essentially the same using a string mixin:
mixin({
string r;
foreach(fn;__traits(allMembers, functions))
if(fn != "object" && fn != "llvm" && fn != "orEmpty")
r~="typeof(functions."~fn~")* "~fn~";";
return r;
}());
timing:
0m0.370s
In case the original semantics should be preserved, I think this is the
best option:
mixin({
string r;
foreach(fn;CFunctions!functions)
r~="typeof(functions."~fn~")* "~fn~";";
return r;
}());
timing:
0m0.740s
More information about the Digitalmars-d
mailing list