powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Ну очень быстрый Move() для x86/x64
38 сообщений из 38, показаны все 2 страниц
Ну очень быстрый Move() для x86/x64
    #38778988
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Привет
Все знают, какой я фанат оптимизаций, и вместе с тем нелюбитель писать тесты замера скорости

Так вот несколько месяцев назад я с ужасом обнаружил, что используемые ранее (REP) MOVS команды - тормозные. Что обычный цикл записи работает быстрее. Кроме того реализация Move() в Delphi x64 оставляет желать лучшего мягко говоря (впрочем как и многое в RTL x64).

Если я ничего не путаю, то скомпилированные x86 приложения в новых версиях Delphi не работают на машинах без поддержки SSE2. Это даёт мне все основания реализовать Move() через SSE(1).

Весомое значение в стандартных Move() реализациях занимает ситуация с пересекающимися областями. Мне эта особенность нужна редко (впрочем как и многим). И поскольку я планирую реформу CachedBuffers, достаточно много внимания было уделено и Move(), потому что библиотека целиком и полностью посвящена копировании памяти.

В итоге реализация выполнена, листинг приведу ниже, функция полностью проверена и отлажена для платформ x86 и x64.
Поэтому:
1) Берите кому нужно
2) Если есть желание делать сравнительный тест скорости и вносить изменения - я за. Но гарантирую, что сам писать такой тест не буду. Нужно определиться с условиями, искать конкурентные реализации, закладываться на разное выравнивание. У меня на это времени и желания нет. Со своей стороны могу гарантировать лучшую производительность на x64 и для больших объёмов на x86. Но насколько именно - я увы не знаю. Have fun
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
// SSE-based non-collision Move() realization
procedure NonCollisionMove(const Source; var Dest; const Size: NativeUInt);
asm
  // basic routine
  {$ifdef CPUX86}
    cmp ecx, 32
  {$else .CPUX64}
    cmp r8, 32
    // make Source = eax/rax, Dest = edx/rdx, Size = ecx/rcx
    mov rax, rcx
    xchg rcx, r8
    // r9 as pointer to @move_03_items
    lea r9, [@move_03_items]
  {$endif}

  // is big/large (32...inf)
  jae @move_big

  // is small (0..3)
  cmp ecx, 4
  jb @move_03

  // move middle(4..31) = move 16(0..16) + move dwords(0..12) + move small(0..3)
  cmp ecx, 16
  jb @move_015

  {$ifdef CPUX86}
    movups xmm0, [eax]
    movups [edx], xmm0
    jne @move_015_offset
    ret
  @move_015_offset:
    sub ecx, 16
    add eax, 16
    add edx, 16
  @move_015:
    push ecx
    and ecx, -4
    add eax, ecx
    add edx, ecx
    jmp [ecx + @move_dwords]
    @move_dwords: DD @rw_0,@rw_4,@rw_8,@rw_12
    @rw_12:
      mov ecx, [eax-12]
      mov [edx-12], ecx
    @rw_8:
      mov ecx, [eax-8]
      mov [edx-8], ecx
    @rw_4:
      mov ecx, [eax-4]
      mov [edx-4], ecx
    @rw_0:
    pop ecx
    and ecx, 3
  {$else .CPUX64}
    movups xmm0, [rax]
    movups [rdx], xmm0
    jne @move_015_offset
    ret
  @move_015_offset:
    sub rcx, 16
    add rax, 16
    add rdx, 16
  @move_015:
    // make r9 = dest 0..3 pointer, rcx = dwords count
    mov r8, rcx
    shr rcx, 2
    and r8, 3
    lea r9, [r9 + r8*8]
    // case jump
    lea r8, [@move_dwords]
    jmp qword ptr [r8 + rcx*8]
    @move_dwords: DQ @rw_0,@rw_4,@rw_8,@rw_12
    @rw_8:
      mov rcx, [rax]
      mov [rdx], rcx
      add rax, 8
      add rdx, 8
    jmp qword ptr [r9]
    @rw_12:
      mov rcx, [rax]
      mov [rdx], rcx
      add rax, 8
      add rdx, 8
    @rw_4:
      mov ecx, [rax]
      mov [rdx], ecx
      add rax, 4
      add rdx, 4
    @rw_0:  
    jmp qword ptr [r9]
  {$endif}

@move_03:
  {$ifdef CPUX86}
    jmp [offset @move_03_items + ecx*4]
    @move_03_items: DD @0,@1,@2,@3
    @2: mov cx, [eax]
        mov [edx], cx
        ret
    @3: mov cx, [eax]
        mov [edx], cx
        add eax, 2
        add edx, 2
    @1: mov cl, [eax]
        mov [edx], cl
    @0: ret
  {$else .CPUX64}
    jmp qword ptr [r9 + rcx*8]
    @move_03_items: DQ @0,@1,@2,@3
    @2: mov cx, [rax]
        mov [rdx], cx
        ret
    @3: mov cx, [rax]
        mov [rdx], cx
        add rax, 2
        add rdx, 2
    @1: mov cl, [rax]
        mov [rdx], cl
    @0: ret
  {$endif}

@move_big:
  {$ifdef CPUX86}
    cmp ecx, 16*4
  {$else .CPUX64}
    cmp rcx, 16*4
  {$endif}
  jae @move_large
  
  // big memory move by SSE (32..63) = (32..48) + (0..15)
  {$ifdef CPUX86}
     test ecx, 15
     jz @move_32_48

     push ecx
     and ecx, 15
     movups xmm0, [eax]
     movups [edx], xmm0
     add eax, ecx
     add edx, ecx

     pop ecx
     and ecx, -16
  {$else .CPUX64}
     mov r8, rcx
     test rcx, 15
     jz @move_32_48

     and r8, 15
     movups xmm0, [rax]
     movups [rdx], xmm0
     add rax, r8
     add rdx, r8

     and rcx, -16
  {$endif}

@move_32_48:
  {$ifdef CPUX86}
    add eax, ecx
    add edx, ecx
    cmp ecx, 48
    jb @rw_32
    @rw_48: movups xmm2, [eax - 2*16 - 16]
            movups [edx - 2*16 - 16], xmm2
    @rw_32: movups xmm1, [eax - 1*16 - 16]
            movups xmm0, [eax - 0*16 - 16]
            movups [edx - 1*16 - 16], xmm1
            movups [edx - 0*16 - 16], xmm0
  {$else .CPUX64}
    add rax, rcx
    add rdx, rcx
    cmp rcx, 48
    jb @rw_32    
    @rw_48: movups xmm2, [rax - 2*16 - 16]
            movups [rdx - 2*16 - 16], xmm2
    @rw_32: movups xmm1, [rax - 1*16 - 16]
            movups xmm0, [rax - 0*16 - 16]
            movups [rdx - 1*16 - 16], xmm1
            movups [rdx - 0*16 - 16], xmm0
  {$endif}

  ret
@move_large:
  // large memory move by SSE (64..inf)

  // destination alignment
  {$ifdef CPUX86}
    push ebx
    test edx, 15
    jz @move_16128_initialize

    mov ebx, edx
    movups xmm0, [eax]
    movups [ebx], xmm0

    add edx, 15
    and edx, -16
    sub ebx, edx
    sub eax, ebx
    add ecx, ebx
  {$else .CPUX64}
    test rdx, 15
    jz @move_16128_initialize

    mov r8, rdx
    movups xmm0, [rax]
    movups [r8], xmm0

    add rdx, 15
    and rdx, -16
    sub r8, rdx
    sub rax, r8
    add rcx, r8
  {$endif}

@move_16128_initialize:
  {$ifdef CPUX86}
    push ecx
    mov ebx, offset @aligned_reads
    shr ecx, 4
    test eax, 15
    jz @move_16128
    mov ebx, offset @unaligned_reads
  {$else .CPUX64}
    mov r8, rcx
    lea r9, [@aligned_reads]
    shr rcx, 4
    test rax, 15
    jz @move_16128
    lea r9, [@unaligned_reads]
  {$endif}

@move_16128:
  {$ifdef CPUX86}
    cmp ecx, 8
    jae @move_128

    lea ecx, [ecx + ecx]
    lea eax, [eax + ecx*8]
    lea edx, [edx + ecx*8]
    lea ebx, [ebx + 8*4]
    neg ecx
    lea ebx, [ebx + ecx*2]
    jmp ebx
  @move_128:
    lea eax, [eax + 128]
    lea edx, [edx + 128]
    lea ecx, [ecx - 8]
    jmp ebx
  {$else .CPUX64}
    cmp rcx, 8
    jae @move_128

    lea rcx, [rcx + rcx]
    lea rax, [rax + rcx*8]
    lea rdx, [rdx + rcx*8]
    lea r9, [r9 + 8*4]
    neg rcx
    lea r9, [r9 + rcx*2]
    jmp r9
  @move_128:
    lea rax, [rax + 128]
    lea rdx, [rdx + 128]
    lea rcx, [rcx - 8]
    jmp r9
  {$endif}

  // aligned sse read
  @aligned_reads:
  {$ifdef CPUX86}
    movaps xmm7, [eax - 7*16 - 16]
    movaps xmm6, [eax - 6*16 - 16]
    movaps xmm5, [eax - 5*16 - 16]
    movaps xmm4, [eax - 4*16 - 16]
    movaps xmm3, [eax - 3*16 - 16]
    movaps xmm2, [eax - 2*16 - 16]
    movaps xmm1, [eax - 1*16 - 16]
    movaps xmm0, [eax - 0*16 - 16]
  {$else .CPUX64}
    movaps xmm7, [rax - 7*16 - 16]
    movaps xmm6, [rax - 6*16 - 16]
    movaps xmm5, [rax - 5*16 - 16]
    movaps xmm4, [rax - 4*16 - 16]
    movaps xmm3, [rax - 3*16 - 16]
    movaps xmm2, [rax - 2*16 - 16]
    movaps xmm1, [rax - 1*16 - 16]
    movaps xmm0, [rax - 0*16 - 16]
  {$endif}
  jae @aligned_writes
  jmp @write_16112

  // unaligned sse read
  @unaligned_reads:
  {$ifdef CPUX86}
    movups xmm7, [eax - 7*16 - 16]
    movups xmm6, [eax - 6*16 - 16]
    movups xmm5, [eax - 5*16 - 16]
    movups xmm4, [eax - 4*16 - 16]
    movups xmm3, [eax - 3*16 - 16]
    movups xmm2, [eax - 2*16 - 16]
    movups xmm1, [eax - 1*16 - 16]
    movups xmm0, [eax - 0*16 - 16]
    jae @aligned_writes
  @write_16112:
    lea ebx, [offset @aligned_writes + 8*4 + ecx*2]
    jmp ebx
  {$else .CPUX64}
    movups xmm7, [rax - 7*16 - 16]
    movups xmm6, [rax - 6*16 - 16]
    movups xmm5, [rax - 5*16 - 16]
    movups xmm4, [rax - 4*16 - 16]
    movups xmm3, [rax - 3*16 - 16]
    movups xmm2, [rax - 2*16 - 16]
    movups xmm1, [rax - 1*16 - 16]
    movups xmm0, [rax - 0*16 - 16]
    jae @aligned_writes
  @write_16112:
    lea r9, [@aligned_writes + 8*4]
    lea r9, [r9 + rcx*2]
    jmp r9
  {$endif}

  // aligned sse write, loop
  @aligned_writes:
  {$ifdef CPUX86}
    movaps [edx - 7*16 - 16], xmm7
    movaps [edx - 6*16 - 16], xmm6
    movaps [edx - 5*16 - 16], xmm5
    movaps [edx - 4*16 - 16], xmm4
    movaps [edx - 3*16 - 16], xmm3
    movaps [edx - 2*16 - 16], xmm2
    movaps [edx - 1*16 - 16], xmm1
    movaps [edx - 0*16 - 16], xmm0
    test ecx, ecx
  {$else .CPUX64}
    movaps [rdx - 7*16 - 16], xmm7
    movaps [rdx - 6*16 - 16], xmm6
    movaps [rdx - 5*16 - 16], xmm5
    movaps [rdx - 4*16 - 16], xmm4
    movaps [rdx - 3*16 - 16], xmm3
    movaps [rdx - 2*16 - 16], xmm2
    movaps [rdx - 1*16 - 16], xmm1
    movaps [rdx - 0*16 - 16], xmm0
    test rcx, rcx
  {$endif}
  jg @move_16128

  // last 0..15 bytes
  {$ifdef CPUX86}
    pop ecx
    pop ebx
    and ecx, 15
    jnz @move_115
    ret
  @move_115:
    add eax, ecx
    add edx, ecx
    movups xmm0, [eax - 0*16 - 16]
    movups [edx - 0*16 - 16], xmm0
  {$else .CPUX64}
    and r8, 15
    jnz @move_115
    ret
  @move_115:
    add rax, r8
    add rdx, r8
    movups xmm0, [rax - 0*16 - 16]
    movups [rdx - 0*16 - 16], xmm0
  {$endif}
end;
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38778994
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
// для поддержки старых версий

{$if (CompilerVersion < 23) and (not Defined(FPC))}
  {$define CPUX86}
{$ifend}

{$if CompilerVersion < 19}
type
  NativeInt = Integer;
  PNativeInt = PInteger;
  NativeUInt = Cardinal;
  PNativeUInt = PCardinal;
{$ifend}
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38778998
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOUнесколько месяцев назад я с ужасом обнаружил, что используемые ранее
(REP) MOVS команды - тормозные
Ещё через пару лет ты откроешь для себя технику Zero-Copy, так что забей.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779011
asviridenkov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU,

Ну ты хоть какие-то тесты проведи, а то так совсем неинтересно.
Ну, типа, на пересылке 100Кб данных работает в 3 раза быстрее чем стандартная move
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779016
vavan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
можно старые бенчи от FastCode поднять
а потом все равно придет шарахов и всех разгонит
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779017
asviridenkov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU,

Кстати, раз ты такой фанат оптимизации... У меня, по опыту, на общую производительность влияет больше не move а функция поиска символа в строке. Ниже приведу текущую реализацию. Слабо улучшить?

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
{$IFDEF CPUx64}
function Q_PStrScan(P: pointer{RCX}; Ch: WideChar{RDX}; ASize: Integer{R8}): Integer; //x64, Unicode
asm
.NOFRAME
        TEST    RCX,RCX
        JE      @@m2
        TEST    R8,R8
        JE      @@m2
        MOV     R9,RDI
        MOV     RDI,RCX   //EDI=P
        MOV     RAX,RDX
        MOV     RDX,RCX   //EDX=P
        MOV     RCX,R8
        REPNE   SCASW
        JNE     @@m1
        MOV     RAX,RDI
        SUB     RAX,RDX
        SHR     RAX,1
        MOV     RDI,R9
        RET
@@m1:   MOV     RDI,R9
@@m2:   XOR     RAX,RAX
end;
{$ELSE}
{$IFDEF UNICODE}
function Q_PStrScan(P: pointer; Ch: Char; ASize: Integer): Integer;  //x32, Unicode
asm
        TEST    EAX,EAX   //P=nil?
        JE      @@qt
        TEST    ECX,ECX   //ASize=0?
        JE      @@qt
        PUSH    EDI
        MOV     EDI,EAX   //EDI=P
        XCHG    EAX,EDX   //EDX=P
        REPNE   SCASW
        JNE     @@m1
        MOV     EAX,EDI
        SUB     EAX,EDX
        SHR     EAX,1
        POP     EDI
        RET
@@m1:   POP     EDI
        XOR     EAX,EAX
@@qt:
end;
{$ELSE}
function Q_PStrScan(P: pointer; Ch: Char; ASize: Integer): Integer; //x32, Ansi
asm
        TEST    EAX,EAX
        JE      @@qt
        TEST    ECX,ECX
        JE      @@qt
        PUSH    EDI
        MOV     EDI,EAX   //EDI=P
        XCHG    EAX,EDX   //EDX=P
        REPNE   SCASB
        JNE     @@m1
        MOV     EAX,EDI
        SUB     EAX,EDX
        POP     EDI
        RET
@@m1:   POP     EDI
        XOR     EAX,EAX
@@qt:
end;
{$ENDIF} //Unicode
{$ENDIF} //x64
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779038
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry SibiryakovЕщё через пару лет ты откроешь для себя технику Zero-Copy, так что забей.
Как ты предлагаешь Zero-Copy вставить в Move? :)

asviridenkovНу ты хоть какие-то тесты проведи, а то так совсем неинтересно.
Ну, типа, на пересылке 100Кб данных работает в 3 раза быстрее чем стандартная move
Да хз. Мне кажется не будет в 3 раза. Всё-таки многое упирается в кеш. Ну максимум процентов на 20-50
Хотя чем чёрт не шутит, надо смотреть. Я лишь знаю, что SSE, да в моём исполнении, должен дать прирост

vavanможно старые бенчи от FastCode поднять
а потом все равно придет шарахов и всех разгонит
Можно
Я за
Сделай если не лень

asviridenkovКстати, раз ты такой фанат оптимизации... У меня, по опыту, на общую производительность влияет больше не move а функция поиска символа в строке. Ниже приведу текущую реализацию. Слабо улучшить?
Фу, ацтой!
Есть же подходы, позволяющие найти символ в одной из частей регистра. Но в твоём случае надо будет придумать с выравниванием и SSE
Посмотри здесь: http://www.wasm.ru/forum/viewtopic.php?id=16358&p=1
А в тырнете поищи константы 7EFEFEFF и 81010100
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779041
Artem_Nav
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я бы не заморачивался особо. По следующей причине :
А недавно вдруг раз, и все вернулось на круги своя. (Может быть, для того, чтобы не заставлять переписывать memcpy на AVX?) Для последних процессоров классическая реализация memcpy снова самая быстрая. Так что если кто-то проспал 34 года, самое время вытащить старый код, и победно посмотреть на коллег, которые переписывали memcpy последовательно на MMX, SSE2, SSE3, SSE4.1.

Думаю, вскоре и AMD подтянется, а через пару-тройку лет все велосипеды будут не нужны вообще :)
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779050
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Artem_NavЯ бы не заморачивался особо. По следующей причине:
Думаю, вскоре и AMD подтянется, а через пару-тройку лет все велосипеды будут не нужны вообще :)
Поживём-увидим
Я лишь исхожу из того, что актуально сегодня

All ,
Слушайте!
Я сейчас почитал, для архитектуры x64 нельзя свободно использовать xmm6 и xmm7 - их надо сохранять на стеке
Сейчас исправлю

А есть такие же ограничения для x86?
По моему нет
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779059
Dimitry Sibiryakov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOUКак ты предлагаешь Zero-Copy вставить в Move? :)
Посредством Ctrl-Y. Если твой алгоритм требует использования Move(), значит это
неправильный алгоритм.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779066
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем функция отныне выглядит так (добавлено сохранение/восстановление xmm6 и xmm7 в случае необходимости):
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
// SSE-based non-collision Move() realization
procedure NonCollisionMove(const Source; var Dest; const Size: NativeUInt);
asm
  // basic routine
  {$ifdef CPUX86}
    cmp ecx, 32
  {$else .CPUX64}
    cmp r8, 32
    // make Source = eax/rax, Dest = edx/rdx, Size = ecx/rcx
    mov rax, rcx
    xchg rcx, r8
    // r9 as pointer to @move_03_items
    lea r9, [@move_03_items]
  {$endif}

  // is big/large (32...inf)
  jae @move_big

  // is small (0..3)
  cmp ecx, 4
  jb @move_03

  // move middle(4..31) = move 16(0..16) + move dwords(0..12) + move small(0..3)
  cmp ecx, 16
  jb @move_015

  {$ifdef CPUX86}
    movups xmm0, [eax]
    movups [edx], xmm0
    jne @move_015_offset
    ret
  @move_015_offset:
    sub ecx, 16
    add eax, 16
    add edx, 16
  @move_015:
    push ecx
    and ecx, -4
    add eax, ecx
    add edx, ecx
    jmp [ecx + @move_dwords]
    @move_dwords: DD @rw_0,@rw_4,@rw_8,@rw_12
    @rw_12:
      mov ecx, [eax-12]
      mov [edx-12], ecx
    @rw_8:
      mov ecx, [eax-8]
      mov [edx-8], ecx
    @rw_4:
      mov ecx, [eax-4]
      mov [edx-4], ecx
    @rw_0:
    pop ecx
    and ecx, 3
  {$else .CPUX64}
    movups xmm0, [rax]
    movups [rdx], xmm0
    jne @move_015_offset
    ret
  @move_015_offset:
    sub rcx, 16
    add rax, 16
    add rdx, 16
  @move_015:
    // make r9 = dest 0..3 pointer, rcx = dwords count
    mov r8, rcx
    shr rcx, 2
    and r8, 3
    lea r9, [r9 + r8*8]
    // case jump
    lea r8, [@move_dwords]
    jmp qword ptr [r8 + rcx*8]
    @move_dwords: DQ @rw_0,@rw_4,@rw_8,@rw_12
    @rw_8:
      mov rcx, [rax]
      mov [rdx], rcx
      add rax, 8
      add rdx, 8
    jmp qword ptr [r9]
    @rw_12:
      mov rcx, [rax]
      mov [rdx], rcx
      add rax, 8
      add rdx, 8
    @rw_4:
      mov ecx, [rax]
      mov [rdx], ecx
      add rax, 4
      add rdx, 4
    @rw_0:  
    jmp qword ptr [r9]
  {$endif}

@move_03:
  {$ifdef CPUX86}
    jmp [offset @move_03_items + ecx*4]
    @move_03_items: DD @0,@1,@2,@3
    @2: mov cx, [eax]
        mov [edx], cx
        ret
    @3: mov cx, [eax]
        mov [edx], cx
        add eax, 2
        add edx, 2
    @1: mov cl, [eax]
        mov [edx], cl
    @0: ret
  {$else .CPUX64}
    jmp qword ptr [r9 + rcx*8]
    @move_03_items: DQ @0,@1,@2,@3
    @2: mov cx, [rax]
        mov [rdx], cx
        ret
    @3: mov cx, [rax]
        mov [rdx], cx
        add rax, 2
        add rdx, 2
    @1: mov cl, [rax]
        mov [rdx], cl
    @0: ret
  {$endif}

@move_big:
  {$ifdef CPUX86}
    cmp ecx, 16*4
  {$else .CPUX64}
    cmp rcx, 16*4
  {$endif}
  jae @move_large
  
  // big memory move by SSE (32..63) = (32..48) + (0..15)
  {$ifdef CPUX86}
     test ecx, 15
     jz @move_32_48

     push ecx
     and ecx, 15
     movups xmm0, [eax]
     movups [edx], xmm0
     add eax, ecx
     add edx, ecx

     pop ecx
     and ecx, -16
  {$else .CPUX64}
     mov r8, rcx
     test rcx, 15
     jz @move_32_48

     and r8, 15
     movups xmm0, [rax]
     movups [rdx], xmm0
     add rax, r8
     add rdx, r8

     and rcx, -16
  {$endif}

@move_32_48:
  {$ifdef CPUX86}
    add eax, ecx
    add edx, ecx
    cmp ecx, 48
    jb @rw_32
    @rw_48: movups xmm2, [eax - 2*16 - 16]
            movups [edx - 2*16 - 16], xmm2
    @rw_32: movups xmm1, [eax - 1*16 - 16]
            movups xmm0, [eax - 0*16 - 16]
            movups [edx - 1*16 - 16], xmm1
            movups [edx - 0*16 - 16], xmm0
  {$else .CPUX64}
    add rax, rcx
    add rdx, rcx
    cmp rcx, 48
    jb @rw_32    
    @rw_48: movups xmm2, [rax - 2*16 - 16]
            movups [rdx - 2*16 - 16], xmm2
    @rw_32: movups xmm1, [rax - 1*16 - 16]
            movups xmm0, [rax - 0*16 - 16]
            movups [rdx - 1*16 - 16], xmm1
            movups [rdx - 0*16 - 16], xmm0
  {$endif}

  ret
@move_large:
  // large memory move by SSE (64..inf)

  // destination alignment
  {$ifdef CPUX86}
    push ebx
    test edx, 15
    jz @move_16128_initialize

    mov ebx, edx
    movups xmm0, [eax]
    movups [ebx], xmm0

    add edx, 15
    and edx, -16
    sub ebx, edx
    sub eax, ebx
    add ecx, ebx
  {$else .CPUX64}
    test rdx, 15
    jz @move_16128_initialize

    mov r8, rdx
    movups xmm0, [rax]
    movups [r8], xmm0

    add rdx, 15
    and rdx, -16
    sub r8, rdx
    sub rax, r8
    add rcx, r8
  {$endif}

@move_16128_initialize:
  {$ifdef CPUX86}
    push ecx
    mov ebx, offset @aligned_reads
    shr ecx, 4
    test eax, 15
    jz @move_16128
    mov ebx, offset @unaligned_reads
  {$else .CPUX64}
    movaps [rsp-8-16], xmm6
    movaps [rsp-8-32], xmm7
    mov r8, rcx
    lea r9, [@aligned_reads]
    shr rcx, 4
    test rax, 15
    jz @move_16128
    lea r9, [@unaligned_reads]
  {$endif}

@move_16128:
  {$ifdef CPUX86}
    cmp ecx, 8
    jae @move_128

    lea ecx, [ecx + ecx]
    lea eax, [eax + ecx*8]
    lea edx, [edx + ecx*8]
    lea ebx, [ebx + 8*4]
    neg ecx
    lea ebx, [ebx + ecx*2]
    jmp ebx
  @move_128:
    lea eax, [eax + 128]
    lea edx, [edx + 128]
    lea ecx, [ecx - 8]
    jmp ebx
  {$else .CPUX64}
    cmp rcx, 8
    jae @move_128

    lea rcx, [rcx + rcx]
    lea rax, [rax + rcx*8]
    lea rdx, [rdx + rcx*8]
    lea r9, [r9 + 8*4]
    neg rcx
    lea r9, [r9 + rcx*2]
    jmp r9
  @move_128:
    lea rax, [rax + 128]
    lea rdx, [rdx + 128]
    lea rcx, [rcx - 8]
    jmp r9
  {$endif}

  // aligned sse read
  @aligned_reads:
  {$ifdef CPUX86}
    movaps xmm7, [eax - 7*16 - 16]
    movaps xmm6, [eax - 6*16 - 16]
    movaps xmm5, [eax - 5*16 - 16]
    movaps xmm4, [eax - 4*16 - 16]
    movaps xmm3, [eax - 3*16 - 16]
    movaps xmm2, [eax - 2*16 - 16]
    movaps xmm1, [eax - 1*16 - 16]
    movaps xmm0, [eax - 0*16 - 16]
  {$else .CPUX64}
    movaps xmm7, [rax - 7*16 - 16]
    movaps xmm6, [rax - 6*16 - 16]
    movaps xmm5, [rax - 5*16 - 16]
    movaps xmm4, [rax - 4*16 - 16]
    movaps xmm3, [rax - 3*16 - 16]
    movaps xmm2, [rax - 2*16 - 16]
    movaps xmm1, [rax - 1*16 - 16]
    movaps xmm0, [rax - 0*16 - 16]
  {$endif}
  jae @aligned_writes
  jmp @write_16112

  // unaligned sse read
  @unaligned_reads:
  {$ifdef CPUX86}
    movups xmm7, [eax - 7*16 - 16]
    movups xmm6, [eax - 6*16 - 16]
    movups xmm5, [eax - 5*16 - 16]
    movups xmm4, [eax - 4*16 - 16]
    movups xmm3, [eax - 3*16 - 16]
    movups xmm2, [eax - 2*16 - 16]
    movups xmm1, [eax - 1*16 - 16]
    movups xmm0, [eax - 0*16 - 16]
    jae @aligned_writes
  @write_16112:
    lea ebx, [offset @aligned_writes + 8*4 + ecx*2]
    jmp ebx
  {$else .CPUX64}
    movups xmm7, [rax - 7*16 - 16]
    movups xmm6, [rax - 6*16 - 16]
    movups xmm5, [rax - 5*16 - 16]
    movups xmm4, [rax - 4*16 - 16]
    movups xmm3, [rax - 3*16 - 16]
    movups xmm2, [rax - 2*16 - 16]
    movups xmm1, [rax - 1*16 - 16]
    movups xmm0, [rax - 0*16 - 16]
    jae @aligned_writes
  @write_16112:
    lea r9, [@aligned_writes + 8*4]
    lea r9, [r9 + rcx*2]
    jmp r9
  {$endif}

  // aligned sse write, loop
  @aligned_writes:
  {$ifdef CPUX86}
    movaps [edx - 7*16 - 16], xmm7
    movaps [edx - 6*16 - 16], xmm6
    movaps [edx - 5*16 - 16], xmm5
    movaps [edx - 4*16 - 16], xmm4
    movaps [edx - 3*16 - 16], xmm3
    movaps [edx - 2*16 - 16], xmm2
    movaps [edx - 1*16 - 16], xmm1
    movaps [edx - 0*16 - 16], xmm0
    test ecx, ecx
  {$else .CPUX64}
    movaps [rdx - 7*16 - 16], xmm7
    movaps [rdx - 6*16 - 16], xmm6
    movaps [rdx - 5*16 - 16], xmm5
    movaps [rdx - 4*16 - 16], xmm4
    movaps [rdx - 3*16 - 16], xmm3
    movaps [rdx - 2*16 - 16], xmm2
    movaps [rdx - 1*16 - 16], xmm1
    movaps [rdx - 0*16 - 16], xmm0
    test rcx, rcx
  {$endif}
  jg @move_16128

  // last 0..15 bytes
  {$ifdef CPUX86}
    pop ecx
    pop ebx
    and ecx, 15
    jnz @move_115
    ret
  @move_115:
    add eax, ecx
    add edx, ecx
    movups xmm0, [eax - 0*16 - 16]
    movups [edx - 0*16 - 16], xmm0
  {$else .CPUX64}
    movaps xmm6, [rsp-8-16]
    movaps xmm7, [rsp-8-32]
    and r8, 15
    jnz @move_115
    ret
  @move_115:
    add rax, r8
    add rdx, r8
    movups xmm0, [rax - 0*16 - 16]
    movups [rdx - 0*16 - 16], xmm0
  {$endif}
end;
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779068
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dimitry SibiryakovПосредством Ctrl-Y. Если твой алгоритм требует использования Move(), значит это
неправильный алгоритм.
Дим, мне кажется ты сегодня слишком устал :)
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779267
asviridenkov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOU,

Раз ты с SSE разбирался, скажи pls, есть возможность умножить 4-ре 32 битных числа в одном xmm регистре на одно 32-битное число, с возвратом младших 32 бит результата.
Ну или хотя-бы одной командой загрузить 32-битное число в xmm регистр с дублированием, как 4 32-битных числа. Потому как умножение одного xmm на другой я нашел, но без первых команд в нем смысла мало.
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779271
TVoid
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SOFT FOR YOU,
Все знают, какой я фанат оптимизаций, и вместе с тем нелюбитель писать тесты замера скорости
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
var
 mSize    :NativeUInt;
 tResult  :string;

procedure Test(aVoid:Pointer);
var 
 i,n:NativeInt;
 t:Cardinal;
 pA,pB:Pointer;
 zA,zB:PNativeInt;
begin
 tResult := 'Error?!';

 pA := GetMemory(mSize); // VirtualAlloc(nil,mSize,MEM_COMMIT or MEM_RESERVE,PAGE_READWRITE);//
 pB := GetMemory(mSize); // VirtualAlloc(nil,mSize,MEM_COMMIT or MEM_RESERVE,PAGE_READWRITE);//

 if (pA <> nil) and (pB <> nil) then begin
 
  n := mSize div sizeOf(zA^) - 1;

  t := GetTickCount();
   zA := pA; for i := 0 to n do begin zA^:=i; inc(zA);  end;
   zB := pB; for i := 0 to n do begin zB^:=i; inc(zB);  end;
  t := GetTickCount() - t; 
  tResult := IntToStr(mSize div (1024*1024))+'::'#9'Zz ' + IntToStr(t);

  
  t := GetTickCount();
   NonCollisionMove(pA^,pB^,mSize);
  t := GetTickCount() - t; 
  tResult :=tResult + #9'Na ' + IntToStr(t);

  t := GetTickCount();
   Move(pA^,pB^,mSize);
  t := GetTickCount() - t; 
  tResult := tResult + #9'Ma ' + IntToStr(t);

  t := GetTickCount();
   NonCollisionMove(pA^,pB^,mSize);
  t := GetTickCount() - t; 
  tResult := tResult + #9'Nb ' + IntToStr(t);

  t := GetTickCount();
   Move(pA^,pB^,mSize);
  t := GetTickCount() - t; 
  tResult := tResult + #9'Mb ' + IntToStr(t);  

  t := GetTickCount();
   NonCollisionMove(pA^,pB^,mSize);
  t := GetTickCount() - t; 
  tResult :=tResult + #9'Nc ' + IntToStr(t);
  
  
 end;
 FreeMemory(pB); // VirtualFree(pB,0,MEM_RELEASE); // 
 FreeMemory(pA); // VirtualFree(pA,0,MEM_RELEASE); //  
 
 SendMessage(Form1.Handle,WM_USER,0,0); 
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
 Caption := 'Go...';  
 Button1.Enabled := False;
 mSize := StrToInt64Def(Edit1.Text,512)*(1024*1024);
 CloseHandle(BeginThread(nil,0,@Test,nil,0,PCardinal(nil)^));
end;

procedure TForm1.WmUser(var Message: TMessage);
begin
 Caption := 'SuperTest!';
 Memo1.Lines.Add(tResult);
 Button1.Enabled := True;
end;



https://yadi.sk/d/k1AkSVvLc5csC
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779287
asviridenkov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
TVoid,

Получается выигрыш от силы 10%
То есть в целом приложении вообще его не будет
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779390
vavan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOUСделай если не леньлень конечно, для моих задач меня вполне устраивают фасткодерские
плюс на просторах в ассортименте прочих от интела, vs и т.п. если уж реально упираешься в move
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779393
vavan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vavanдля моих задач меня вполне устраивают фасткодерскиено твои инициативы всегда приветствую!
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779395
Фотография defecator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Пока я бухал спал, тут такая тема вчера была ))
Скачал тесты, преимущество максимум в несколько процентов.
Решил, что фтопку такие портянки, оно того не стоит.
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779455
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
asviridenkovРаз ты с SSE разбирался, скажи pls, есть возможность умножить 4-ре 32 битных числа в одном xmm регистре на одно 32-битное число, с возвратом младших 32 бит результата.
Ну или хотя-бы одной командой загрузить 32-битное число в xmm регистр с дублированием, как 4 32-битных числа. Потому как умножение одного xmm на другой я нашел, но без первых команд в нем смысла мало.
Да я не особо в SSE разбирался
Но для твоего случае используют SHUFPS
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779502
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
TVoid

Оу, спасибо за первый тест!
1) Я не понял, ты 5Гб ОЗУ копируешь?
2) У тебя a и b варианты не отличаются. Что за Nc?
3) Тесты у тебя упираются в кеш, и скорее всего в файл подкачки
4) Тестировать мне кажется нужно на трёх компиляторах: новый Delphi x86, новый Delphi x64, старый Delphi (где не FastCode реализация). Для каждого из этих случаев скорость копирования будет отличаться
5) Я посмотрел исходники Move, там идёт разделение градаций размера на 1..8, 9..32 и 32+. У меня немного другие. Думаю тестировать копирование больше, чем 100кб - смысла нет. Ну и потом нафига тестировать кеш-мисс, если на практике данные преимущественно в кеше, ну как минимум 3 уровня. Поэтому для размера предлагаю такую вот штуку:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
function RandomSize(): NativeInt;
begin
  case Random(4) of
    0: Result := 1 + Random(8-1+1); // 1..8
    1: Result := 9 + Random(32-9+1); // 9..32
    2: Result := 33 + Random(128-33+1); // 33..128
  else
    Result := Random(100*1024);
  end;
end;


6) Ну а для замера времени предлагаю устроить цикл. Причём обусловиться, что за замеряемое время копируется константный объём памяти, например порядка 1Гб
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
const
  MOVE_SIZE = 1 * 1024*1024*1024;

procedure RunMove(const Source; var Dest; const Size: NativeInt);
var
  i: Integer;
begin
  for i := 1 to MOVE_SIZE div Size do
  System.Move(Source, Dest, Size);
end;

procedure RunNcMove(const Source; var Dest; const Size: NativeInt);
var
  i: Integer;
begin
  for i := 1 to MOVE_SIZE div Size do
  NonCollisionMove(Source, Dest, Size);
end;


7) Ещё бы неплохо поиграться с выравниванием, как для Source, так и для Dest. Для стандартной реализации важно выравнивание на 8 байт, для моей - 16.
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779504
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
defecatorСкачал тесты, преимущество максимум в несколько процентов.
Решил, что фтопку такие портянки, оно того не стоит.
Твои выводы обусловлены неумением анализировать ситуацию :)
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779572
Фотография defecator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
SOFT FOR YOUdefecatorСкачал тесты, преимущество максимум в несколько процентов.
Решил, что фтопку такие портянки, оно того не стоит.
Твои выводы обусловлены неумением анализировать ситуацию :)

Да мне пофигу, я стараюсь память не копировать с места на место, а обходиться указателями.
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779584
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
defecatorДа мне пофигу, я стараюсь память не копировать с места на место, а обходиться указателями.
Да ты как бы не новатор :)
Но порой не получается обойтись без Move. Это и операции со строками, и динамическими массивами, и в моём случае запись/чтение данных в "стрим"
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779595
Фотография defecator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
SOFT FOR YOUdefecatorДа мне пофигу, я стараюсь память не копировать с места на место, а обходиться указателями.
Да ты как бы не новатор :)
Но порой не получается обойтись без Move. Это и операции со строками, и динамическими массивами, и в моём случае запись/чтение данных в "стрим"

Я разрабатываю, по большей части, проекты, которые должны работать 24x7x365,
и использование там типов String, динамических массивов и всяких SetLength категорически выкидывается.
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779605
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
defecatorЯ разрабатываю, по большей части, проекты, которые должны работать 24x7x365,
и использование там типов String, динамических массивов и всяких SetLength категорически выкидывается.
Я буду тебе благодарен, если ты избавишь нас от подробностей своей личной жизни
Спасибо :)
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779617
Фотография defecator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
SOFT FOR YOUНо порой не получается обойтись без Move. Это и операции со строками, и динамическими массивами, и в моём случае запись/чтение данных в "стрим"

Чтобы Move имело смысл как-то существенно ускорять, копировать нужно именно большие объёмы,
на малых объёмах разницы, видимой глазу, не будет, разве что эффект плацебо.
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38779646
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
defecatorЧтобы Move имело смысл как-то существенно ускорять, копировать нужно именно большие объёмы,
на малых объёмах разницы, видимой глазу, не будет, разве что эффект плацебо.
Чтобы Move имело смысл ускорять - нужно чтобы Move использовался часто. Это мой случай
И наверняка не только мой :)
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38780589
TVoid
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SOFT FOR YOU,
Src: https://yadi.sk/d/7ayPhNkoc6fEF
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
var
 mSize     :Cardinal;
 mOffsetS  :Cardinal;
 mOffsetD  :Cardinal;
 tResult  :string;

procedure Test(aVoid:Pointer);
const 
 GB = UInt64(8)*1024*1024*1024;
var 
 i,n,t :NativeUInt;
 pS,pD :Pointer;
begin

 tResult := 'Error?!';

 pS := VirtualAlloc(nil,mSize,MEM_COMMIT or MEM_RESERVE,PAGE_READWRITE); // pS := GetMemory(mSize); 
 pD := VirtualAlloc(nil,mSize,MEM_COMMIT or MEM_RESERVE,PAGE_READWRITE); // pD := GetMemory(mSize); 

 if (pS <> nil) and (pD <> nil) then begin

  ZeroMemory(pS,mSize);
  ZeroMemory(pD,mSize);
 
  n := GB div mSize - 1;
  tResult := IntToStr( mSize div 1024) +'KB x ' +IntToStr((n+1) div 1024) +'Kn S+' +IntToStr(mOffsetS) +' D+' +IntToStr(mOffsetD) +' :';

  pS := PByte(pS) + mOffsetS;
  pD := PByte(pD) + mOffsetD;
  if (mOffsetS > mOffsetD) then Dec(mSize, mOffsetS) else Dec(mSize, mOffsetD);
  
  t := GetTickCount();
   for i := 0 to n do NonCollisionMove(pS^,pD^,mSize);
  tResult := tResult + #9'Na ' + IntToStr(GetTickCount() - t);

  t := GetTickCount();
   for i := 0 to n do Move(pS^,pD^,mSize);
  tResult := tResult + #9'Ma ' + IntToStr(GetTickCount() - t);

  t := GetTickCount();
   for i := 0 to n do NonCollisionMove(pS^,pD^,mSize);
  tResult := tResult + #9'Nb ' + IntToStr(GetTickCount() - t);

  t := GetTickCount();
   for i := 0 to n do Move(pS^,pD^,mSize);
  tResult := tResult + #9'Mb ' + IntToStr(GetTickCount() - t);

  t := GetTickCount();
   for i := 0 to n do  NonCollisionMove(pS^,pD^,mSize);
  tResult := tResult + #9'Nc ' + IntToStr(GetTickCount() - t);

 end;
 
 pS:=PByte(pS)-mOffsetS;
 pD:=PByte(pD)-mOffsetD;

 VirtualFree(pD,0,MEM_RELEASE); // FreeMemory(pS);
 VirtualFree(pS,0,MEM_RELEASE); // FreeMemory(pD); 
 
 PostMessage(Form1.Handle,WM_USER,0,0); 
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 mSize := StrToIntDef(Edit1.Text,4); 
 mOffsetS := StrToIntDef(Edit2.Text,0);
 mOffsetD := StrToIntDef(Edit3.Text,0);   
 mSize:=mSize * 1024; 
 Button1.Enabled := False;
 CloseHandle(BeginThread(nil,0,@Test,nil,0,PCardinal(nil)^));
end;

procedure TForm1.WmUser(var Message: TMessage);
begin
 Memo1.Lines.Add(tResult);
 Button1.Enabled := True;                                  
end;



binXE4: https://yadi.sk/d/E3FCMpKLc6exQ
binXE7: https://yadi.sk/d/wqThCXNsc6esT

CPU E5-2670

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
///  Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz 

128KB x 64Kn S+0 D+1 :	Na 639	Ma 858	Nb 484	Mb 842	Nc 484
128KB x 64Kn S+0 D+1 :	Na 639	Ma 858	Nb 484	Mb 936	Nc 468
128KB x 64Kn S+1 D+0 :	Na 655	Ma 1482	Nb 468	Mb 1482	Nc 468
128KB x 64Kn S+1 D+0 :	Na 608	Ma 1482	Nb 468	Mb 1482	Nc 468
256KB x 32Kn S+0 D+1 :	Na 967	Ma 1108	Nb 795	Mb 1092	Nc 811
256KB x 32Kn S+0 D+1 :	Na 1014	Ma 1108	Nb 811	Mb 1107	Nc 796
512KB x 16Kn S+0 D+1 :	Na 998	Ma 1155	Nb 795	Mb 1108	Nc 796
512KB x 16Kn S+0 D+1 :	Na 983	Ma 1123	Nb 796	Mb 1107	Nc 812
512KB x 16Kn S+0 D+0 :	Na 858	Ma 1030	Nb 780	Mb 1045	Nc 780
1024KB x 8Kn S+0 D+1 :	Na 1139	Ma 1170	Nb 811	Mb 1107	Nc 812
1024KB x 8Kn S+0 D+1 :	Na 1014	Ma 1108	Nb 951	Mb 1108	Nc 827
2048KB x 4Kn S+0 D+1 :	Na 1045	Ma 1186	Nb 858	Mb 1185	Nc 858
2048KB x 4Kn S+0 D+0 :	Na 904	Ma 1139	Nb 812	Mb 1123	Nc 795
4096KB x 2Kn S+0 D+1 :	Na 1045	Ma 1170	Nb 874	Mb 1170	Nc 873 //
4096KB x 2Kn S+1 D+0 :	Na 1029	Ma 2044	Nb 827	Mb 2246	Nc 827 \\
2048KB x 4Kn S+1 D+0 :	Na 1014	Ma 2059	Nb 843	Mb 2044	Nc 842   //
1024KB x 8Kn S+1 D+0 :	Na 983	Ma 7114	Nb 795	Mb 6927	Nc 795 !!
1024KB x 8Kn S+1 D+0 :	Na 1107	Ma 6927	Nb 795	Mb 6958	Nc 811 !!
512KB x 16Kn S+1 D+0 :	Na 1030	Ma 1872	Nb 811	Mb 1888	Nc 795   \\
768KB x 10Kn S+1 D+0 :	Na 1061	Ma 1888	Nb 795	Mb 1857	Nc 795
1024KB x 8Kn S+1 D+0 :	Na 998	Ma 6927	Nb 795	Mb 6942	Nc 796 //
1024KB x 8Kn S+0 D+1 :	Na 998	Ma 1108	Nb 826	Mb 1108	Nc 827 \\
2048KB x 4Kn S+0 D+1 :	Na 1061	Ma 1186	Nb 873	Mb 1186	Nc 874
2048KB x 4Kn S+1 D+0 :	Na 1092	Ma 2044	Nb 826	Mb 2059	Nc 843
1024KB x 8Kn S+1 D+0 :	Na 967	Ma 6926	Nb 812	Mb 6926	Nc 811 //

4KB x 2048Kn S+0 D+0 :	Na 405	Ma 1045	Nb 266	Mb 873	Nc 265

8KB x 1024Kn S+0 D+0 :	Na 390	Ma 889	Nb 234	Mb 843	Nc 234
8KB x 1024Kn S+1 D+0 :	Na 452	Ma 952	Nb 328	Mb 936	Nc 312 +
8KB x 1024Kn S+0 D+1 :	Na 499	Ma 874	Nb 327	Mb 874	Nc 327 +
8KB x 1024Kn S+0 D+0 :	Na 422	Ma 936	Nb 234	Mb 842	Nc 234

1KB x 8192Kn S+0 D+0 :	Na 515	Ma 1045	Nb 359	Mb 1030	Nc 358
1KB x 8192Kn S+1 D+0 :	Na 577	Ma 1107	Nb 359	Mb 1077	Nc 358 +
1KB x 8192Kn S+0 D+1 :	Na 546	Ma 1232	Nb 344	Mb 1045	Nc 343

16KB x 512Kn S+1 D+0 :	Na 468	Ma 967	Nb 328	Mb 967	Nc 328
16KB x 512Kn S+0 D+1 :	Na 514	Ma 968	Nb 358	Mb 843	Nc 343 +
16KB x 512Kn S+0 D+0 :	Na 452	Ma 874	Nb 281	Mb 827	Nc 265

32KB x 256Kn S+0 D+0 :	Na 640	Ma 858	Nb 452	Mb 843	Nc 452
32KB x 256Kn S+1 D+0 :	Na 640	Ma 1466	Nb 468	Mb 1467	Nc 452 !!
32KB x 256Kn S+0 D+1 :	Na 530	Ma 858	Nb 468	Mb 858	Nc 468

64KB x 128Kn S+0 D+0 :	Na 452	Ma 858	Nb 437	Mb 858	Nc 437
64KB x 128Kn S+1 D+0 :	Na 624	Ma 1467	Nb 483	Mb 1467	Nc 499 !!
64KB x 128Kn S+0 D+1 :	Na 717	Ma 905	Nb 484	Mb 858	Nc 468
128KB x 64Kn S+0 D+1 :	Na 639	Ma 858	Nb 484	Mb 842	Nc 484
128KB x 64Kn S+0 D+1 :	Na 639	Ma 858	Nb 484	Mb 936	Nc 468
128KB x 64Kn S+1 D+0 :	Na 655	Ma 1482	Nb 468	Mb 1482	Nc 468
128KB x 64Kn S+1 D+0 :	Na 608	Ma 1482	Nb 468	Mb 1482	Nc 468
256KB x 32Kn S+0 D+1 :	Na 967	Ma 1108	Nb 795	Mb 1092	Nc 811
256KB x 32Kn S+0 D+1 :	Na 1014	Ma 1108	Nb 811	Mb 1107	Nc 796
512KB x 16Kn S+0 D+1 :	Na 998	Ma 1155	Nb 795	Mb 1108	Nc 796
512KB x 16Kn S+0 D+1 :	Na 983	Ma 1123	Nb 796	Mb 1107	Nc 812
512KB x 16Kn S+0 D+0 :	Na 858	Ma 1030	Nb 780	Mb 1045	Nc 780
1024KB x 8Kn S+0 D+1 :	Na 1139	Ma 1170	Nb 811	Mb 1107	Nc 812
1024KB x 8Kn S+0 D+1 :	Na 1014	Ma 1108	Nb 951	Mb 1108	Nc 827
2048KB x 4Kn S+0 D+1 :	Na 1045	Ma 1186	Nb 858	Mb 1185	Nc 858
2048KB x 4Kn S+0 D+0 :	Na 904	Ma 1139	Nb 812	Mb 1123	Nc 795
4096KB x 2Kn S+0 D+1 :	Na 1045	Ma 1170	Nb 874	Mb 1170	Nc 873 //
4096KB x 2Kn S+1 D+0 :	Na 1029	Ma 2044	Nb 827	Mb 2246	Nc 827 \\

2048KB x 4Kn S+1 D+0 :	Na 1014	Ma 2059	Nb 843	Mb 2044	Nc 842   //
1024KB x 8Kn S+1 D+0 :	Na 983	Ma 7114	Nb 795	Mb 6927	Nc 795 !!!?
1024KB x 8Kn S+1 D+0 :	Na 1107	Ma 6927	Nb 795	Mb 6958	Nc 811 !!!?
512KB x 16Kn S+1 D+0 :	Na 1030	Ma 1872	Nb 811	Mb 1888	Nc 795   \\

768KB x 10Kn S+1 D+0 :	Na 1061	Ma 1888	Nb 795	Mb 1857	Nc 795

1024KB x 8Kn S+1 D+0 :	Na 998	Ma 6927	Nb 795	Mb 6942	Nc 796 //
1024KB x 8Kn S+1 D+0 :	Na 967	Ma 6926	Nb 812	Mb 6926	Nc 811 !!!
1024KB x 8Kn S+0 D+1 :	Na 998	Ma 1108	Nb 826	Mb 1108	Nc 827 \\

2048KB x 4Kn S+0 D+1 :	Na 1061	Ma 1186	Nb 873	Mb 1186	Nc 874 +
2048KB x 4Kn S+1 D+0 :	Na 1092	Ma 2044	Nb 826	Mb 2059	Nc 843 +
CPU T7250
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
///Intel(R) Core(TM)2 Duo CPU     T7250  @ 2.00GHz

4KB x 2048Kn S+0 D+0 :	Na 421	Ma 1108	Nb 421	Mb 1108	Nc 421
4KB x 2048Kn S+1 D+0 :	Na 1310	Ma 6599	Nb 1264	Mb 6614	Nc 1279 !!!!
4KB x 2048Kn S+1 D+1 :	Na 421	Ma 1108	Nb 405	Mb 1108	Nc 421
4KB x 2048Kn S+0 D+1 :	Na 1731	Ma 1966	Nb 1700	Mb 1982	Nc 1700 ??
4KB x 2048Kn S+0 D+7 :	Na 1716	Ma 1965	Nb 1685	Mb 1966	Nc 1700 ??
4KB x 2048Kn S+0 D+8 :	Na 936	Ma 1092	Nb 921	Mb 1092	Nc 905
4KB x 2048Kn S+0 D+4 :	Na 1701	Ma 1950	Nb 1700	Mb 1950	Nc 1701
4KB x 2048Kn S+0 D+16 :	Na 671	Ma 1108	Nb 670	Mb 1092	Nc 671
4KB x 2048Kn S+16 D+0 :	Na 453	Ma 3198	Nb 421	Mb 3229	Nc 421
4KB x 2048Kn S+8 D+0 :	Na 577	Ma 6412	Nb 546	Mb 6411	Nc 562
4KB x 2048Kn S+4 D+0 :	Na 1326	Ma 6630	Nb 1264	Mb 6614	Nc 1295

128KB x 64Kn S+0 D+0 :	Na 983	Ma 1341	Nb 983	Mb 1342	Nc 982    //
128KB x 64Kn S+1 D+0 :	Na 1997	Ma 7519	Nb 2012	Mb 7520	Nc 2012 !!!
128KB x 64Kn S+0 D+1 :	Na 2293	Ma 2184	Nb 2278	Mb 2246	Nc 2340 ???
128KB x 64Kn S+0 D+1 :	Na 2278	Ma 2199	Nb 2262	Mb 2231	Nc 2278 ???
128KB x 64Kn S+0 D+1 :	Na 2278	Ma 2215	Nb 2278	Mb 2215	Nc 2278 ???
128KB x 64Kn S+0 D+1 :	Na 2309	Ma 2293	Nb 2324	Mb 2216	Nc 2277 ???

2KB x 4096Kn S+0 D+1 :	Na 1700	Ma 1950	Nb 1716	Mb 1966	Nc 1685
2KB x 4096Kn S+1 D+0 :	Na 1310	Ma 6630	Nb 1264	Mb 6599	Nc 1279 !!!!
2KB x 4096Kn S+0 D+0 :	Na 453	Ma 1154	Nb 421	Mb 1139	Nc 437

4KB x 2048Kn S+32 D+0 :	Na 422	Ma 1622	Nb 421	Mb 1607	Nc 421

64KB x 128Kn S+0 D+0 :	Na 1029	Ma 1342	Nb 998	Mb 1342	Nc 967
64KB x 128Kn S+0 D+1 :	Na 2309	Ma 2199	Nb 2278	Mb 2215	Nc 2278
64KB x 128Kn S+0 D+1 :	Na 2309	Ma 2215	Nb 2293	Mb 2184	Nc 2293
64KB x 128Kn S+1 D+0 :	Na 2028	Ma 7504	Nb 1981	Mb 7535	Nc 1997
64KB x 128Kn S+7 D+0 :	Na 2013	Ma 7519	Nb 2012	Mb 7504	Nc 2012
64KB x 128Kn S+15 D+0 :	Na 2044	Ma 7503	Nb 2028	Mb 7520	Nc 2043

64KB x 128Kn S+0 D+0 :	Na 983	Ma 1326	Nb 999	Mb 1326	Nc 982
64KB x 128Kn S+8 D+0 :	Na 1201	Ma 6443	Nb 1201	Mb 6474	Nc 1202 ?!?!?!?
64KB x 128Kn S+16 D+0 :	Na 983	Ma 3229	Nb 983	Mb 3229	Nc 983
64KB x 128Kn S+24 D+0 :	Na 1217	Ma 2230	Nb 1186	Mb 2215	Nc 1217 !!
64KB x 128Kn S+32 D+0 :	Na 983	Ma 1903	Nb 967	Mb 1888	Nc 967
64KB x 128Kn S+40 D+0 :	Na 1217	Ma 1731	Nb 1201	Mb 1716	Nc 1202 !!
64KB x 128Kn S+48 D+0 :	Na 983	Ma 1653	Nb 968	Mb 1653	Nc 983
64KB x 128Kn S+56 D+0 :	Na 1217	Ma 1575	Nb 1217	Mb 1591	Nc 1217 !!
64KB x 128Kn S+64 D+0 :	Na 998	Ma 1560	Nb 983	Mb 1544	Nc 983

64KB x 128Kn S+57 D+0 :	Na 2044	Ma 2792	Nb 2012	Mb 2777	Nc 2028
64KB x 128Kn S+0 D+57 :	Na 2324	Ma 2216	Nb 2308	Mb 2184	Nc 2325
64KB x 128Kn S+0 D+9 :	Na 2277	Ma 2200	Nb 2293	Mb 2200	Nc 2262
64KB x 128Kn S+0 D+1 :	Na 2278	Ma 2230	Nb 2262	Mb 2216	Nc 2277
64KB x 128Kn S+9 D+1 :	Na 1216	Ma 6396	Nb 1202	Mb 6489	Nc 1201 ?!?!?!?
64KB x 128Kn S+9 D+0 :	Na 2028	Ma 7535	Nb 2044	Mb 7535	Nc 2043

64KB x 128Kn S+65 D+0 :	Na 2012	Ma 2793	Nb 1996	Mb 2777	Nc 2013 ! !
64KB x 128Kn S+1 D+0 :	Na 2012	Ma 7519	Nb 2013	Mb 7550	Nc 1981 ?!?!?!?
64KB x 128Kn S+0 D+1 :	Na 2294	Ma 2199	Nb 2293	Mb 2200	Nc 2293 !
64KB x 128Kn S+0 D+65 :	Na 2247	Ma 2215	Nb 2246	Mb 2215	Nc 2216 !

64KB x 128Kn S+8 D+0 :	Na 1170	Ma 6147	Nb 1154	Mb 6147	Nc 1154 !!!!
64KB x 128Kn S+8 D+0 :	Na 1185	Ma 6272	Nb 1154	Mb 6147	Nc 1154 !!!!

128KB x 64Kn S+0 D+1 :	Na 2231	Ma 2091	Nb 2184	Mb 2106	Nc 2168
128KB x 64Kn S+0 D+2 :	Na 2200	Ma 2106	Nb 2168	Mb 2106	Nc 2169
128KB x 64Kn S+0 D+3 :	Na 2200	Ma 2153	Nb 2215	Mb 2106	Nc 2168
128KB x 64Kn S+0 D+4 :	Na 2247	Ma 2121	Nb 2184	Mb 2106	Nc 2184
128KB x 64Kn S+0 D+5 :	Na 2246	Ma 2137	Nb 2184	Mb 2106	Nc 2169
128KB x 64Kn S+0 D+8 :	Na 1279	Ma 1279	Nb 1248	Mb 1279	Nc 1248
128KB x 64Kn S+0 D+9 :	Na 2199	Ma 2091	Nb 2168	Mb 2106	Nc 2168
128KB x 64Kn S+0 D+16 :	Na 1186	Ma 1310	Nb 1155	Mb 1263	Nc 1155

4KB x 2048Kn S+0 D+0 :	Na 421	Ma 1108	Nb 421	Mb 1108	Nc 421
4KB x 2048Kn S+1 D+0 :	Na 1310	Ma 6599	Nb 1264	Mb 6614	Nc 1279 !!!!
4KB x 2048Kn S+1 D+1 :	Na 421	Ma 1108	Nb 405	Mb 1108	Nc 421
4KB x 2048Kn S+0 D+1 :	Na 1731	Ma 1966	Nb 1700	Mb 1982	Nc 1700 ??
4KB x 2048Kn S+0 D+7 :	Na 1716	Ma 1965	Nb 1685	Mb 1966	Nc 1700 ??
4KB x 2048Kn S+0 D+8 :	Na 936	Ma 1092	Nb 921	Mb 1092	Nc 905
4KB x 2048Kn S+0 D+4 :	Na 1701	Ma 1950	Nb 1700	Mb 1950	Nc 1701
4KB x 2048Kn S+0 D+16 :	Na 671	Ma 1108	Nb 670	Mb 1092	Nc 671
4KB x 2048Kn S+16 D+0 :	Na 453	Ma 3198	Nb 421	Mb 3229	Nc 421
4KB x 2048Kn S+8 D+0 :	Na 577	Ma 6412	Nb 546	Mb 6411	Nc 562
4KB x 2048Kn S+4 D+0 :	Na 1326	Ma 6630	Nb 1264	Mb 6614	Nc 1295

128KB x 64Kn S+0 D+0 :	Na 983	Ma 1341	Nb 983	Mb 1342	Nc 982    //
128KB x 64Kn S+1 D+0 :	Na 1997	Ma 7519	Nb 2012	Mb 7520	Nc 2012 !!!
128KB x 64Kn S+0 D+1 :	Na 2293	Ma 2184	Nb 2278	Mb 2246	Nc 2340 ???
128KB x 64Kn S+0 D+1 :	Na 2278	Ma 2199	Nb 2262	Mb 2231	Nc 2278 ???
128KB x 64Kn S+0 D+1 :	Na 2278	Ma 2215	Nb 2278	Mb 2215	Nc 2278 ???
128KB x 64Kn S+0 D+1 :	Na 2309	Ma 2293	Nb 2324	Mb 2216	Nc 2277 ???

2KB x 4096Kn S+0 D+1 :	Na 1700	Ma 1950	Nb 1716	Mb 1966	Nc 1685
2KB x 4096Kn S+1 D+0 :	Na 1310	Ma 6630	Nb 1264	Mb 6599	Nc 1279 !!!!
2KB x 4096Kn S+0 D+0 :	Na 453	Ma 1154	Nb 421	Mb 1139	Nc 437

4KB x 2048Kn S+32 D+0 :	Na 422	Ma 1622	Nb 421	Mb 1607	Nc 421

64KB x 128Kn S+0 D+0 :	Na 1029	Ma 1342	Nb 998	Mb 1342	Nc 967
64KB x 128Kn S+0 D+1 :	Na 2309	Ma 2199	Nb 2278	Mb 2215	Nc 2278
64KB x 128Kn S+0 D+1 :	Na 2309	Ma 2215	Nb 2293	Mb 2184	Nc 2293
64KB x 128Kn S+1 D+0 :	Na 2028	Ma 7504	Nb 1981	Mb 7535	Nc 1997
64KB x 128Kn S+7 D+0 :	Na 2013	Ma 7519	Nb 2012	Mb 7504	Nc 2012
64KB x 128Kn S+15 D+0 :	Na 2044	Ma 7503	Nb 2028	Mb 7520	Nc 2043

64KB x 128Kn S+0 D+0 :	Na 983	Ma 1326	Nb 999	Mb 1326	Nc 982
64KB x 128Kn S+8 D+0 :	Na 1201	Ma 6443	Nb 1201	Mb 6474	Nc 1202
64KB x 128Kn S+16 D+0 :	Na 983	Ma 3229	Nb 983	Mb 3229	Nc 983
64KB x 128Kn S+24 D+0 :	Na 1217	Ma 2230	Nb 1186	Mb 2215	Nc 1217
64KB x 128Kn S+32 D+0 :	Na 983	Ma 1903	Nb 967	Mb 1888	Nc 967
64KB x 128Kn S+40 D+0 :	Na 1217	Ma 1731	Nb 1201	Mb 1716	Nc 1202
64KB x 128Kn S+48 D+0 :	Na 983	Ma 1653	Nb 968	Mb 1653	Nc 983
64KB x 128Kn S+56 D+0 :	Na 1217	Ma 1575	Nb 1217	Mb 1591	Nc 1217
64KB x 128Kn S+64 D+0 :	Na 998	Ma 1560	Nb 983	Mb 1544	Nc 983

64KB x 128Kn S+57 D+0 :	Na 2044	Ma 2792	Nb 2012	Mb 2777	Nc 2028
64KB x 128Kn S+0 D+57 :	Na 2324	Ma 2216	Nb 2308	Mb 2184	Nc 2325
64KB x 128Kn S+0 D+9 :	Na 2277	Ma 2200	Nb 2293	Mb 2200	Nc 2262
64KB x 128Kn S+0 D+1 :	Na 2278	Ma 2230	Nb 2262	Mb 2216	Nc 2277
64KB x 128Kn S+9 D+1 :	Na 1216	Ma 6396	Nb 1202	Mb 6489	Nc 1201
64KB x 128Kn S+9 D+0 :	Na 2028	Ma 7535	Nb 2044	Mb 7535	Nc 2043

64KB x 128Kn S+65 D+0 :	Na 2012	Ma 2793	Nb 1996	Mb 2777	Nc 2013 !
64KB x 128Kn S+1 D+0 :	Na 2012	Ma 7519	Nb 2013	Mb 7550	Nc 1981 ?!?!?!?
64KB x 128Kn S+0 D+1 :	Na 2294	Ma 2199	Nb 2293	Mb 2200	Nc 2293 !
64KB x 128Kn S+0 D+65 :	Na 2247	Ma 2215	Nb 2246	Mb 2215	Nc 2216 !

4KB x 2048Kn S+0 D+0 :	Na 453	Ma 1107	Nb 421	Mb 1092	Nc 422
4KB x 2048Kn S+0 D+0 :	Na 437	Ma 1107	Nb 437	Mb 1092	Nc 406

-------  x32   ------------------------------------------------

1KB x 8192Kn S+0 D+0 :	Na 390	Ma 1170	Nb 390	Mb 1170	Nc 375
1KB x 8192Kn S+0 D+0 :	Na 406	Ma 1170	Nb 374	Mb 1170	Nc 374
1KB x 8192Kn S+0 D+0 :	Na 406	Ma 1170	Nb 374	Mb 1170	Nc 390
1KB x 8192Kn S+0 D+0 :	Na 405	Ma 1170	Nb 375	Mb 1170	Nc 374
1KB x 8192Kn S+0 D+0 :	Na 406	Ma 1170	Nb 374	Mb 1170	Nc 390

8KB x 1024Kn S+0 D+0 :	Na 343	Ma 1045	Nb 344	Mb 1045	Nc 327
8KB x 1024Kn S+0 D+0 :	Na 359	Ma 1061	Nb 327	Mb 1045	Nc 344
8KB x 1024Kn S+0 D+0 :	Na 359	Ma 1092	Nb 343	Mb 1076	Nc 344

1KB x 8192Kn S+0 D+0 :	Na 422	Ma 1216	Nb 406	Mb 1201	Nc 390
4KB x 2048Kn S+0 D+0 :	Na 374	Ma 1108	Nb 343	Mb 1108	Nc 358
8KB x 1024Kn S+0 D+0 :	Na 358	Ma 1092	Nb 359	Mb 1092	Nc 359
16KB x 512Kn S+0 D+0 :	Na 422	Ma 1092	Nb 405	Mb 1092	Nc 421

32KB x 256Kn S+0 D+0 :	Na 1029	Ma 1342	Nb 998	Mb 1326	Nc 999 
64KB x 128Kn S+0 D+0 :	Na 1014	Ma 1342	Nb 983	Mb 1341	Nc 999
128KB x 64Kn S+0 D+0 :	Na 1014	Ma 1326	Nb 998	Mb 1342	Nc 998
256KB x 32Kn S+0 D+0 :	Na 1014	Ma 1326	Nb 998	Mb 1326	Nc 999
512KB x 16Kn S+0 D+0 :	Na 1077	Ma 1388	Nb 1045	Mb 1373	Nc 1030
768KB x 10Kn S+0 D+0 :	Na 1435	Ma 1872	Nb 1435	Mb 1904	Nc 1388

1024KB x 8Kn S+0 D+0 :	Na 2355	Ma 2871	Nb 2293	Mb 2886	Nc 2574
2048KB x 4Kn S+0 D+0 :	Na 6630	Ma 6864	Nb 6661	Mb 6864	Nc 6646
4096KB x 2Kn S+0 D+0 :	Na 6614	Ma 6786	Nb 6599	Mb 6802	Nc 6599

4KB x 2048Kn S+0 D+0 :	Na 375	Ma 1076	Nb 343	Mb 1092	Nc 359
4KB x 2048Kn S+1 D+0 :	Na 1280	Ma 2308	Nb 1264	Mb 2309	Nc 1248
4KB x 2048Kn S+0 D+1 :	Na 1669	Ma 9953	Nb 1653	Mb 9938	Nc 1638  !
4KB x 2048Kn S+0 D+1 :	Na 1685	Ma 9906	Nb 1653	Mb 9938	Nc 1653  !

1KB x 8192Kn S+0 D+0 :	Na 390	Ma 1170	Nb 390	Mb 1170	Nc 375 
1KB x 8192Kn S+0 D+1 :	Na 1653	Ma 9844	Nb 1638	Mb 9859	Nc 1638  !
1KB x 8192Kn S+1 D+0 :	Na 1326	Ma 2356	Nb 1295	Mb 2355	Nc 1295

64KB x 128Kn S+0 D+0 :	Na 1045	Ma 1311	Nb 998	Mb 1326	Nc 999
64KB x 128Kn S+1 D+0 :	Na 2074	Ma 2606	Nb 2074	Mb 2621	Nc 2059
64KB x 128Kn S+0 D+1 :	Na 2278	Ma 10514Nb 2293	Mb 10562Nc 2246  !!
Pentium(R) 4 CPU 3.00GHz
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
///Intel(R) Pentium(R) 4 CPU 3.00GHz

-------  x32   -----------------------------------------------

1KB x 8192Kn S+0 D+0 :	Na 860	Ma 1484	Nb 860	Mb 1515	Nc 860
2KB x 4096Kn S+0 D+0 :	Na 844	Ma 1406	Nb 844	Mb 1390	Nc 844
4KB x 2048Kn S+0 D+0 :	Na 828	Ma 1453	Nb 828	Mb 1657	Nc 843
4KB x 2048Kn S+0 D+0 :	Na 844	Ma 1390	Nb 828	Mb 1407	Nc 828
4KB x 2048Kn S+1 D+0 :	Na 1563	Ma 1859	Nb 1531	Mb 1844	Nc 1547
4KB x 2048Kn S+0 D+1 :	Na 1531	Ma 1844	Nb 1547	Mb 1828	Nc 1531

8KB x 1024Kn S+0 D+1 :	Na 1531	Ma 2016	Nb 1516	Mb 2015	Nc 1516
8KB x 1024Kn S+1 D+0 :	Na 1594	Ma 2000	Nb 1563	Mb 2000	Nc 1578
8KB x 1024Kn S+16 D+0 :	Na 859	Ma 1453	Nb 860	Mb 1453	Nc 828
8KB x 1024Kn S+8 D+0 :	Na 843	Ma 1500	Nb 860	Mb 1468	Nc 860
8KB x 1024Kn S+4 D+0 :	Na 1594	Ma 2016	Nb 1562	Mb 2000	Nc 1594
8KB x 1024Kn S+0 D+8 :	Na 875	Ma 2031	Nb 875	Mb 2047	Nc 875
8KB x 1024Kn S+0 D+16 :	Na 828	Ma 1922	Nb 828	Mb 1922	Nc 828
8KB x 1024Kn S+0 D+20 :	Na 1469	Ma 1906	Nb 1469	Mb 1922	Nc 1468

16KB x 512Kn S+0 D+0 :	Na 1015	Ma 1782	Nb 1000	Mb 1781	Nc 1000
32KB x 256Kn S+0 D+0 :	Na 1016	Ma 1750	Nb 1015	Mb 1766	Nc 1000
64KB x 128Kn S+0 D+0 :	Na 1016	Ma 1750	Nb 1015	Mb 1750	Nc 1016
128KB x 64Kn S+0 D+0 :	Na 1000	Ma 1765	Nb 1000	Mb 1782	Nc 1000
256KB x 32Kn S+0 D+0 :	Na 1000	Ma 1797	Nb 1000	Mb 1797	Nc 1016
512KB x 16Kn S+0 D+0 :	Na 1218	Ma 1985	Nb 1203	Mb 1984	Nc 1203
1024KB x 8Kn S+0 D+0 :	Na 7515	Ma 7579	Nb 7531	Mb 7687	Nc 7641
2048KB x 4Kn S+0 D+0 :	Na 7453	Ma 7562	Nb 7454	Mb 7546	Nc 7469

4KB x 2048Kn S+0 D+0 :	Na 844	Ma 1390	Nb 828	Mb 1407	Nc 828
4KB x 2048Kn S+8 D+0 :	Na 844	Ma 1391	Nb 843	Mb 1375	Nc 829
4KB x 2048Kn S+0 D+8 :	Na 844	Ma 1875	Nb 844	Mb 1890	Nc 860
4KB x 2048Kn S+16 D+0 :	Na 828	Ma 1375	Nb 828	Mb 1375	Nc 844
4KB x 2048Kn S+0 D+16 :	Na 828	Ma 1797	Nb 828	Mb 1797	Nc 812

128KB x 64Kn S+0 D+8 :	Na 1141	Ma 2391	Nb 1125	Mb 2343	Nc 1125
128KB x 64Kn S+8 D+0 :	Na 1140	Ma 1782	Nb 1125	Mb 1797	Nc 1125
128KB x 64Kn S+16 D+0 :	Na 984	Ma 1797	Nb 984	Mb 1782	Nc 984
128KB x 64Kn S+0 D+16 :	Na 1031	Ma 2313	Nb 1016	Mb 2359	Nc 1031
128KB x 64Kn S+17 D+1 :	Na 859	Ma 1766	Nb 859	Mb 1766	Nc 844
128KB x 64Kn S+1 D+1 :	Na 1000	Ma 1750	Nb 985	Mb 1765	Nc 985
128KB x 64Kn S+1 D+1 :	Na 984	Ma 1766	Nb 984	Mb 1750	Nc 984
128KB x 64Kn S+1 D+17 :	Na 953	Ma 2313	Nb 953	Mb 2328	Nc 953
128KB x 64Kn S+9 D+17 :	Na 1218	Ma 2360	Nb 1203	Mb 2375	Nc 1203
128KB x 64Kn S+9 D+25 :	Na 953	Ma 2297	Nb 938	Mb 2281	Nc 953
128KB x 64Kn S+25 D+9 :	Na 860	Ma 1750	Nb 843	Mb 1735	Nc 859
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38780609
SoftGuest
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Честно говоря я не совсем понял, как работает тест и какой именно "стандартный Move" фигурирует (похоже самый быстрый x86)... Но судя по результатам я бог оптимизаций :). Хотя по большому счёту увеличение производительности в полтора-два раза вполне ожидаемо
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38806952
Корбен
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
asviridenkovСлабо улучшить?
Сначала подправим логику
1) неправильный результат выдают "x32" версии PStrScan для параметров (NotNil, '1', 0)
2) неплохо бы защититься от отрицательного size:
Код: plaintext
1.
2.
        TEST    ECX,ECX   //ASize=0?
        J L E     @@qt

Теперь о производительности. Думаю, что результаты сильно зависят от железа, но у меня следующий пример быстрее. Чем короче строка, тем больше разница (до 6 раз). На длинных строках - паритет.
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
function Q_PStrScan(P: PWideChar; Ch: WideChar; Size: Integer): Integer; // x32
asm
  test    eax, eax   // P=nil?
  jz      @@exit

  push    ecx
  lea     eax, [eax + 2*ecx]
  neg     ecx
  jnl     @@zero

@@loop:
  cmp dx, [eax + 2*ecx]
  je @@found

  inc ecx
  jne @@loop

@@zero:
  pop ecx
  xor eax, eax
@@exit:
  ret

@@found:
  pop eax
  lea eax, [eax + ecx + 1]
end;
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #38806961
Фотография defecator
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Модератор форума
Корбенно у меня следующий пример быстрее. Чем короче строка, тем больше разница (до 6 раз). На длинных строках - паритет.
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
function Q_PStrScan(P: PWideChar; Ch: WideChar; Size: Integer): Integer; // x32
asm
  test    eax, eax   // P=nil?
  jz      @@exit

  push    ecx
  lea     eax, [eax + 2*ecx]
  neg     ecx
  jnl     @@zero

@@loop:
  cmp dx, [eax + 2*ecx]
  je @@found

  inc ecx
  jne @@loop

@@zero:
  pop ecx
  xor eax, eax
@@exit:
  ret

@@found:
  pop eax
  lea eax, [eax + ecx + 1]
end;



Это же код из библиотеки QStrings, так нечестно ))
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Ну очень быстрый Move() для x86/x64
    #39544651
Няшик
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну очень быстрый Move - самый простой

Вот этот, без использования SSE будет быстрее стандартного Move и NonCollisionMove

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
function MyMove(const Source; var Dest; Count: NativeInt): Integer;
asm
  push ebx
  cmp ecx, 15
  jbe @@Move8
@@Move16:
  mov ebx, DWORD PTR [eax]
  mov DWORD PTR [edx], ebx
  mov ebx, DWORD PTR [eax+4]
  mov DWORD PTR [edx+4], ebx
  add edx, 16
  add eax, 16
  sub ecx, 16
  cmp ecx, 15
  ja @@Move16
@@Move8:
  test ecx, ecx
  je @@Exit
  test cl, 8
  je @@Move4
  mov ebx, DWORD PTR [eax]
  mov DWORD PTR [edx], ebx
  add edx, 8
  add eax, 8
@@Move4:
  test cl, 4
  je @@Move2
  mov ebx, DWORD PTR [eax]
  mov DWORD PTR [edx], ebx
  add edx, 4
  add eax, 4
@@Move2:
  test cl, 2
  je @@Move1
  movzx ebx, WORD PTR [eax]
  mov WORD PTR [edx], bx
  add edx, 2
  add eax, 2
@@Move1:
  test cl, 1
  je @@Exit
  movzx eax, BYTE PTR [eax]
  mov BYTE PTR [edx], al
@@Exit:
  pop ebx
end;




Сам тестер
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
program Project71;

uses
  Windows;

function sprintf(S: PAnsiChar; const Format: PAnsiChar): Integer; cdecl;
  varargs; external 'msvcrt.dll';
function QueryPerformanceCounter(var lpPerformanceCount: Int64): LongBool;
  stdcall; external 'kernel32.dll' name 'QueryPerformanceCounter';
function QueryPerformanceFrequency(var lpFrequency: Int64): LongBool; stdcall;
  external 'kernel32.dll' name 'QueryPerformanceFrequency';

function PrintTime(time: Single): AnsiString;
begin
  Result := '';
  SetLength(Result, 25);
  SetLength(Result, sprintf(PAnsiChar(Result), '%f', time));
end;

function MyMove(const Source; var Dest; Count: NativeInt): Integer;
asm
  push ebx
  cmp ecx, 15
  jbe @@Move8
@@Move16:
  mov ebx, DWORD PTR [eax]
  mov DWORD PTR [edx], ebx
  mov ebx, DWORD PTR [eax+4]
  mov DWORD PTR [edx+4], ebx
  add edx, 16
  add eax, 16
  sub ecx, 16
  cmp ecx, 15
  ja @@Move16
@@Move8:
  test ecx, ecx
  je @@Exit
  test cl, 8
  je @@Move4
  mov ebx, DWORD PTR [eax]
  mov DWORD PTR [edx], ebx
  add edx, 8
  add eax, 8
@@Move4:
  test cl, 4
  je @@Move2
  mov ebx, DWORD PTR [eax]
  mov DWORD PTR [edx], ebx
  add edx, 4
  add eax, 4
@@Move2:
  test cl, 2
  je @@Move1
  movzx ebx, WORD PTR [eax]
  mov WORD PTR [edx], bx
  add edx, 2
  add eax, 2
@@Move1:
  test cl, 1
  je @@Exit
  movzx eax, BYTE PTR [eax]
  mov BYTE PTR [edx], al
@@Exit:
  pop ebx
end;

procedure NonCollisionMove(const Source; var Dest; const size: NativeUInt);
asm
  // basic routine
  {$IFDEF CPUX86}
  cmp ecx, 32
  {$ELSE .CPUX64}
  cmp r8, 32
  // make Source = eax/rax, Dest = edx/rdx, Size = ecx/rcx
  mov rax, rcx
  xchg rcx, r8
  // r9 as pointer to @move_03_items
  lea r9, [@move_03_items]
  {$ENDIF}

  // is big/large (32...inf)
  jae @move_big

  // is small (0..3)
  cmp ecx, 4
  jb @move_03

  // move middle(4..31) = move 16(0..16) + move dwords(0..12) + move small(0..3)
  cmp ecx, 16
  jb @move_015

  {$IFDEF CPUX86}
  movups xmm0, [eax]
  movups [edx], xmm0
  jne @move_015_offset
  ret
@move_015_offset:
  sub ecx, 16
  add eax, 16
  add edx, 16
@move_015:
  push ecx
  and ecx, -4
  add eax, ecx
  add edx, ecx
  jmp [ecx + @move_dwords]
@move_dwords: DD @rw_0,@rw_4,@rw_8,@rw_12
@rw_12:
  mov ecx, [eax-12]
  mov [edx-12], ecx
@rw_8:
  mov ecx, [eax-8]
  mov [edx-8], ecx
@rw_4:
  mov ecx, [eax-4]
  mov [edx-4], ecx
@rw_0:
  pop ecx
  and ecx, 3
  {$ELSE .CPUX64}
  movups xmm0, [rax]
  movups [rdx], xmm0
  jne @move_015_offset
  ret
@move_015_offset:
  sub rcx, 16
  add rax, 16
  add rdx, 16
@move_015:
  // make r9 = dest 0..3 pointer, rcx = dwords count
  mov r8, rcx
  shr rcx, 2
  and r8, 3
  lea r9, [r9 + r8*8]
  // case jump
  lea r8, [@move_dwords]
  jmp qword ptr [r8 + rcx*8]
@move_dwords: DQ @rw_0,@rw_4,@rw_8,@rw_12
@rw_8:
  mov rcx, [rax]
  mov [rdx], rcx
  add rax, 8
  add rdx, 8
  jmp qword ptr [r9]
@rw_12:
  mov rcx, [rax]
  mov [rdx], rcx
  add rax, 8
  add rdx, 8
@rw_4:
  mov ecx, [rax]
  mov [rdx], ecx
  add rax, 4
  add rdx, 4
@rw_0:
  jmp qword ptr [r9]
  {$ENDIF}

@move_03:
  {$IFDEF CPUX86}
  jmp [offset @move_03_items + ecx*4]
@move_03_items: DD @0,@1,@2,@3
@2: mov cx, [eax]
  mov [edx], cx
  ret
@3: mov cx, [eax]
  mov [edx], cx
  add eax, 2
  add edx, 2
@1: mov cl, [eax]
  mov [edx], cl
@0: ret
  {$ELSE .CPUX64}
  jmp qword ptr [r9 + rcx*8]
@move_03_items: DQ @0,@1,@2,@3
@2: mov cx, [rax]
  mov [rdx], cx
  ret
@3: mov cx, [rax]
  mov [rdx], cx
  add rax, 2
  add rdx, 2
@1: mov cl, [rax]
  mov [rdx], cl
@0: ret
  {$ENDIF}

@move_big:
  {$IFDEF CPUX86}
  cmp ecx, 16*4
  {$ELSE .CPUX64}
  cmp rcx, 16*4
  {$ENDIF}
  jae @move_large

  // big memory move by SSE (32..63) = (32..48) + (0..15)
  {$IFDEF CPUX86}
  test ecx, 15
  jz @move_32_48

  push ecx
  and ecx, 15
  movups xmm0, [eax]
  movups [edx], xmm0
  add eax, ecx
  add edx, ecx

  pop ecx
  and ecx, -16
  {$ELSE .CPUX64}
  mov r8, rcx
  test rcx, 15
  jz @move_32_48

  and r8, 15
  movups xmm0, [rax]
  movups [rdx], xmm0
  add rax, r8
  add rdx, r8

  and rcx, -16
  {$ENDIF}

@move_32_48:
  {$IFDEF CPUX86}
  add eax, ecx
  add edx, ecx
  cmp ecx, 48
  jb @rw_32
@rw_48: movups xmm2, [eax - 2*16 - 16]
  movups [edx - 2*16 - 16], xmm2
@rw_32: movups xmm1, [eax - 1*16 - 16]
  movups xmm0, [eax - 0*16 - 16]
  movups [edx - 1*16 - 16], xmm1
  movups [edx - 0*16 - 16], xmm0
  {$ELSE .CPUX64}
  add rax, rcx
  add rdx, rcx
  cmp rcx, 48
  jb @rw_32
@rw_48: movups xmm2, [rax - 2*16 - 16]
  movups [rdx - 2*16 - 16], xmm2
@rw_32: movups xmm1, [rax - 1*16 - 16]
  movups xmm0, [rax - 0*16 - 16]
  movups [rdx - 1*16 - 16], xmm1
  movups [rdx - 0*16 - 16], xmm0
  {$ENDIF}

  ret
@move_large:
  // large memory move by SSE (64..inf)

  // destination alignment
  {$IFDEF CPUX86}
  push ebx
  test edx, 15
  jz @move_16128_initialize

  mov ebx, edx
  movups xmm0, [eax]
  movups [ebx], xmm0

  add edx, 15
  and edx, -16
  sub ebx, edx
  sub eax, ebx
  add ecx, ebx
  {$ELSE .CPUX64}
  test rdx, 15
  jz @move_16128_initialize

  mov r8, rdx
  movups xmm0, [rax]
  movups [r8], xmm0

  add rdx, 15
  and rdx, -16
  sub r8, rdx
  sub rax, r8
  add rcx, r8
  {$ENDIF}

@move_16128_initialize:
  {$IFDEF CPUX86}
  push ecx
  mov ebx, offset @aligned_reads
  shr ecx, 4
  test eax, 15
  jz @move_16128
  mov ebx, offset @unaligned_reads
  {$ELSE .CPUX64}
  movaps [rsp-8-16], xmm6
  movaps [rsp-8-32], xmm7
  mov r8, rcx
  lea r9, [@aligned_reads]
  shr rcx, 4
  test rax, 15
  jz @move_16128
  lea r9, [@unaligned_reads]
  {$ENDIF}

@move_16128:
  {$IFDEF CPUX86}
  cmp ecx, 8
  jae @move_128

  lea ecx, [ecx + ecx]
  lea eax, [eax + ecx*8]
  lea edx, [edx + ecx*8]
  lea ebx, [ebx + 8*4]
  neg ecx
  lea ebx, [ebx + ecx*2]
  jmp ebx
@move_128:
  lea eax, [eax + 128]
  lea edx, [edx + 128]
  lea ecx, [ecx - 8]
  jmp ebx
  {$ELSE .CPUX64}
  cmp rcx, 8
  jae @move_128

  lea rcx, [rcx + rcx]
  lea rax, [rax + rcx*8]
  lea rdx, [rdx + rcx*8]
  lea r9, [r9 + 8*4]
  neg rcx
  lea r9, [r9 + rcx*2]
  jmp r9
@move_128:
  lea rax, [rax + 128]
  lea rdx, [rdx + 128]
  lea rcx, [rcx - 8]
  jmp r9
  {$ENDIF}

  // aligned sse read
@aligned_reads:
  {$IFDEF CPUX86}
  movaps xmm7, [eax - 7*16 - 16]
  movaps xmm6, [eax - 6*16 - 16]
  movaps xmm5, [eax - 5*16 - 16]
  movaps xmm4, [eax - 4*16 - 16]
  movaps xmm3, [eax - 3*16 - 16]
  movaps xmm2, [eax - 2*16 - 16]
  movaps xmm1, [eax - 1*16 - 16]
  movaps xmm0, [eax - 0*16 - 16]
  {$ELSE .CPUX64}
  movaps xmm7, [rax - 7*16 - 16]
  movaps xmm6, [rax - 6*16 - 16]
  movaps xmm5, [rax - 5*16 - 16]
  movaps xmm4, [rax - 4*16 - 16]
  movaps xmm3, [rax - 3*16 - 16]
  movaps xmm2, [rax - 2*16 - 16]
  movaps xmm1, [rax - 1*16 - 16]
  movaps xmm0, [rax - 0*16 - 16]
  {$ENDIF}
  jae @aligned_writes
  jmp @write_16112

  // unaligned sse read
@unaligned_reads:
  {$IFDEF CPUX86}
  movups xmm7, [eax - 7*16 - 16]
  movups xmm6, [eax - 6*16 - 16]
  movups xmm5, [eax - 5*16 - 16]
  movups xmm4, [eax - 4*16 - 16]
  movups xmm3, [eax - 3*16 - 16]
  movups xmm2, [eax - 2*16 - 16]
  movups xmm1, [eax - 1*16 - 16]
  movups xmm0, [eax - 0*16 - 16]
  jae @aligned_writes
@write_16112:
  lea ebx, [offset @aligned_writes + 8*4 + ecx*2]
  jmp ebx
  {$ELSE .CPUX64}
  movups xmm7, [rax - 7*16 - 16]
  movups xmm6, [rax - 6*16 - 16]
  movups xmm5, [rax - 5*16 - 16]
  movups xmm4, [rax - 4*16 - 16]
  movups xmm3, [rax - 3*16 - 16]
  movups xmm2, [rax - 2*16 - 16]
  movups xmm1, [rax - 1*16 - 16]
  movups xmm0, [rax - 0*16 - 16]
  jae @aligned_writes
@write_16112:
  lea r9, [@aligned_writes + 8*4]
  lea r9, [r9 + rcx*2]
  jmp r9
  {$ENDIF}

  // aligned sse write, loop
@aligned_writes:
  {$IFDEF CPUX86}
  movaps [edx - 7*16 - 16], xmm7
  movaps [edx - 6*16 - 16], xmm6
  movaps [edx - 5*16 - 16], xmm5
  movaps [edx - 4*16 - 16], xmm4
  movaps [edx - 3*16 - 16], xmm3
  movaps [edx - 2*16 - 16], xmm2
  movaps [edx - 1*16 - 16], xmm1
  movaps [edx - 0*16 - 16], xmm0
  test ecx, ecx
  {$ELSE .CPUX64}
  movaps [rdx - 7*16 - 16], xmm7
  movaps [rdx - 6*16 - 16], xmm6
  movaps [rdx - 5*16 - 16], xmm5
  movaps [rdx - 4*16 - 16], xmm4
  movaps [rdx - 3*16 - 16], xmm3
  movaps [rdx - 2*16 - 16], xmm2
  movaps [rdx - 1*16 - 16], xmm1
  movaps [rdx - 0*16 - 16], xmm0
  test rcx, rcx
  {$ENDIF}
  jg @move_16128

  // last 0..15 bytes
  {$IFDEF CPUX86}
  pop ecx
  pop ebx
  and ecx, 15
  jnz @move_115
  ret
@move_115:
  add eax, ecx
  add edx, ecx
  movups xmm0, [eax - 0*16 - 16]
  movups [edx - 0*16 - 16], xmm0
  {$ELSE .CPUX64}
  movaps xmm6, [rsp-8-16]
  movaps xmm7, [rsp-8-32]
  and r8, 15
  jnz @move_115
  ret
@move_115:
  add rax, r8
  add rdx, r8
  movups xmm0, [rax - 0*16 - 16]
  movups [rdx - 0*16 - 16], xmm0
  {$ENDIF}
end;

type
  TCall = procedure(const Source; var Dest; Count: NativeInt);

var
  i, g: Integer;

  Str1, Str2: AnsiString;
  StartTime, StopTime: Int64;
  iCounterPerSec: Int64;

procedure Speed(const n: string; c: Pointer; i: Integer);
begin
  QueryPerformanceCounter(StartTime);

  for g := 0 to 10000000 do
  begin
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
    TCall(c)(Str2[1], Str1[i + 1], Length(Str2) - i);
  end;

  if QueryPerformanceCounter(StopTime) and QueryPerformanceFrequency
    (iCounterPerSec) then
    Writeln(n, ':: ', PrintTime((StopTime - StartTime) / iCounterPerSec));
end;

begin
{$IFNDEF DEBUG}
  Write('Release');
{$ELSE}
  Write('Debug');
{$ENDIF}
{$IF Defined(CPUX64) or Defined(CPUARM64)}
  Writeln(' 64bit');
{$ELSE}
  Writeln(' 32Bit');
{$IFEND}
  System.SetMinimumBlockAlignment(mba16Byte);

  Str1 := 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    + 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

  Str2 := '------------------------------------------------------------------------------------------------------------------------------------------------'
    + '------------------------------------------------------------------------------------------------------------------------------------------------';


  i := 9;
  Writeln('-- ', i ,' -- ');
  Speed('MyMove', @MyMove, i);
  Speed('Move', @Move, i);
  Speed('NonCollisionMove', @NonCollisionMove, i);


  i := 0;
  Writeln('-- ', i ,' -- ');
  Speed('MyMove', @MyMove, i);
  Speed('Move', @Move, i);
  Speed('NonCollisionMove', @NonCollisionMove, i);

  i := 3;
  Writeln('-- ', i ,' -- ');
  Speed('MyMove', @MyMove, i);
  Speed('Move', @Move, i);
  Speed('NonCollisionMove', @NonCollisionMove, i);

  Readln;

end.



Результат
Debug 32Bit
-- 9 --
MyMove:: 3.631395
Move:: 9.564001
NonCollisionMove:: 9.057227
-- 0 --
MyMove:: 3.415018
Move:: 5.097708
NonCollisionMove:: 4.003383
-- 3 --
MyMove:: 6.619108
Move:: 9.994631
NonCollisionMove:: 7.615205


Собственно написать этот Move послужило - то, что стандартный Move меняет адрес исходного адреса (Жутко бесила)
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #39544657
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Няшик,

@@Move16
Копируешь 8 байт вместо 16
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #39544671
Фотография Квейд
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Инструкции REP MOVSx начиная с архитектуры Nehalem, и далее в Ivy Bridge заоптимизированы микрокодом по немогу и по скорости не уступают SSE. Пруф на странице 160.

http://www.cs.utexas.edu/~hunt/class/2017-spring/cs350c/documents/Intel-x86-Docs/64-ia-32-architectures-optimization-manual.pdf
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #39545088
alekcvp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOUНяшик,
@@Move16
Копируешь 8 байт вместо 16
И в @@Move8 - 4, вместо 8.
Оптимизация-с :)
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #39545137
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
КвейдИнструкции REP MOVSx начиная с архитектуры Nehalem, и далее в Ivy Bridge заоптимизированы микрокодом по немогу и по скорости не уступают SSE. Пруф на странице 160.

http://www.cs.utexas.edu/~hunt/class/2017-spring/cs350c/documents/Intel-x86-Docs/64-ia-32-architectures-optimization-manual.pdf

Говорят, сейчас на некоторых архитектурах заруливает REP MOVSB
Но мы же тут не для конкретной архитектуры пишем, а в общем, для многих :)
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #39545200
Sapersky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Оптимизировали только MOVSB (не SD), т.е. Move от старых Дельфей сам по себе не ускоряется.
Получается, нужно делать отдельную версию Move специально для Ivy Bridge+, проверять процессор и т.д. - слишком муторно.
И на мелких блоках (проверял 256 и 1024 байт с выравниваем 4) SIMD всё равно быстрее.
...
Рейтинг: 0 / 0
Ну очень быстрый Move() для x86/x64
    #39545208
vavan
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SaperskyПолучается, нужно делать отдельную версию Move специально для Ivy Bridge+, проверять процессор и т.д.а так оно и делается. на старте детектится камень и подтыкается оптимальная для него версия
...
Рейтинг: 0 / 0
38 сообщений из 38, показаны все 2 страниц
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Ну очень быстрый Move() для x86/x64
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]