Vectors and matrices in D

Sean Kelly sean at f4.ca
Thu Mar 15 12:02:05 PDT 2007


Bill Baxter wrote:
> 
> Anyway, if you're coming from Java then doing a heap allocation for 
> every vector may not seem like a big deal.  But Java's allocations of 
> small objects are pretty heavily optimized from what I've heard.  D 
> isn't really there.

I think some Java compilers will actually allocate classes on the stack 
if they can prove the object does not escape scope.  This is similar to 
what we do manually in D with the 'scope' keyword.  That said, there are 
still many instances where automated stack allocation is typically not 
possible in Java (returning data from a function, for example), but can 
still be done in D using structs.

As an example of how much of an impact dynamic allocation has on 
application run times, I did a short performance analysis using Java a 
while back.  I'll include the summary plus some timings below.

----------------------------------------------------------------------

 From a performance perspective, the array-based and link-based queue 
implementations are effectively identical but for the enqueue method.  A 
link-based enqueue operation allocates a new node object then performs 
some reference manipulation to append this node to an internal 
linked-list.  By comparison, the array-based implementation will resize 
its internal array by doubling its length and copying existing elements 
into the new area if the array is full, and will then copy the new value 
into the array directly.  Therefore, assuming all operations have an 
equal cost, the performance difference between these two implementations 
rests in how often the array-queue must grow to accommodate new 
elements.  Assuming a worst-case scenario where elements are repeatedly 
inserted into the queue and are never removed, the array-based 
implementation must perform log(N) resize operations, and (N - 1) 
elements copied, assuming N represents the maximum number of elements 
inserted into the queue.  This is a cost not incurred by the link-queue, 
where no copy operation is performed regardless of queue growth. 
Therefore, in terms of N, the array-queue will perform (N + log(N)) more 
operations than the link-queue in a worst-case scenario.  So assuming 
the queue grows to 1000 elements, ten resize operations will be 
performed to produce a maximum array size of 1024 elements, and 1023 
element copy operations will be performed, for a total of 1033 
additional operations, or approximately twice as many operations as the 
linked-queue implementation.  Therefore, it is reasonable to assume that 
the array-queue will perform approximately twice as slowly as the 
link-queue, assuming this worst-case scenario.

Performance results are rarely as simple as such a code analysis 
suggests however.  Memory allocations are typically fairly expensive 
operations, as are any garbage collection runs required to clean up 
discarded memory.  Also, arrays typically have far better locality of 
reference than linked-lists (linked-list locality depends on allocator 
design and on how the container is used within the application), so 
fewer cache misses typically occur with array-based containers than with 
linked-list containers.  Finally, the array-queue described above will 
actually resize very rarely compared to the number of insertion 
operations performed, giving what is sometimes referred to as "amortized 
constant time" performance for the enqueue operation.  Given all these 
considerations, I think real-world use of these two queue 
implementations will show approximately equal performance, and the 
array-queue has the potential to be even faster than the link-queue in 
some situations, or on some systems.

For three runs inserting one million elements in succession and then 
removing them (similar to the worst case for array-queue as described 
above), my average times were:

array-queue: 153.3 milliseconds
link-queue: 641 milliseconds


More information about the Digitalmars-d-learn mailing list