passing a variadic parameter to randomSample
so I'm trying to write (or rather learn how to write) a 'variadic template function', that returns just one of its variadic parameter, randomly chosen. But can't get my head around the problem here :-( .. Error: template `std.random.randomSample` cannot deduce function from argument types ` // -- module test; import std; string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); } // --
Re: passing a variadic parameter to randomSample
On Tuesday, 25 January 2022 at 09:48:25 UTC, forkit wrote: so I'm trying to write (or rather learn how to write) a 'variadic template function', that returns just one of its variadic parameter, randomly chosen. But can't get my head around the problem here :-( .. Error: template `std.random.randomSample` cannot deduce function from argument types ` // -- module test; import std; string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); } // -- `r` is not input range, try this: ```d module test; import std; string RandomChoice1(R...)(R r) { auto rnd = MinstdRand0(unpredictableSeed); return only(r).randomSample(1, rnd).front; } string RandomChoice2(R...)(R r)@nogc { auto rnd = MinstdRand0(unpredictableSeed); switch(rnd.front % R.length){ static foreach(enum I, alias arg; r){ case I: return arg; } default: assert(0, "no impl"); } } void main() { writeln( RandomChoice1("typeA", "typeB", "typeC") ); writeln( RandomChoice2("typeA", "typeB", "typeC") ); } ```
How to create a function that behaves like std.stdio.writeln but prepends output with __FILE__:_LINE_
Any ideas how one can achieve what is written in the subject line? f below does achieve this but I one would expect that it produces significant template bloat. g achieves the aim but isn't very elegant. import std; void f(string file=__FILE__,size_t line=__LINE__,R...)(R r) { writeln(file,":",line," ",r); } void g(T)(T t,string file=__FILE__,size_t line=__LINE__) { writeln(file,":",line," ",t.expand); } void main() { f("hello ", 123); g(tuple("hello ",123)); }
Re: How to create a function that behaves like std.stdio.writeln but prepends output with __FILE__:_LINE_
On Tuesday, 25 January 2022 at 12:11:01 UTC, JG wrote: Any ideas how one can achieve what is written in the subject line? ```D void f(T...)(auto ref T args, string file = __FILE__, int line = __LINE__) { writeln(file, ":", line, ": ", args); } ```
Re: passing a variadic parameter to randomSample
On Tuesday, 25 January 2022 at 09:48:25 UTC, forkit wrote: so I'm trying to write (or rather learn how to write) a 'variadic template function', that returns just one of its variadic parameter, randomly chosen. But can't get my head around the problem here :-( .. Error: template `std.random.randomSample` cannot deduce function from argument types ` // -- module test; import std; string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); } // -- With R... each value could be of different type, so passing `RandomChoice("typeA", 4)` would break the current code. I think there are 2 different ways that can solve this elegantly: 1) restrict the parameters to all be the same parameter type: ```d string RandomChoice(T)(T[] r...) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } ``` and code compiles with no changes. Instead of using .to!string you could also return the parameter type itself if you want to get the value itself: ```d T RandomChoice(T)(T[] r...) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).front; } ``` 2) generate a random number between 0 and `r.length`, add a switch case and dynamically generate a case for each number (static foreach) and return the processed value using .to!string: ```d string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); switch (uniform(0, R.length, rnd)) { static foreach (i, value; r) { case i: // this code is duplicated for each parameter // use this if you want to support different argument types return value.to!string; } default: assert(false); } } ```
Re: How to create a function that behaves like std.stdio.writeln but prepends output with __FILE__:_LINE_
On Tuesday, 25 January 2022 at 12:27:16 UTC, Dennis wrote: On Tuesday, 25 January 2022 at 12:11:01 UTC, JG wrote: Any ideas how one can achieve what is written in the subject line? ```D void f(T...)(auto ref T args, string file = __FILE__, int line = __LINE__) { writeln(file, ":", line, ": ", args); } ``` note: default arguments after variadic arguments are supported since D 2.079.0: https://dlang.org/changelog/2.079.0.html#default_after_variadic
Re: passing a variadic parameter to randomSample
On Tuesday, 25 January 2022 at 09:48:25 UTC, forkit wrote: so I'm trying to write (or rather learn how to write) a 'variadic template function', that returns just one of its variadic parameter, randomly chosen. But can't get my head around the problem here :-( .. Error: template `std.random.randomSample` cannot deduce function from argument types ` // -- module test; import std; string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); } // -- On Tuesday, 25 January 2022 at 09:48:25 UTC, forkit wrote: so I'm trying to write (or rather learn how to write) a 'variadic template function', that returns just one of its variadic parameter, randomly chosen. But can't get my head around the problem here :-( .. Error: template `std.random.randomSample` cannot deduce function from argument types ` // -- module test; import std; string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); } // -- With R... each value could be of different type, so passing `RandomChoice("typeA", 4)` would break the current code. I think there are 2 different ways that can solve this elegantly: 1) restrict the parameters to all be the same parameter type: ```d string RandomChoice(T)(T[] r...) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).to!string; } ``` and code compiles with no changes. Instead of using .to!string you could also return the parameter type itself if you want to get the value itself: ```d T RandomChoice(T)(T[] r...) { auto rnd = MinstdRand0(42); return r.randomSample(1, rnd).front; } ``` 2) generate a random number between 0 and `r.length`, add a switch case and dynamically generate a case for each number (static foreach) and return the processed value using .to!string: ```d string RandomChoice(R...)(R r) { auto rnd = MinstdRand0(42); switch (uniform(0, R.length, rnd)) { static foreach (i, value; r) { case i: // this code is duplicated for each parameter // use this if you want to support different argument types return value.to!string; } default: assert(false); } } ```
Re: How to create a function that behaves like std.stdio.writeln but prepends output with __FILE__:_LINE_
On Tuesday, 25 January 2022 at 12:27:16 UTC, Dennis wrote: On Tuesday, 25 January 2022 at 12:11:01 UTC, JG wrote: Any ideas how one can achieve what is written in the subject line? ```D void f(T...)(auto ref T args, string file = __FILE__, int line = __LINE__) { writeln(file, ":", line, ": ", args); } ``` Thank you very much.
gdc or ldc for faster programs?
Sorry for being vague and not giving the code here but a program I wrote about spelling-out parts of a number (in Turkish) as in "1 milyon 42" runs much faster with gdc. The program integer-divides the number in a loop to find quotients and adds the word next to it. One obvious optimization might be to use POSIX div() and friends to get the quotient and the remainder at one shot but I made myself believe that the compilers already do that. (But still not sure. :o) ) I am not experienced with dub but I used --build=release-nobounds and verified that -O3 is used for both compilers. (I also tried building manually with GNU 'make' with e.g. -O5 and the results were similar.) For a test run for 2 million numbers: ldc: ~0.95 seconds gdc: ~0.79 seconds dmd: ~1.77 seconds I am using compilers installed by Manjaro Linux's package system: ldc: LDC - the LLVM D compiler (1.28.0): based on DMD v2.098.0 and LLVM 13.0.0 gdc: dc (GCC) 11.1.0 dmd: DMD64 D Compiler v2.098.1 I've been mainly a dmd person for various reasons and was under the impression that ldc was the clear winner among the three. What is your experience? Does gdc compile faster programs in general? Would ldc win if I took advantage of e.g. link-time optimizations? Ali
Re: gdc or ldc for faster programs?
On Tuesday, 25 January 2022 at 19:52:17 UTC, Ali Çehreli wrote: I am not experienced with dub but I used --build=release-nobounds and verified that -O3 is used for both compilers. (I also tried building manually with GNU 'make' with e.g. -O5 and the results were similar.) `-O5` does not do anything different than `-O3` for LDC. For a test run for 2 million numbers: ldc: ~0.95 seconds gdc: ~0.79 seconds dmd: ~1.77 seconds I am using compilers installed by Manjaro Linux's package system: ldc: LDC - the LLVM D compiler (1.28.0): based on DMD v2.098.0 and LLVM 13.0.0 gdc: dc (GCC) 11.1.0 dmd: DMD64 D Compiler v2.098.1 I've been mainly a dmd person for various reasons and was under the impression that ldc was the clear winner among the three. What is your experience? Does gdc compile faster programs in general? Would ldc win if I took advantage of e.g. link-time optimizations? Tough to say. Of course DMD is not a serious contender, but I believe the difference between GDC and LDC is very small and really in the details, i.e. you'll have to look at assembly to find out the delta. Have you tried `--enable-cross-module-inlining` with LDC? -Johan
Re: gdc or ldc for faster programs?
On Tuesday, 25 January 2022 at 19:52:17 UTC, Ali Çehreli wrote: ldc: ~0.95 seconds gdc: ~0.79 seconds dmd: ~1.77 seconds Not surprising at all: gdc is excellent and underrated in the community.
Re: gdc or ldc for faster programs?
On Tue, Jan 25, 2022 at 11:52:17AM -0800, Ali Çehreli via Digitalmars-d-learn wrote: > Sorry for being vague and not giving the code here but a program I > wrote about spelling-out parts of a number (in Turkish) as in "1 > milyon 42" runs much faster with gdc. > > The program integer-divides the number in a loop to find quotients and > adds the word next to it. One obvious optimization might be to use > POSIX div() and friends to get the quotient and the remainder at one > shot but I made myself believe that the compilers already do that. > (But still not sure. :o)) Don't guess at what the compilers are doing; disassemble the binary and see for yourself exactly what the difference is. Use run.dlang.io for a convenient interface that shows you exactly how the compilers translated your code. Or if you're macho, use `objdump -d` and search for _Dmain (or the specific function if you know how it's mangled). > I am not experienced with dub but I used --build=release-nobounds and > verified that -O3 is used for both compilers. (I also tried building > manually with GNU 'make' with e.g. -O5 and the results were similar.) > > For a test run for 2 million numbers: > > ldc: ~0.95 seconds > gdc: ~0.79 seconds > dmd: ~1.77 seconds For measurements under 1 second, I'm skeptical of the accuracy, because there could be all kinds of background noise, CPU interrupts and stuff that could be skewing the numbers. What about do a best-of-3-runs with 20 million numbers (expected <20 seconds per run) and see how the numbers look? Though having said all that, I can say at least that dmd's relatively poor performance seems in line with my previous observations. :-P The difference between ldc and gdc is harder to pinpoint; they each have different optimizers that could work better or worse than the other depending on the specifics of what the program is doing. [...] > I've been mainly a dmd person for various reasons and was under the > impression that ldc was the clear winner among the three. What is your > experience? Does gdc compile faster programs in general? Would ldc win > if I took advantage of e.g. link-time optimizations? [...] I'm not sure LDC is the clear winner. I only prefer LDC because LDC's architecture makes it easier for cross-compilation (with GCC/GDC you need to jump through a lot more hoops to get a working cross compiler). GDC is also tied to the GCC release cycle, and tends to be several language versions behind LDC. But both compilers have excellent optimizers, but they are definitely different so for some things GDC will beat LDC, for other things LDC will beat GDC. It may depend on the specific optimization flags you use as well. But these sorts of statements are just generalizations. The best way to find out for sure is to disassemble the executable and see for yourself what the assembly looks like. :-) T -- Public parking: euphemism for paid parking. -- Flora
Re: gdc or ldc for faster programs?
On Tuesday, 25 January 2022 at 20:04:04 UTC, Adam D Ruppe wrote: On Tuesday, 25 January 2022 at 19:52:17 UTC, Ali Çehreli wrote: ldc: ~0.95 seconds gdc: ~0.79 seconds dmd: ~1.77 seconds Maybe you can try --ffast-math on ldc.
Re: gdc or ldc for faster programs?
On 1/25/22 11:52, Ali Çehreli wrote: > a program I wrote about spelling-out parts of a number Here is the program as a single module: module spellout.spellout; // This program was written as a code kata to spell out // certain parts of integers as in "1 million 2 thousand // 42". Note that this way of spelling-out numbers is not // grammatically correct in English. // Returns a string that contains the partly spelled-out version // of the parameter. // // You must copy the returned string when needed as this function // uses the same internal buffer for all invocations of the same // template instance. auto spellOut(T)(in T number_) { import std.array : Appender; import std.string : strip; import std.traits : Unqual; import std.meta : AliasSeq; static Appender!(char[]) result; result.clear; // We treat these specially because the algorithm below does // 'number = -number' and calls the same implementation // function. The trouble is, for example, -int.min is still a // negative number. alias problematics = AliasSeq!( byte, "negative 128", short, "negative 32 thousand 768", int, "negative 2 billion 147 million 483 thousand 648", long, "negative 9 quintillion 223 quadrillion 372 trillion" ~ " 36 billion 854 million 775 thousand 808"); static assert((problematics.length % 2) == 0); static foreach (i, P; problematics) { static if (i % 2) { // This is a string; skip } else { // This is a problematic type static if (is (T == P)) { // Our T happens to be this problematic type if (number_ == T.min) { // and we are dealing with a problematic value result ~= problematics[i + 1]; return result.data; } } } } auto number = cast(Unqual!T)number_; // Thanks 'in'! :p if (number == 0) { result ~= "zero"; } else { if (number < 0) { result ~= "negative"; static if (T.sizeof < int.sizeof) { // Being careful with implicit conversions. (See the dmd // command line switch -preview=intpromote) number = cast(T)(-cast(int)number); } else { number = -number; } } spellOutImpl(number, result); } return result.data.strip; } unittest { assert(1_001_500.spellOut == "1 million 1 thousand 500"); assert((-1_001_500).spellOut == "negative 1 million 1 thousand 500"); assert(1_002_500.spellOut == "1 million 2 thousand 500"); } import std.format : format; import std.range : isOutputRange; void spellOutImpl(T, O)(T number, ref O output) if (isOutputRange!(O, char)) in (number > 0, format!"Invalid number: %s"(number)) { import std.range : retro; import std.format : formattedWrite; foreach (divider; dividers!T.retro) { const quotient = number / divider.value; if (quotient) { output.formattedWrite!" %s %s"(quotient, divider.word); } number %= divider.value; } } struct Divider(T) { T value;// 1_000, 1_000_000, etc. string word;// "thousand", etc } // Returns the words related with the provided size of an // integral type. The parameter is number of bytes // e.g. int.sizeof auto words(size_t typeSize) { // This need not be recursive at all but it was fun using // recursion. final switch (typeSize) { case 1: return [ "" ]; case 2: return words(1) ~ [ "thousand" ]; case 4: return words(2) ~ [ "million", "billion" ]; case 8: return words(4) ~ [ "trillion", "quadrillion", "quintillion" ]; } } unittest { // These are relevant words for 'int' and 'uint' values: assert(words(4) == [ "", "thousand", "million", "billion" ]); } // Returns a Divider!T array associated with T auto dividers(T)() { import std.range : array, enumerate; import std.algorithm : map; static const(Divider!T[]) result = words(T.sizeof) .enumerate!T .map!(t => Divider!T(cast(T)(10^^(t.index * 3)), t.value)) .array; return result; } unittest { // Test a few entries assert(dividers!int[1] == Divider!int(1_000, "thousand")); assert(dividers!ulong[3] == Divider!ulong(1_000_000_000, "billion")); } void main() { version (test) { return; } import std.meta : AliasSeq; import std.stdio : writefln; import std.random : Random, uniform; import std.conv : to; static foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong)) {{ // A few numbers for each type report(T.min); report((T.max / 4).to!T); // Overcome int promotion for // shorter types because I want // to test with the exact type // e.g. for byte. report(T.max); }} enum count = 2_000_000; writefln!"Testing with %,s random numbers"(spellOut(count)); // Use the same seed to be fair between compilations enum seed = 0; auto rnd = Random(seed); ulong totalLength; foreach (i; 0 .
Re: gdc or ldc for faster programs?
On Tue, Jan 25, 2022 at 08:04:04PM +, Adam D Ruppe via Digitalmars-d-learn wrote: > On Tuesday, 25 January 2022 at 19:52:17 UTC, Ali Çehreli wrote: > > ldc: ~0.95 seconds > > gdc: ~0.79 seconds > > dmd: ~1.77 seconds > > Not surprising at all: gdc is excellent and underrated in the > community. The GCC optimizer is actually pretty darned good, comparable to LDC's. I only prefer LDC because of easier cross-compilation and more up-to-date language version (due to GDC being tied to GCC's release cycle). But I wouldn't hesitate to use gdc if I didn't need to cross-compile or use features from the latest language version. DMD's optimizer is miles behind LDC/GDC, sad to say. About the only thing that keeps me using dmd is its lightning-fast compilation times, ideal for iterative development. For anything performance related, DMD isn't even on my radar. T -- Doubtless it is a good thing to have an open mind, but a truly open mind should be open at both ends, like the food-pipe, with the capacity for excretion as well as absorption. -- Northrop Frye
Re: gdc or ldc for faster programs?
On 1/25/22 12:01, Johan wrote: Have you tried `--enable-cross-module-inlining` with LDC? Tried now. Makes no difference that I can sense, likely because there is only one module anyway. :) (But I guess it works over Phobos modules too.) Ali
Re: gdc or ldc for faster programs?
On 1/25/22 12:59, Daniel N wrote: Maybe you can try --ffast-math on ldc. Did not make a difference. Ali
Re: gdc or ldc for faster programs?
On 1/25/22 12:42, H. S. Teoh wrote: >> For a test run for 2 million numbers: >> >> ldc: ~0.95 seconds >> gdc: ~0.79 seconds >> dmd: ~1.77 seconds > > For measurements under 1 second, I'm skeptical of the accuracy, because > there could be all kinds of background noise, CPU interrupts and stuff > that could be skewing the numbers. What about do a best-of-3-runs with > 20 million numbers (expected <20 seconds per run) and see how the > numbers look? Makes sense. The results are similar to the 2 million run. > But these sorts of statements are just generalizations. The best way to > find out for sure is to disassemble the executable and see for yourself > what the assembly looks like. :-) I posted the program to have more eyes on the assembly. ;) Ali
Re: passing a variadic parameter to randomSample
On Tuesday, 25 January 2022 at 11:50:08 UTC, vit wrote: thanks. problem solved (providing all parameters are of the same type). // --- module test; import std; auto RandomChoice(R...)(R r) { auto rnd = MinstdRand0(unpredictableSeed); return only(r).randomSample(1, rnd).front; } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); writeln( RandomChoice(5, 8, 2) ); writeln( RandomChoice(100.05, 110.8, 109.54) ); //writeln( RandomChoice("typeA", 5, 100.14) ); // nope. they all need to be of the same type. writeln( RandomChoice("typeA", 5.to!string, 100.14.to!string) ); } //--
Re: passing a variadic parameter to randomSample
On 1/25/22 13:55, forkit wrote: > auto RandomChoice(R...)(R r) Watch out though: The compiler will compile a different function per set of values. For example, there will be separate RandomChoice instances for ("hello") vs. ("world"). D has a simple variadic parameter syntax as well: auto RandomChoice(R)(R[] r...) > { > auto rnd = MinstdRand0(unpredictableSeed); > return only(r).randomSample(1, rnd).front; Which makes that simpler as well because being a slice, r is already a range. And there is choice(): return r.choice(rnd); Something is very important though: The 'r' slice is short-lived; it does not live in dynamic memory. RandomChoice() should not save it for later use nor return it. (The compiler may have protection against that; I am not sure.) Ali
Re: gdc or ldc for faster programs?
On Tue, Jan 25, 2022 at 01:30:59PM -0800, Ali Çehreli via Digitalmars-d-learn wrote: [...] > I posted the program to have more eyes on the assembly. ;) [...] I tested the code locally, and observed, just like Ali did, that the LDC version is unambiguously slower than the gdc version by a small margin. So I decided to compare the disassembly. Due to the large number of templates in the main spellOut/spellOutImpl functions, I didn't have the time to look at all of them; I just arbitrarily picked the !(int) instantiation. And I'm seeing something truly fascinating: - The GDC version has at its core a single idivl instruction for the / and %= operators (I surmise that the optimizer realized that both could share the same instruction because it yields both results). The function is short and compact. - The LDC version, however, seems to go out of its way to avoid the idivl instruction, having instead a whole bunch of shr instructions and imul instructions involving magic constants -- the kind of stuff you see in bit-twiddling hacks when people try to ultra-optimize their code. There also appears to be some loop unrolling, and the function is markedly longer than the GDC version because of this. This is very interesting because idivl is known to be one of the slower instructions, but gdc nevertheless considered it not worthwhile to replace it, whereas ldc seems obsessed about avoid idivl at all costs. I didn't check the other instantiations, but it would appear that in this case the simpler route of just using idivl won over the complexity of trying to replace it with shr+mul. T -- Guns don't kill people. Bullets do.
Re: passing a variadic parameter to randomSample
On Tue, Jan 25, 2022 at 02:07:43PM -0800, Ali Çehreli via Digitalmars-d-learn wrote: [...] > auto RandomChoice(R)(R[] r...) > > > { > > auto rnd = MinstdRand0(unpredictableSeed); > > return only(r).randomSample(1, rnd).front; > > Which makes that simpler as well because being a slice, r is already a > range. And there is choice(): > > return r.choice(rnd); > > Something is very important though: The 'r' slice is short-lived; it does > not live in dynamic memory. RandomChoice() should not save it for later use > nor return it. (The compiler may have protection against that; I am not > sure.) I think with -dip1000 the compiler should refuse to compile the code if you try to save a slice of r past the function body. T -- Philosophy: how to make a career out of daydreaming.
Re: passing a variadic parameter to randomSample
On Tuesday, 25 January 2022 at 22:07:43 UTC, Ali Çehreli wrote: thanks. makes it even shorter and simpler :-) // -- module test; @safe: import std; auto RandomChoice(R...)(R r) { auto rnd = MinstdRand0(unpredictableSeed); return only(r).choice(rnd); } void main() { writeln( RandomChoice("typeA", "typeB", "typeC") ); writeln( RandomChoice(5, 8, 2) ); writeln( RandomChoice(1.3, 5.09, 8, 2) ); writeln( RandomChoice(100.05, 110.8, 109.54) ); //writeln( RandomChoice("typeA", 5, 100.14) ); // nope. some issue with mixing strings with numeric types writeln( RandomChoice("typeA", 5.to!string, 100.14.to!string) ); // NOTE: This registers with -profile=gc } // --
Re: gdc or ldc for faster programs?
On Tuesday, 25 January 2022 at 22:33:37 UTC, H. S. Teoh wrote: interesting because idivl is known to be one of the slower instructions, but gdc nevertheless considered it not worthwhile to replace it, whereas ldc seems obsessed about avoid idivl at all costs. Interesting indeed. Two remarks: 1. Actual performance cost of div depends a lot on hardware. IIRC on my old intel laptop it's like 40-60 cycles; on my newer amd chip it's more like 20; on my mac it's ~10. GCC may be assuming newer hardware than llvm. Could be worth popping on a -march=native -mtune=native. Also could depend on how many ports can do divs; i.e. how many of them you can have running at a time. 2. LLVM is more aggressive wrt certain optimizations than gcc, by default. Though I don't know how relevant that is at -O3.
Re: passing a variadic parameter to randomSample
On Tuesday, 25 January 2022 at 22:35:29 UTC, forkit wrote: I should point out (to anyone looking at that code I posted), that it's easier, and makes more sense, to just write: writeln( ["typeA", "typeB", "typeC"].choice ); ... but my main focus here, was learning about variadic template functions.
Re: gdc or ldc for faster programs?
On 1/25/22 14:33, H. S. Teoh wrote: > This is very interesting Fascinating code generation and investigation! :) Ali
Re: gdc or ldc for faster programs?
On Tue, Jan 25, 2022 at 10:41:35PM +, Elronnd via Digitalmars-d-learn wrote: > On Tuesday, 25 January 2022 at 22:33:37 UTC, H. S. Teoh wrote: > > interesting because idivl is known to be one of the slower > > instructions, but gdc nevertheless considered it not worthwhile to > > replace it, whereas ldc seems obsessed about avoid idivl at all > > costs. > > Interesting indeed. Two remarks: > > 1. Actual performance cost of div depends a lot on hardware. IIRC on > my old intel laptop it's like 40-60 cycles; on my newer amd chip it's > more like 20; on my mac it's ~10. GCC may be assuming newer hardware > than llvm. Could be worth popping on a -march=native -mtune=native. > Also could depend on how many ports can do divs; i.e. how many of them > you can have running at a time. I tried `ldc2 -mcpu=native` but that did not significantly change the performance. > 2. LLVM is more aggressive wrt certain optimizations than gcc, by > default. Though I don't know how relevant that is at -O3. Yeah, I've noted in the past that LDC seems to be pretty aggressive with inlining / loop unrolling, whereas GDC has a thing for vectorization and SIMD/XMM usage. The exact outcomes are a toss-up, though. Sometimes LDC wins, sometimes GDC wins. Depends on what exactly the code is doing. T -- "Outlook not so good." That magic 8-ball knows everything! I'll ask about Exchange Server next. -- (Stolen from the net)
Re: passing a variadic parameter to randomSample
On Tue, Jan 25, 2022 at 10:48:26PM +, forkit via Digitalmars-d-learn wrote: [...] > ... but my main focus here, was learning about variadic template > functions. D has several flavors of variadics: 1) C-style variadics (not type-safe, not recommended): int func(int firstArgc, ...) 2) D-style type-safe variadics (non-templated): int func(int[] args...) All arguments must be of the same type, and the function receives them as an array of that type, so .length can be used to ensure you don't overrun the array. 3) Variadic template functions: int func(Args...)(Args args) Arguments can be of any type, the type can be obtained with Args[i]. (Not to be confused with lowercase args[i], which gives you the argument value itself.) The most flexible of the lot, but may also lead to template bloat if used excessively (one instantiation is generated for every different combination of argument types). There's also the lazy variant of (2) with delegates, but I've never used them before. T -- An elephant: A mouse built to government specifications. -- Robert Heinlein
Re: gdc or ldc for faster programs?
On Tuesday, 25 January 2022 at 20:01:18 UTC, Johan wrote: Tough to say. Of course DMD is not a serious contender, but I believe the difference between GDC and LDC is very small and really in the details, i.e. you'll have to look at assembly to find out the delta. Have you tried `--enable-cross-module-inlining` with LDC? -Johan dmd is the best though, in terms of compilation speed without optimisation. As I write/test A LOT of code, that time saved is very much appreciated ;-) I hope it remains that way.
Re: gdc or ldc for faster programs?
On Tue, Jan 25, 2022 at 11:01:57PM +, forkit via Digitalmars-d-learn wrote: > On Tuesday, 25 January 2022 at 20:01:18 UTC, Johan wrote: > > > > Tough to say. Of course DMD is not a serious contender, but I > > believe the difference between GDC and LDC is very small and really > > in the details, i.e. you'll have to look at assembly to find out the > > delta. Have you tried `--enable-cross-module-inlining` with LDC? [...] > dmd is the best though, in terms of compilation speed without > optimisation. > > As I write/test A LOT of code, that time saved is very much > appreciated ;-) [...] My general approach is: use dmd for iterating the code - compile - test cycle, and use LDC for release/production builds. T -- Chance favours the prepared mind. -- Louis Pasteur
Re: gdc or ldc for faster programs?
On Tuesday, 25 January 2022 at 19:52:17 UTC, Ali Çehreli wrote: I am using compilers installed by Manjaro Linux's package system: ldc: LDC - the LLVM D compiler (1.28.0): based on DMD v2.098.0 and LLVM 13.0.0 gdc: dc (GCC) 11.1.0 dmd: DMD64 D Compiler v2.098.1 What phobos version is gdc using? -Johan
Re: gdc or ldc for faster programs?
On 1/25/22 16:15, Johan wrote: > On Tuesday, 25 January 2022 at 19:52:17 UTC, Ali Çehreli wrote: >> >> I am using compilers installed by Manjaro Linux's package system: >> >> ldc: LDC - the LLVM D compiler (1.28.0): >> based on DMD v2.098.0 and LLVM 13.0.0 >> >> gdc: dc (GCC) 11.1.0 >> >> dmd: DMD64 D Compiler v2.098.1 > > What phobos version is gdc using? Oh! Good question. Unfortunately, I don't think Phobos modules contain that information. The following line outputs 2076L: pragma(msg, __VERSION__); So, I guess I've been comparing apples to oranges but in this case an older gdc is doing pretty well. Ali