Помогите, пожалуйста, оптимизировать этот код (заполнение массива случайными неповторяющимися числами): Код (Text): mov ecx, 63 // Кол-во блоков массива по 4 байта mov edi, OFFSET list // edi = адрес массива xor eax, eax // mov [edi], eax // list[0] = 0 @@loop: // * mov [edi+ecx*4], eax // * Заполнение dec ecx // * list[1..255] нулями jnz @@loop // * @@L1: cmp cx, 256 // for (i=0; i<=255; i++) je @@exit // { call RealRandom // * fimul freeCount // * fld1 // * skip = (unsigned short int)(freeCount* fadd st(0), st(1) // * RealRandom()+1) fistp WORD PTR [skip] // * @@L1a: cmp skip, 0 // while (skip>0) jz @@L2 // { xor eax, eax // * mov al, location // * ror ax, 8 // * location = location%256+1 xor al, al // * rol ax, 8 // * inc ax // * mov location, al // * cmp BYTE PTR [edi+eax-1], 0 // if (list[location-1] == 0) then jnz @@L1a // --skip dec skip jmp @@L1a // } @@L2: mov BYTE PTR [edi+eax-1], cl // list[location-1] = i dec freeCount // --freeCount inc cx // jmp @@L1 @@exit: // } Интересует оптимизация по скорости. Всем спасибо за внимание!
1. Заменяй однобайтовые inc/dec на add. Выполняются адды быстрее. 2. Код (Text): ror ax, 8 // * location = location%256+1 xor al, al // * rol ax, 8 // * А чем and не устраивает? and eax, 0x00FFFFFF 3. 256 = 0x100 = 0000 ... 0001 0000 0000 (bin) юзай комманду bt проверяй 9й бит на 1цу Так вроде все. leo спец в этих вопросах. Ждем его комментов.
они долго грузятся, лучше развёртка цикла (не лучший пример): Код (Text): @@loop: // * mov [edi+ecx*4], eax mov [edi+ecx*4-4], eax sub ecx, 2 mov [edi+ecx*4], eax // * Заполнение dec ecx // * list[1..255] нулями jnz @@loop // * P.S. получше написал )
Код (Text): fimul freeCount fld1 fadd st(0), st(1) fistp WORD PTR [skip] @@L1a: cmp skip, 0 сделой чтото типа Код (Text): fimul freeCount fistp WORD PTR [skip] mov bx,[skip] inc bx с регистром операции быстрее чем с памятью
Большое всем спасибо! На Core 2 Duo. Код (Text): могу конечно тупить, но rep stosd вместо кода выше точно преимуществ не даст? До скорости даёт преемущество только до i80386-го процессора.
Вот что получилось: Код (Text): mov edi, OFFSET list xor eax, eax mov ebx, 63 mov [edi], eax @@loop: mov [edi+ebx*4], eax // * mov [edi+ebx*4-4], eax // * mov [edi+ebx*4-8], eax // * Заполнение sub ebx, 3 // * list[1..255] нулями jnz @@loop //* @@L1: bt bx, 8 // for (i=0; i<=255; i++) jc @@exit // { call RealRandom // * fimul freeCount // * fistp WORD PTR [skip] // * skip = (unsigned short int)(freeCount* mov cx, skip // * RealRandom()+1) add cx, 1 // * @@L1a: jecxz @@L2 // while (skip>0) and ax, 0x00FF // { add ax, 1 // * location = location%256+1 cmp BYTE PTR [edi+eax-1], 0 // if (list[location-1] == 0) then jnz @@L1a // --skip sub ecx, 1 // jmp @@L1a // } @@L2: mov BYTE PTR [edi+eax-1], bl // list[location-1] = i sub freeCount, 1 // --freeCount add bx, 1 // jmp @@L1 // @@exit: // }
AssemblerIA64 оригинал покажите? P.S. Код (Text): mov edi, OFFSET list xor eax, eax mov ebx, 63 mov [edi], eax @@loop: mov [edi+ebx*4], eax // * mov [edi+ebx*4-4], eax // * mov [edi+ebx*4-8], eax // * Заполнение sub ebx, 3 // * list[1..255] нулями jnz @@loop //* получше переписал Код (Text): mov ecx, 64 xor eax, eax lea edi, [ecx*4+list] neg ecx @@loop: mov [edi+ecx*4], eax ; // * mov [edi+ecx*4+4], eax ; // * mov [edi+ecx*4+8], eax ; // * mov [edi+ecx*4+12], eax ; // * Заполнение add ecx, 4 ; // * list[0..255] нулями jnz @@loop ; //*
t00x, Оригинал вверху темы. Вообще-то я взял код из книги и переписал его на ассемблере. Код (Text): получше переписал Спасибо! Завтра поэкспериментирую.
Тестирую версии алгоритма при помощи небезызвестной инструкции RDTSC. Прогоняю алгоритм несколько раз, суммирую результаты, делю на кол-во итераций. Самое интересное в том, что в зависимости от того, в каком порядке тестируются коды получаются разные результаты! Всегда быстрее тот код, скорость которого замеряется последней. Интересно, почему так? P.S. В диспетчере задач стоит приоритет реального времени.
Реализация алгоритма Бута для знаковых целых чисел (под архитектуру AMD64): Код (Text): mov rax, [Y] ; rax = Y - величина R xor rsi, rsi ; rsi = 0 - величина L mov [R], rax ; R = Y mov [L], rsi ; L = 0 xor rdx, rdx ; rdx = 0 - бит (n-1)-ый числа R mov r8b, 64 ; Кол-во итераций .0: and rax, 0x1 ; n-ый бит числа R (самый младший бит) mov rcx, rax xor rax, rdx ; Биты n и (n-1) различаются? jz .2 ; Если нет, то на .2 test rcx, rcx ; Бит n равен 0? jne .1b ; Если нет, то на .1b .1a: add rsi, [X] ; L = L + X jmp .2 .1b: sub rsi, [X] ; L = L - X .2: mov rax, [R] ; | Арифметический сдвиг shrd rax, rsi, 1 ; | связки <L:R> sar rsi, 1 ; | на 1 разряд mov [R], rax ; | вправо mov rdx, rcx ; (n-1)-ый бит = n-ый бит sub r8b, 1 jnz .0 mov [L], rsi Код (Text): X dq xxxxxxx ; Множимое Y dq xxxxxxx ; Множитель R dq ? ; Младшая часть результата L dq ? ; Старшая часть результата Можно ли что-нибудь убыстрить?
в целях оптимизации кода по скорости, можно например, использовать оставшиеся регистры для хранения переменных и избавиться от переходов .1a и .1b как-нибудь так Код (Text): ... mov r8b, 64 ; Кол-во итераций mov r6, [X] .0: mov r5, r6 ; neg r5 ; или not? and rax, 0x1 ; n-ый бит числа R (самый младший бит) mov rcx, rax cmovz r5, r6 xor rax, rdx ; Биты n и (n-1) различаются? jz .2 ; Если нет, то на .2 ; test rcx, rcx ; Бит n равен 0? ; jne .1b ; Если нет, то на .1b ; .1a: ; add rsi, [X] ; L = L + X ; jmp .2 ; .1b: ; sub rsi, [X] ; L = L - X add rsi, r5 .2: mov rax, [R] ; | Арифметический сдвиг
На основе Ваших советов + переделав кое-что сам, составил: Код (Text): mov rax, [Y] ; rax = Y xor rsi, rsi ; rsi = 0 - величина L mov r11, rax ; r11 = Y - величина R mov r10, [X] ; r10 = X - множимое xor rdx, rdx ; rdx = 0 - бит (n-1)-ый числа R mov r8b, 64 ; Кол-во итераций .0: mov r9, r10 neg r9 ; r9 = -r10 and rax, 0x1 ; n-ый бит числа R (самый младший бит) mov rcx, rax cmovz r9, r10 xor rax, rdx ; Биты n и (n-1) различаются? jz .2 ; Если нет, то на .2 add rsi, r9 ; L = L + X или L = L - X (взависимости от n-ого бита) .2: shrd r11, rsi, 1 ; | Арифметический сдвиг sar rsi, 1 ; | связки <L:R> на mov rax, r11 ; | 1 разряд вправо mov rdx, rcx ; (n-1)-ый бит = n-ый бит sub r8b, 1 jnz .0 mov [L], rsi mov [R], r11 Кстати, регистров r5, r6 нет, есть регистры r8-r15 (см. 79-ю страницу http://download.intel.com/design/processor/manuals/253665.pdf).
слова "убыстрить" кстати тоже Код (Text): ... mov cl, 64 ; Кол-во итераций xor r12, r12 ; const r12=0 mov r9, r10 neg r9 ; r9 = -r10 .0: mov r15, r10 and rax, 0x1 ; n-ый бит числа R (самый младший бит) ; mov rcx, rax cmovz r15, r10 xor rax, rdx ; Биты n и (n-1) различаются? cmovz r15, r12 ; jz .2 ; Если нет, то на .2 add rsi, r15 ; L = L + X или L = L - X (взависимости от n-ого бита) ; .2: shrd r11, rsi, 1 ; | Арифметический сдвиг ... sub cl, 1 jnz .0 в качестве счётчика цикла лучше использовать cl, и кол-во итераций можно посчитать заранее. P.S. изменение быстродействия не измеряли?