Skip to main content
gamedev.net
🔒 Locked

Fast Array Element Copy?

Started by DIB 24 replies 2.7k views
Original Post
DIB
DIB
I am trying to copy elements within an array. The array is huge, so I need it to be fast. Here's what I am currently doing... for(int i = 0; i < totalArraySize; i+=5) { array[i+1] = array; array[i+2] = array; array[i+3] = array; array[i+4] = array; } Is there any memcpy-like function that can do this? I would love to know how to unroll this and make it faster. Any suggestions?? [edited for formatting]
dave
dave
There is:

void* memcpy( void* dst, void* src, size_t sizeToCopy);

Just cast the &element[n] to void* and run this code. Also, check the return value of memcpy() as well, it will be null if it failed.

ace
DIB
DIB
void* memcpy( void* dst, void* src, size_t sizeToCopy);


I would have to do this for every set of elements, though.

for(...)
{
memcpy(array[i+1], array, 1);
memcpy(array[i+2], array, 1);
memcpy(array[i+3], array, 1);
memcpy(array[i+4], array, 1);
}

Is this really any faster???

The array size is so large, that there is a noticable performance hit by copying like this, in general. Just wondering if there were any tricks. I should have thought about just doing this memcpy within the loop. (That's why it helps to have other people lookat your code from time to time!)
dave
dave
No, you can memcpy the whole lot in one go.

Just do n * sizeof( elementType ) for the size parameter, just make sure that the destination is big enough to hold what you are copying.

ace

EDIT: As far as i know, memcpy is as lowlevel as it goes. I think a simple assignment like:

int a;
int b;

b = a;

is basically the same as a memcpy( (void*) &a, (void*) &b, sizeof( int ) );

I could be wrong though.

ace
DIB
DIB
Hmmm...you're saying:

memcpy(array[i+1], array, 4);

That would be a neat trick. I can see how this could work, but I can also see how it would fail. Am I understanding you correctly?

If my array were....

[9][0][0][0][0] [8][0][0][0][0]

I would want:

[9][9][9][9][9] [8][8][8][8][8]

I could see how that memcpy might give me:

[9][9][0][0][0] [0][0][0][0][0]

Just want to make sure I am understanding you right...

Thanks for the help!!

dave
dave
Oh i see, sorry.

To do what you want to do then the loop is the best way. But to simply copy lumps of memory from one place to another, use memvpy().

ace
DIB
DIB
Ok, good. Thought I was going nuts. Yeah, blocks of memory are easy to copy...

This copy is screaming for a faster way, I just don't know of a faster way to do it!

Cocalus
Cocalus
What does the array hold? ints doubles shorts?
me22
me22
If you're using C, use memcpy.
If you're using C++, use std::copy.

std::copy is usually implemented by your library writer to turn into a call to memcpy whenever possible, but it won't use memcpy in a case where you have a non-POD type, which would really screw you over.
Dim_Yimma_H
Dim_Yimma_H
Quote:
Original post by DIB
I am trying to copy elements within an array. The array is huge, so I need it to be fast. Here's what I am currently doing...

for(int i = 0; i < totalArraySize; i+=5)
{
array[i+1] = array;
array[i+2] = array;
array[i+3] = array;
array[i+4] = array;
}

Is there any memcpy-like function that can do this? I would love to know how to unroll this and make it faster. Any suggestions??

[edited for formatting]


Since array is the same as *(array + i) and this addition is done four times it could help to have a temporary variable = array which is assigned once and then only copy tmp, so it'll be 5 operations instead of 8.

I changed the index increments to ++ ones only but that change probably doesn't make much difference in execution speed.

int tmp;for(int i = 0; i < totalArraySize; i++){	tmp = array;	array[++i] = tmp;	array[++i] = tmp;	array[++i] = tmp;	array[++i] = tmp;}


I too, am a bit curious on what you're going to do with that sort of copy.
DIB
DIB
I like that addition idea.

Ok, the reason I am doing this is:

Each set of n array positions (5, in this case) starts out with a bunch of data in them. I have to move through the data, manipulating things, doing calculations, etc. When I am done, the result is in the first of the 5 bins. Now, I could just leave the result there, eliminating this problem. However, for presentation reasons, I need to copy it to the rest of the bins so the next function, which plots the data, looks prettier. [Now, sure, you can say I should modify the display function, etc, but this is a slight simplification of the problem, so trust me, if I want it pretty, I have to copy the elements.]

So, the real reason I need to do this? To look good.

(C'mon, you know you've sacraficed performance for looks. Right? Right?) However, when I implemented it, it seemed as though there should have been a faster way to do it.

Keep the good ideas flowing!

TDragon
TDragon
Quote:
Original post by DIB
[Now, sure, you can say I should modify the display function, etc, but this is a slight simplification of the problem, so trust me, if I want it pretty, I have to copy the elements.]
I'm not a very trusting person. This is nothing a very minor rework couldn't solve, unless the code that relies on it is intentionally obfuscated.

Skeleton_V@T
Skeleton_V@T
You can use memcpy as double as the last time. Say, first time it copies 5 elements, next time it will copy 10 elements. The copy operations will be much faster. One note about the size of the array however.
If you want to sacrifice performance for readability, you'll probably bypass my suggestion. Anyway, hope this helps.

V@T
--> The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones <--
DIB
DIB
Quote:
I'm not a very trusting person. This is nothing a very minor rework couldn't solve, unless the code that relies on it is intentionally obfuscated.


I have to push the data to some external hardware. That's the problem. Further, I can't modify the hardware or the software running on it. So here I am...not being trusted...but I don't blame you.

Zahlman
Zahlman
Quote:
Original post by me22
If you're using C, use memcpy.
If you're using C++, use std::copy.

std::copy is usually implemented by your library writer to turn into a call to memcpy whenever possible, but it won't use memcpy in a case where you have a non-POD type, which would really screw you over.


Quoted for emphasis. std::copy can tag-dispatch to figure out the best copying method (and for each method, an optimized implementation will be provided) that will actually do things correctly. Compiler writers know how to do this stuff better than you. If that were not the case, you would be employed alongside them.

Anyway, it looks to me as if you are already unrolling things - incorrectly, missing the elements with indices divisible by 5 :s Never mind, I'm an idiot.

[Edited by - Zahlman on November 1, 2005 6:09:28 PM]
TDragon
TDragon
Quote:
Original post by Zahlman
Anyway, it looks to me as if you are already unrolling things - incorrectly, missing the elements with indices divisible by 5 :s

Quote:
Original post by DIB
Ok, the reason I am doing this is:

Each set of n array positions (5, in this case) starts out with a bunch of data in them. I have to move through the data, manipulating things, doing calculations, etc. When I am done, the result is in the first of the 5 bins. Now, I could just leave the result there, eliminating this problem. However, for presentation reasons, I need to copy it to the rest of the bins so the next function, which plots the data, looks prettier.


Anon Mike
Anon Mike
If the source and destination buffers overlap the operation of memcpy is *not defined*. Something like memcpy(p+1, p, 10) could shift the all the elements one spot or it could just as easily set all the elements equal to the first one or interleave them in some wierd way.

If you actually want to copy a buffer to some overlapping location you should use memmove instead. memcpy is only guaranteed for non-overlapping buffers.

MSDN says std::copy is defined to shift elements to the left. I'm not sure what that means offhand.
-Mike
MaulingMonkey
MaulingMonkey
Quote:
If you actually want to copy a buffer to some overlapping location you should use memmove instead. memcpy is only guaranteed for non-overlapping buffers.

MSDN says std::copy is defined to shift elements to the left. I'm not sure what that means offhand.


Quote:
Because the algorithm copies the source elements in order beginning with the first element, the destination range can overlap with the source range provided the _First position of the source range is not contained in the destination range. copy can be used to shift elements to the left but not the right, unless there is no overlap between the source and destination ranges. To shift to the right any number of positions, use the copy_backward algorithm.


Basically:

std::vector< int > example( ... );<strike>std::copy          ( example.begin() + 1 , example.end()     , example.begin()     ); //shifts everything left 1 element  - <font color="green">OK</font>std::copy          ( example.begin()     , example.end() - 1 , example.begin() + 1 ); //shifts everything right 1 element - <font color="red">NOT OK</font>std::backwards_copy( example.begin()     , example.end() - 1 , example.begin() + 1 ); //shifts everything right 1 element - <font color="green">OK</font>std::backwards_copy( example.begin() + 1 , example.end()     , example.begin()     ); //shifts everything left 1 element  - <font color="red">NOT OK</font></strike>std::copy         ( example.begin() + 1 , example.end()     , example.begin()     ); //shifts everything left 1 element  - <font color="green">OK</font>std::copy         ( example.begin()     , example.end() - 1 , example.begin() + 1 ); //shifts everything right 1 element - <font color="red">NOT OK</font>std::copy_backward( example.begin()     , example.end() - 1 , example.end()       ); //shifts everything right 1 element - <font color="green">OK</font>std::copy_backward( example.begin() + 1 , example.end()     , example.end() - 1   ); //shifts everything left 1 element  - <font color="red">NOT OK</font>


Quote:
Originally posted by me22
Warning, I think you need to check that.


Yes. You would have thought I would have learned to read API documentation... and keep the name of the function straight for 5 seconds. Guess not :-p.

[Edited by - MaulingMonkey on November 1, 2005 9:16:09 PM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.