imam edin problem...
10 отговора
533 прегледа
imam edin problem...
triabva mi da kopiram edna stoinost s golemina maksimum __int64 na niakolko posledovatelni elementa v masiv ot __int64
problema e che s memset ne stava poneze e samo za po edin byte ,a s direktno prisvoiavane shte e tvirde bavno
niakoi da ima ideia kak da stane tova?
(ot Asembler ne razbiram tii che ako predlagate s nego napravo pratete kod)
Blagodariia predvaritelno na vsichki
problema e che s memset ne stava poneze e samo za po edin byte ,a s direktno prisvoiavane shte e tvirde bavno
niakoi da ima ideia kak da stane tova?
(ot Asembler ne razbiram tii che ako predlagate s nego napravo pratete kod)
Blagodariia predvaritelno na vsichki
Re: imam edin problem...
Директното присвояване няма да стане бавно. Ако работиш под Visual C++ въобще няма нужда да се притесняваш. Оптимизациите му са доста ефикасни. Практически един от най-добрите компилатори в това отношение.
Re: imam edin problem...
Сега вече имам малко повече време та мога да дам пример затова колко ефикасни са оптимизациите на VC++. Следния фрагмент:
Се компилира до:
Когато го видях за пръв път реших че има бъг в оптимизацията, та трябваше да се вгледам по-внимателно докато видя какво прави. С други думи не си губи времето да търсиш по-ефикасни начини. Просто сложи оптимизациите за въпросния участък на максимум и VC++ ще генерира практически оптимален код.
int main (int argc, char *argv)
{
int i;
__int64 buffer [256];
for (i = 0; i < 256; ++i) {
buffer = 0x12345678;
}
...
}
Се компилира до:
mov ecx, 1FEh
lea esi, [esp+8]
lea edi, [esp+10h]
mov dword ptr [esp+8], 12345678h
mov dword ptr [esp+0Ch], 0
rep movs dword ptr [edi], dword ptr [esi]
Когато го видях за пръв път реших че има бъг в оптимизацията, та трябваше да се вгледам по-внимателно докато видя какво прави. С други думи не си губи времето да търсиш по-ефикасни начини. Просто сложи оптимизациите за въпросния участък на максимум и VC++ ще генерира практически оптимален код.
Re: imam edin problem...
С други думи не си губи времето да търсиш по-ефикасни начини. Просто сложи оптимизациите за въпросния участък на максимум и VC++ ще генерира практически оптимален код.
Re: imam edin problem...
с други думи.
buffer[0] = value;
memcpy( &buffer[1], buffer, там колкото трябва ).
btw C компилатора на Intel (5.0.1) unroll-на loop-a - не напълно разбира се, но на всеки цикъл записваше по 4 елемента в масива.
предполагам, че така е още по-бързо...
buffer[0] = value;
memcpy( &buffer[1], buffer, там колкото трябва ).
btw C компилатора на Intel (5.0.1) unroll-на loop-a - не напълно разбира се, но на всеки цикъл записваше по 4 елемента в масива.
предполагам, че така е още по-бързо...
Re: imam edin problem...
> buffer[0] = value;
> memcpy( &buffer[1], buffer, там колкото трябва ).
Да.
> btw C компилатора на Intel (5.0.1) unroll-на loop-a - не напълно разбира се,
> но на всеки цикъл записваше по 4 елемента в масива.
> предполагам, че така е още по-бързо...
Странно. Досега бях готов да се обзаложа че rep movs е по-бързо от unroll-нат loop. Ако ми остане малко време вечерта ще пробвам да вмъкна по една rdtsc инструкция преди и след loop-а за да видя колко такта отнема всеки вариант. Все пак нямам под ръка компилатора на Intel, така че ще трябва да импровизирам с unroll-ването.
> memcpy( &buffer[1], buffer, там колкото трябва ).
Да.
> btw C компилатора на Intel (5.0.1) unroll-на loop-a - не напълно разбира се,
> но на всеки цикъл записваше по 4 елемента в масива.
> предполагам, че така е още по-бързо...
Странно. Досега бях готов да се обзаложа че rep movs е по-бързо от unroll-нат loop. Ако ми остане малко време вечерта ще пробвам да вмъкна по една rdtsc инструкция преди и след loop-а за да видя колко такта отнема всеки вариант. Все пак нямам под ръка компилатора на Intel, така че ще трябва да импровизирам с unroll-ването.
Re: imam edin problem...
Ima i drug na4in - da se izpolzwa FPU-to. 4rez fild i fist se postiga o6te po-golqma skorost - move da se premestwat 4etworni dumi. Move da se napravi i s MMX instrukcii. Ama dokolkoto si spomnqm s fild i fist be6e po-byrzo (zasi4al sym go).
Na
Na
Re: imam edin problem...
blagodariia na vsichki samo deto nishto ne razbrah ot toiia kod na Asembler
do Penguin :
kide da kaza na kompilatora da optimizira koda?
do Penguin :
kide da kaza na kompilatora da optimizira koda?
Re: imam edin problem...
Аз ли съм тъп, или има нещо гнило? Я вижте таз функцийка:
void memcpyEx(void *dest, void *src, int nSrcSize, int nLoopSize)
{
int nIterations = 2;
int nTrail = 0;
nIterations = (int)sqrt(nLoopSize * nSrcSize);
nTrail = nLoopSize - (int)pow(2, nIterations);
_asm
{
cld
mov esi, src
mov edi, dest
mov ecx, nSrcSize
rep movsd
mov eax, nIterations
cmp eax, 0
jz trail
mov bl, 0
begin:
mov esi, dest
mov edx, nSrcSize
mov cl, bl
shl edx, cl
mov ecx, edx
rep movsd
inc bl
dec eax
jnz begin
trail:
cld
mov ecx, nTrail
cmp ecx, 0
jz end
mov esi, dest
rep movsd
end:
}
}
Идеята е dest да се запълва с nLoopSize броя копия на src, като при това запълването да става чрез копиране на вече готови запълнени области. Т.е. ако *src = 5, dest е масив от 16 елемента, които трябва да са запълнени с 5-ци, то процеса ще има такъв вид:
5
55
5555
55555555
5555555555555555
Ако обаче има остатък, т.е. корена на броя на запълванията има остатък, то се налага доп. прехвърляне на остататъка вън от цикъла. В кода това се извършва в секцията след trail: етикета.
И сега проблемът: При ето такова извикване
int arr[11], n
n=5
memcpyEx(arr, &n, 1, 11);
алгоритъмът има остатък nTrail == 3. Обаче при изпълнението на
trail:
cld
mov ecx, nTrail
cmp ecx, 0
jz end
mov esi, dest
rep movsd
се прехвърлят само 2 стойности, въпреки, че ecx == 3. Всъщност, независимо какъв е остатъка, винаги се прехвърлят само 2 стойности. От какво може да е това?
Si Vis Pacem, Para Bellum
void memcpyEx(void *dest, void *src, int nSrcSize, int nLoopSize)
{
int nIterations = 2;
int nTrail = 0;
nIterations = (int)sqrt(nLoopSize * nSrcSize);
nTrail = nLoopSize - (int)pow(2, nIterations);
_asm
{
cld
mov esi, src
mov edi, dest
mov ecx, nSrcSize
rep movsd
mov eax, nIterations
cmp eax, 0
jz trail
mov bl, 0
begin:
mov esi, dest
mov edx, nSrcSize
mov cl, bl
shl edx, cl
mov ecx, edx
rep movsd
inc bl
dec eax
jnz begin
trail:
cld
mov ecx, nTrail
cmp ecx, 0
jz end
mov esi, dest
rep movsd
end:
}
}
Идеята е dest да се запълва с nLoopSize броя копия на src, като при това запълването да става чрез копиране на вече готови запълнени области. Т.е. ако *src = 5, dest е масив от 16 елемента, които трябва да са запълнени с 5-ци, то процеса ще има такъв вид:
5
55
5555
55555555
5555555555555555
Ако обаче има остатък, т.е. корена на броя на запълванията има остатък, то се налага доп. прехвърляне на остататъка вън от цикъла. В кода това се извършва в секцията след trail: етикета.
И сега проблемът: При ето такова извикване
int arr[11], n
n=5
memcpyEx(arr, &n, 1, 11);
алгоритъмът има остатък nTrail == 3. Обаче при изпълнението на
trail:
cld
mov ecx, nTrail
cmp ecx, 0
jz end
mov esi, dest
rep movsd
се прехвърлят само 2 стойности, въпреки, че ecx == 3. Всъщност, независимо какъв е остатъка, винаги се прехвърлят само 2 стойности. От какво може да е това?
Si Vis Pacem, Para Bellum