www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: T[new]

reply bearophile <bearophileHUGS lycos.com> writes:
dsimcha:

 import std.stdio, std.perf;

 Results:
 Direct:  226
 Indirect:  229

Thank you. Following your example I have tried to do a bit more realistic tests. // test1.d, for D2, Phobos import std.stdio: writeln; import std.perf: PerformanceCounter; final class TNew(T) { T* ptr; size_t length, capacity; this(size_t size) { this.ptr = (new T[size]).ptr; this.length = size; this.capacity = size; } ref T opIndex(size_t index) { return this.ptr[index]; } } void main() { // increase N if you have a large L2 cache enum int N = 100_000; enum int NLOOP = 40_000; alias uint T; auto pc = new PerformanceCounter; auto a = new T[N]; auto c = new TNew!T(N); pc.start; T* p = a.ptr; for (uint j; j < NLOOP; j++) for (uint i; i < N; i++) p[i]++; pc.stop; writeln("Direct: ", pc.milliseconds); pc.start; for (uint j; j < NLOOP; j++) for (uint i; i < N; i++) c[i]++; pc.stop; writeln("Class: ", pc.milliseconds); pc.start; for (uint j; j < NLOOP; j++) for (uint i; i < N; i++) a[i]++; pc.stop; writeln("Array: ", pc.milliseconds); writeln(); pc.start; for (uint j; j < NLOOP; j++) for (uint i = N-1; i--; ) p[i]++; pc.stop; writeln("Direct: ", pc.milliseconds); pc.start; for (uint j; j < NLOOP; j++) for (uint i = N-1; i--; ) c[i]++; pc.stop; writeln("Class: ", pc.milliseconds); pc.start; for (uint j; j < NLOOP; j++) for (uint i = N-1; i--; ) a[i]++; pc.stop; writeln("Array: ", pc.milliseconds); } Timings on Windows, DMD v2.031, 2 GHz Core2 PC (use a larger N if you have a large L2 CPU Cache): Direct: 4654 Class: 4670 Array: 4095 Direct: 4650 Class: 4688 Array: 4089 It's curious how the "direct" version is slower than the normal dynamic array (this doesn't happen in LDC, see below). ----------------------------- Then I've tried to create a version that can be compiled with LDC too (with Tango). The LDC that I have compiles D1 code, so I can't use ref T opIndex(). So I have created the following version, if you spot bugs or mistakes please tell me: // test2.d, for D1, Phobos and Tango version (Tango) { import tango.stdc.stdio: printf; import tango.time.StopWatch: StopWatch; } else { import std.c.stdio: printf; import std.perf: PerformanceCounter; } final class TNew(T) { T* ptr; size_t length, capacity; this(size_t size) { this.ptr = (new T[size]).ptr; this.length = size; this.capacity = size; } T* refItem(size_t index) { return &(this.ptr[index]); } } void main() { // increase N if you have a large L2 cache const int N = 100_000; const int NLOOP = 40_000; alias uint T; version (Tango) StopWatch timer; else auto timer = new PerformanceCounter; int deltaTime; auto a = new T[N]; auto c = new TNew!(T)(N); timer.start; T* p = a.ptr; for (uint j; j < NLOOP; j++) for (uint i; i < N; i++) p[i]++; version (Tango) { deltaTime = timer.microsec() / 1000; } else { timer.stop; deltaTime = cast(int)timer.milliseconds; } printf("Direct: %d\n", deltaTime); timer.start; for (uint j; j < NLOOP; j++) for (uint i; i < N; i++) (*c.refItem(i))++; version (Tango) { deltaTime = timer.microsec() / 1000; } else { timer.stop; deltaTime = cast(int)timer.milliseconds; } printf("Class: %d\n", deltaTime); timer.start; for (uint j; j < NLOOP; j++) for (uint i; i < N; i++) a[i]++; version (Tango) { deltaTime = timer.microsec() / 1000; } else { timer.stop; deltaTime = cast(int)timer.milliseconds; } printf("Array: %d\n", deltaTime); printf("\n"); timer.start; for (uint j; j < NLOOP; j++) for (uint i = N-1; i--; ) p[i]++; version (Tango) { deltaTime = timer.microsec() / 1000; } else { timer.stop; deltaTime = cast(int)timer.milliseconds; } printf("Direct: %d\n", deltaTime); timer.start; for (uint j; j < NLOOP; j++) for (uint i = N-1; i--; ) (*c.refItem(i))++; version (Tango) { deltaTime = timer.microsec() / 1000; } else { timer.stop; deltaTime = cast(int)timer.milliseconds; } printf("Class: %d\n", deltaTime); timer.start; for (uint j; j < NLOOP; j++) for (uint i = N-1; i--; ) a[i]++; version (Tango) { deltaTime = timer.microsec() / 1000; } else { timer.stop; deltaTime = cast(int)timer.milliseconds; } printf("Array: %d\n", deltaTime); } Timings on Windows: Direct: 4654 Class: 4810 Array: 4086 Direct: 4665 Class: 4598 Array: 4084 Timings on a 32 bit Linux (ldc -O3 -release -inline): Direct: 4280 Class: 5000 Array: 4280 Direct: 4280 Class: 4860 Array: 4270 If such tests are correct, then the new resizable arrays of D2 will indeed have some performance penality (something like 13%-17% in this test, but results may change with other array sizes). Bye, bearophile
Aug 10 2009
parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Mon, Aug 10, 2009 at 6:53 PM, bearophile<bearophileHUGS lycos.com> wrote:

 If such tests are correct, then the new resizable arrays of D2 will indeed
have some performance penality (something like 13%-17% in this test, but
results may change with other array sizes).

I don't see why that's a big problem. If you're using a resizable array, you probably care more about *resizing* it. That is, you're probably only going to be using resizable arrays when you're doing ~=. Like Walter said, if you need fast access to the data, you can just slice it and get a slice array.
Aug 10 2009
parent bearophile <bearophileHUGS lycos.com> writes:
Jarrett Billingsley:
I don't see why that's a big problem.<

Like St Thomas I touch first and believe (maybe) later :-) Bye, bearophile
Aug 11 2009