- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 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
const n = 50;
type vec = array [1..n*4] of system.word;
function vprod(const a, b: vec): Cardinal;
var i: longInt;
begin
result := 0;
for i := 1 to high(vec) do inc(result, a[i] * b[i]);
end;
function vprod_asm1(const a, b: vec): Cardinal; assembler;
asm
push ebx
push ecx
push edx
push esi
push edi
xor ebx, ebx
mov ecx, n*4
mov esi, a
mov edi, b
xor eax, eax
cld
@@l:
mov ax, word ptr [esi]
lea esi, [esi+2]
mul word ptr [edi]
lea edi, [edi+2]
shl edx, 16
mov dx, ax
add ebx, edx
dec ecx
jne @@l
mov eax, ebx
pop edi
pop esi
pop edx
pop ecx
pop ebx
end;
function vprod_asm2(const a, b: vec): Cardinal; assembler;
asm
push ebx
push ecx
push edx
push esi
push edi
xor ebx, ebx
mov ecx, n*4
mov esi, a
mov edi, b
xor eax, eax
cld
@@l:
lodsw
movzx edx, WORD PTR [edi]
imul edx
lea edi, [edi+2]
add ebx, eax
loop @@l
mov eax, ebx
pop edi
pop esi
pop edx
pop ecx
pop ebx
end;
function vprod_mmx (const a, b: vec): Cardinal; assembler;
var muls: record l, h: Cardinal end;
asm
push ebx
push ecx
push esi
push edi
mov ecx, n
mov esi, a
mov edi, b
xor eax, eax
lea ebx, muls
@@l:
db $0F,$6F,$06 // movq mm0, [esi]
db $0F,$F5,$07 // pmaddwd mm0, [edi]
lea esi, [esi+8]
db $0F,$7F,$03 // movq [ebx], mm0
lea edi, [edi+8]
add eax, [ebx]
add eax, [ebx+4]
loop @@l
db $0F,$77 // emms
pop edi
pop esi
pop ecx
pop ebx
end;
По просьбам трудящихся публикую модифицированную версию примера MMXTEST.PAS из комплекта компилятора TMT Pascal. Программа находит скалярное произведение двух векторов. Далее должен быть основной блок с фрагментами типа for i := 1 to 100000 do vprod(a, b); , которые я не стал публиковать ввиду ограничений. Функция vprod_asm1 — почти оригинальный код TMT, функция vprod_asm2 — мой оптимизированный вариант. Результаты запуска на двух машинах (таймер получал по RDTSC):
AMD K6-2-333 МГц, FSB 66 МГц.
Delphi7:
Pascal = 0.550 sec.
Asm x86 (original) = 1.034 sec.
Asm x86 (optimized) = 0.490 sec.
Asm MMX = 0.130 sec.
С директивой $O- первый результат 0.853 sec.
Замена loop на dec ecx + jne увеличивает результаты на 0,015 c.
FPC:
Pascal = 1.387 sec.
Asm x86 (original) = 1.199 sec.
Asm x86 (optimized) = 0.510 sec.
Asm MMX = 0.124 sec.
TMT:
Pascal = 0.914 sec.
Asm x86 (original) = 1.037 sec.
Asm x86 (optimized) = 0.494 sec.
Asm MMX = 0.126 sec.
VP:
Pascal = 0.520 sec.
Asm x86 (original) = 1.033 sec.
Asm x86 (optimized) = 0.493 sec.
Asm MMX = 0.146 sec.
С директивами $Q+,R+ первый результат 1.032 sec.
С директивой $Speed- первый результат 0.731 sec.
------------------------------
Celeron 1,86 ГГц, FSB 533 МГц.
Delphi7:
Pascal = 0.025 sec.
Asm x86 (original) = 0.091 sec.
Asm x86 (optimized) = 0.082 sec.
Asm MMX = 0.044 sec.
TMT:
Pascal = 0.109 sec.
Asm x86 (original) = 0.087 sec.
Asm x86 (optimized) = 0.079 sec.
Asm MMX = 0.042 sec.
alexoy 25.09.2011 19:10 # −3
Dummy00001 25.09.2011 19:13 # +1
inkanus-gray 25.09.2011 19:16 # +2
§1. Оригинальный ассемблерный вариант функции из примера на некоторых машинах работает медленнее паскалевского.
§2. Код, сгенерированный Дельфи и Виртуал Паскалем, вдвое быстрее оригинального ассемблерного на некоторых машинах.
§3. Код, сгенерированный Дельфи 7, на современных машинах быстрее примера в MMX.
§4. Проверка целочисленного переполнения и границ диапазонов не влияет на быстродействие данного кода в Дельфи 7, в отличие от, например, VP, но даже его код получается не тормознее первой версии ассемблерного.
Lure Of Chaos 25.09.2011 19:30 # +2
кстати, не так давно я уже встречал эту вонь про "дельфи быстрее ассемблера"
inkanus-gray 25.09.2011 20:38 # 0
Спасибо, капитан.
Lure Of Chaos 25.09.2011 20:39 # 0
Uhehesh 25.09.2011 22:31 # +4
TarasB 26.09.2011 10:40 # −1
TarasB 26.09.2011 10:39 # 0
Lure Of Chaos 26.09.2011 10:41 # +1
TarasB 26.09.2011 10:48 # 0
ctm 26.09.2011 11:52 # +1
TarasB 26.09.2011 12:00 # 0
Только не про
i: word;
for i := 0 to L.Count-1 do...
ctm 26.09.2011 12:26 # 0
ну или код корявый был:)
TarasB 26.09.2011 12:54 # 0
ctm 26.09.2011 13:14 # 0
когда найду - выложу.
Dummy00001 25.09.2011 19:33 # +3
для математики есть (во-первых) компетентные компиляторы (например, *любой* С компилятор) и (во-вторых) кучи мат библиотек (таже STL's valarray хорошая стартовая точка).
переизобретание велосипеда, всего лишь потому что с Дельфой прилагаются только квадратные колеса, наталкивает на мысли что вы пользуетесь неправильной тулзой для поставленой задачи.
ЗЫ есть такой крутой пример: Quake1, один из самых быстрых SW 3D движков когда либо написаный, не содержит ни одной строчки асма.
inkanus-gray 25.09.2011 20:33 # 0
Я сначала не хотел, но в каком-то говнокоде мне предложили опубликовать результаты испытаний отдельным ГК.
> например, *любой* С компилятор
Конкретные примеры компиляторов с конкретными примерами ключей и сгенерированного кода имеются? Пока мне удалось заметить только мелочи типа add eax, 1 вместо inc eax в некоторых режимах, а также замену leave на явные операции с регистрами.
> кучи мат библиотек
Здесь пример слишком примитивный. Да и целью было не перемножить два вектора, а проиллюстрировать разные подходы.
Dummy00001 25.09.2011 21:13 # 0
олололо. сам попросил. aCC 6.06 c +O3 на Итанике 2:
Dummy00001 25.09.2011 21:14 # 0
вот тебе и пайплайнинг, и префетч c бранчпредикшн, и все че только можно.
Dummy00001 25.09.2011 21:16 # 0
bugmenot 25.09.2011 20:51 # +9
ctm 26.09.2011 11:51 # +2
1) уменьшить обращения к памяти (тут основные тормоза): mov [...], ... mov ..., [...] push ... pop ...
2) eax, ecx, edx не нужно сохранять
3) аргументы в функцию передаются по порядку: eax, edx, ecx, результат возвращается в eax. если метод класса, то первым параметром будет self
4) FPC в начале и в конце процедуры добавляет push ebp / pop ebp, даже если это не требуется
PS. оптимизация в старых версиях дельфи глючная.
ctm 26.09.2011 12:11 # 0
asm
push ebx
push esi
push edi
xor ebx, ebx
mov ecx, 2*n
@@l:
movzx edi, [eax]
mov esi, [edx]
imul edi, esi
and edi, $FFFF
add ebx, edi
movzx edi, [eax + 2]
shr esi, 16
imul edi, esi
add ebx, edi
add eax, 4
add edx, 4
dec ecx
jnz @@l
mov eax, ebx
pop edi
pop esi
pop ebx
end;
но он не будет работать для нечетного размера массива
RaZeR 27.09.2011 13:03 # −1
Отдельным ГК запостить не желаете? :)
guest8 09.04.2019 11:35 # −999