Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
mat_for_c
132 / 127 / 28
Регистрация: 26.04.2013
Сообщений: 636
Завершенные тесты: 2
#1

Обнулить элементы вектора через __asm - C++

06.04.2014, 15:06. Просмотров 810. Ответов 24
Метки нет (Все метки)

Хочу обнулить элементы вектора через __asm

C++
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
#include <vector>
#include <iostream>
 
using namespace std;
 
void main() {
   vector<vector<int>> v(2, vector <int> (3, 1));
 
   __asm {
      mov ecx, 2
      mov edi, v
      mov eax, dword ptr [edi + 16]
      mov edi, [edi][1]
        
      //mov dword ptr [edi + 8], 0
   cycl:
      mov dword ptr [edi + ecx*4], 0
      //add eax, 4
      loop cycl
   }
     
   for (int i = 0; i < 2; ++i) {
      for (int j = 0; j < 3; ++j)
         cout << v[i][j] << " ";
      cout << endl;
   }
}
Сам вопрос: eax и edi имеют разные значения, причем в eax лежит правильный результат. Я же хочу получить доступ ко 2-й строке через индексацию [1]. Как это реализовать?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
06.04.2014, 15:06     Обнулить элементы вектора через __asm
Посмотрите здесь:
Дан список, элементы которого являются координатами вектора. Найти длину вектора C++
STL. Функция, которая будет искать элементы большее среднего арифметического вектора и удалять их из вектора C++
C++ Используя алгоритм adjacent_find, обнулить первую пару соседних элементов вектора, имеющих одинаковую чётность
Заменить первые два нулевые элементы заданного вектора В на два первых НЕ нулевые элементы этого вектора C++
C++ Заменить первых 2 нулевые элементы заданного вектора соответственно на первых 2 не нулевые элементы этого вектора
Обнулить элементы матрицы C++
Обнулить нечетные элементы матрицы C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
DrOffset
6922 / 4115 / 942
Регистрация: 30.01.2014
Сообщений: 6,910
06.04.2014, 17:14     Обнулить элементы вектора через __asm #2
mat_for_c, зачем это нужно?
Индексация в векторе - это вызов метода (operator[]). Для того чтобы правильно обратиться к внутренностям вектора через asm нужно знать устройство вектора. А так же про всякие штуки типа выравнивания. Внутреннее устройство вектора в общем случае не обязано быть идентичным на разных компиляторах или версиях одного и того же. Более того, код, который компилятор сделает из С++ кода вектора тоже зависит от многих вещей. Может так случиться, что с одним уровнем оптимизации твой асм будет работать, а с другим - нет.
mat_for_c
132 / 127 / 28
Регистрация: 26.04.2013
Сообщений: 636
Завершенные тесты: 2
07.04.2014, 19:19  [ТС]     Обнулить элементы вектора через __asm #3
Цитата Сообщение от DrOffset Посмотреть сообщение
Может так случиться, что с одним уровнем оптимизации твой асм будет работать, а с другим - нет.
С этим я уже познакомился: например, в Debug не работает то, что работает в Release

Цитата Сообщение от DrOffset Посмотреть сообщение
А так же про всякие штуки типа выравнивания
А что именно знать надо? Пример можешь привести?
DrOffset
6922 / 4115 / 942
Регистрация: 30.01.2014
Сообщений: 6,910
07.04.2014, 20:31     Обнулить элементы вектора через __asm #4
Цитата Сообщение от mat_for_c Посмотреть сообщение
А что именно знать надо?
В общем случае это значит, что нужно знать как конкретный компилятор на конкретной платформе генерирует код.
Про выравнивание примеры есть по ссылке, много.
PS. Если ты надеешься выиграть в скорости таким образом - я тебя разочарую, вряд ли удастся обогнать компилятор, максимум сравняешься в скорости. Зато код будет непереносим и труден в сопровождении.

Добавлено через 10 минут
mat_for_c, вот, к примеру, я написал такой код для обнуления:
C++
1
2
3
4
5
void fill_raw(vector< vector<int> > & v)
{
    memset(&v[0][0], 0, v[0].size() * sizeof(int));
    memset(&v[1][0], 0, v[1].size() * sizeof(int));
}
из которого получилось вот это:
Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
_fill_raw:
    push    edi
    push    ebx
    mov ebx, DWORD PTR [esp+12]
    mov eax, DWORD PTR [ebx]
    mov edx, DWORD PTR [eax]
    mov ecx, DWORD PTR [eax+4]
    sub ecx, edx
    and ecx, -4
    xor eax, eax
    mov edi, edx
    rep stosb
    mov ecx, DWORD PTR [ebx]
    mov edx, DWORD PTR [ecx+12]
    mov ecx, DWORD PTR [ecx+16]
    sub ecx, edx
    and ecx, -4
    mov edi, edx
    rep stosb
    pop ebx
    pop edi
    ret
mingw32 c оптимизацией -02

Добавлено через 24 минуты
Теперь добавим цикл для общего случая:
C++
1
2
3
4
5
6
7
void fill_raw(vector< vector<int> > & v)
{
    for(int i = 0, s = v.size(); i < s; ++i)
    {
        memset(&v[i][0], 0, v[i].size() * sizeof(int));
    }
}
Получаем:
Кликните здесь для просмотра всего текста
Assembler
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
_fill_raw:
    push    ebp
    push    edi
    push    esi
    push    ebx
    mov esi, DWORD PTR [esp+20]
    mov ecx, DWORD PTR [esi]
    mov eax, DWORD PTR [esi+4]
    sub eax, ecx
    sar eax, 2
    lea edx, [eax+eax*4]
    lea edx, [eax+edx*4]
    lea edx, [eax+edx*4]
    mov ebx, edx
    sal ebx, 8
    add edx, ebx
    mov ebx, edx
    sal ebx, 16
    add edx, ebx
    lea ebp, [eax+edx*2]
    xor edx, edx
    xor eax, eax
    test    ebp, ebp
    jg  L6
    jmp L2
L9:
    mov ecx, DWORD PTR [esi]
L6:
    lea ebx, [edx+edx*2]
    lea ecx, [ecx+ebx*4]
    mov ebx, DWORD PTR [ecx]
    mov ecx, DWORD PTR [ecx+4]
    sub ecx, ebx
    and ecx, -4
    mov edi, ebx
    rep stosb
    inc edx
    cmp edx, ebp
    jne L9
L2:
    pop ebx
    pop esi
    pop edi
    pop ebp
    ret

В принципе можно отталкиваться от приведенных примеров для написания своего (только с учетом компилятора и версии, конечно же) Но на самом деле я привел их для того, чтобы показать, что компилятор не дурак и код будет эффективен, если изначально правильно написан. А главное его можно будет перенести без проблем на другой компилятор.
mat_for_c
132 / 127 / 28
Регистрация: 26.04.2013
Сообщений: 636
Завершенные тесты: 2
07.04.2014, 22:10  [ТС]     Обнулить элементы вектора через __asm #5
DrOffset, попробовал так:
Кликните здесь для просмотра всего текста
C++
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
#include <vector>
#include <iostream>
#include <iterator>
 
using namespace std;
 
void main() {
   vector<vector<int>> v(2, vector <int> (3, 1));
   vector<vector<int>> v_copy = v;
 
   vector<vector<int>>::iterator ptr_v = v.begin();
 
   __asm {
      mov ecx, 2
 
      mov edi, ptr_v
      mov edi, [ptr_v]
        
      mov eax, v_copy 
      mov eax, [eax]
   cycl:
      mov dword ptr [edi + ecx*4], 0
      mov dword ptr [eax + ecx*4], 0
      loop cycl
   }
     
   for (int i = 0; i < 2; ++i) {
      for (int j = 0; j < 3; ++j)
         cout << v[i][j] << " ";
      cout << endl;
   }
 
   for (int i = 0; i < 2; ++i) {
      for (int j = 0; j < 3; ++j)
         cout << v_copy[i][j] << " ";
      cout << endl;
   }
}


почему когда делаешь через итератор, изменения не сохраняются ???
DrOffset
6922 / 4115 / 942
Регистрация: 30.01.2014
Сообщений: 6,910
08.04.2014, 00:12     Обнулить элементы вектора через __asm #6
mat_for_c, потому что так вообще нельзя делать. vector < vector <int> > - это ведь не просто двумерный массив. А итератор - это не просто указатель. И адрес его не обязан совпадать с адресом элемента. Вектор гарантирует только, что:
1) Память будет распределена непрерывной областью.
2) Операция взятия адреса от элемента даст адрес памяти в которой он находится.
&v[0] - адрес первого вектора vector<int>
&v[0][0] - адрес элемента int первого вектора.
Чтобы правильно адресовать элементы - нужно выяснить механизм адресации, который использует компилятор. Лучший способ это выяснить - декомпилировать программу с нормальным обращением (код на С++) к элементу.
mat_for_c
132 / 127 / 28
Регистрация: 26.04.2013
Сообщений: 636
Завершенные тесты: 2
08.04.2014, 19:08  [ТС]     Обнулить элементы вектора через __asm #7
DrOffset, через итераторы работает )). Это я не правильно написал:

Assembler
1
2
mov edi, [ptr_v] ; не так надо
mov edi, [edi] ; о как
и все изменения сохраняет
DrOffset
6922 / 4115 / 942
Регистрация: 30.01.2014
Сообщений: 6,910
08.04.2014, 19:21     Обнулить элементы вектора через __asm #8
Цитата Сообщение от mat_for_c Посмотреть сообщение
через итераторы работает ))
повезло.
Так зачем оно нужно-то?
mat_for_c
132 / 127 / 28
Регистрация: 26.04.2013
Сообщений: 636
Завершенные тесты: 2
08.04.2014, 20:50  [ТС]     Обнулить элементы вектора через __asm #9
Цитата Сообщение от DrOffset Посмотреть сообщение
зачем оно нужно-то?
хочу проверить, получится ли разогнать цикл или нет...

Спасибо за помощь )
DrOffset
6922 / 4115 / 942
Регистрация: 30.01.2014
Сообщений: 6,910
08.04.2014, 22:09     Обнулить элементы вектора через __asm #10
Цитата Сообщение от mat_for_c Посмотреть сообщение
хочу проверить, получится ли разогнать цикл или нет...
Используй memset вместо цикла. Твой асм код пока что медленнее, чем делает компилятор.
mat_for_c
132 / 127 / 28
Регистрация: 26.04.2013
Сообщений: 636
Завершенные тесты: 2
10.04.2014, 18:52  [ТС]     Обнулить элементы вектора через __asm #11
Цитата Сообщение от DrOffset Посмотреть сообщение
memset вместо цикла
не все так просто. мне нужно не все элементы обнулять, а большинство из них (примерно 80 - 90 % от размера вектора)

Цитата Сообщение от DrOffset Посмотреть сообщение
PS. Если ты надеешься выиграть в скорости таким образом - я тебя разочарую, вряд ли удастся обогнать компилятор, максимум сравняешься в скорости. Зато код будет непереносим и труден в сопровождении.
вот какая штука: протестил я програмки (c __asm и без) на

Intel core i5 M 460 2,53 Ghz и
AMD Phenom II X6 1035T Processor 2,60 GHz.

результаты:
14 сек __asm проиграл компилятору на Intel'е
~ 1 мин __asm выйграл компилятора на AMD
0x10
2459 / 1631 / 238
Регистрация: 24.11.2012
Сообщений: 4,009
10.04.2014, 18:56     Обнулить элементы вектора через __asm #12
Цитата Сообщение от mat_for_c Посмотреть сообщение
протестил я програмки (c __asm и без)
Тут еще надо детально закапываться в то, как именно тестили. Кастануть бы на форум Андрея Аксенова - он в паре матерных фраз объяснил бы как надо бенчмаркать)
DrOffset
6922 / 4115 / 942
Регистрация: 30.01.2014
Сообщений: 6,910
10.04.2014, 18:59     Обнулить элементы вектора через __asm #13
Цитата Сообщение от mat_for_c Посмотреть сообщение
14 сек __asm проиграл компилятору на Intel'е
~ 1 мин __asm выйграл компилятора на AMD
А можно код бенчмарков посмотреть? Интересно же
mat_for_c
132 / 127 / 28
Регистрация: 26.04.2013
Сообщений: 636
Завершенные тесты: 2
10.04.2014, 19:05  [ТС]     Обнулить элементы вектора через __asm #14
Цитата Сообщение от DrOffset Посмотреть сообщение
можно код бенчмарков посмотреть
а что это ???

Добавлено через 2 минуты
Цитата Сообщение от 0x10 Посмотреть сообщение
Тут еще надо детально закапываться в то, как именно тестили
обычным способом: запускаем .exe и в самой программе через clock() замеряем время.
DrOffset
6922 / 4115 / 942
Регистрация: 30.01.2014
Сообщений: 6,910
10.04.2014, 19:06     Обнулить элементы вектора через __asm #15
mat_for_c, Тест производительности

Добавлено через 44 секунды
Цитата Сообщение от mat_for_c Посмотреть сообщение
обычным способом: запускаем .exe и в самой программе через clock() замеряем время.
Я думаю он тоже имел в виду код, а не способ замера (хотя это тоже важно).
mat_for_c
132 / 127 / 28
Регистрация: 26.04.2013
Сообщений: 636
Завершенные тесты: 2
10.04.2014, 19:14  [ТС]     Обнулить элементы вектора через __asm #16
а вам весь код нужен (он оч. большой)? или только того участка, за место чего __asm вставлялась?
0x10
2459 / 1631 / 238
Регистрация: 24.11.2012
Сообщений: 4,009
10.04.2014, 19:16     Обнулить элементы вектора через __asm #17
Минимальный компилируемый код, на котором можно пронаблюдать разницу в производительности.
DrOffset
6922 / 4115 / 942
Регистрация: 30.01.2014
Сообщений: 6,910
10.04.2014, 19:19     Обнулить элементы вектора через __asm #18
mat_for_c, если кинешь вложением в личку или сюда (как удобнее), то мне все равно какого он размера Компилятор Visual Studio я так понимаю?
mat_for_c
132 / 127 / 28
Регистрация: 26.04.2013
Сообщений: 636
Завершенные тесты: 2
10.04.2014, 19:59  [ТС]     Обнулить элементы вектора через __asm #19
Цитата Сообщение от DrOffset Посмотреть сообщение
Visual Studio
VS 2010 professional

Добавлено через 43 секунды
я тогда щас похожий код настрочу...

Добавлено через 31 минуту
вот та минимальная часть кода:
Кликните здесь для просмотра всего текста
C++
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
#include <vector>
#include <iostream>
#include <algorithm>
#include <time.h>
 
using namespace std;
 
int main() {
   vector <int> vec(50000, 10);
   vector <int> zero_position;
 
   int i;
   for (i = 3; i < 45000; ++i)
      zero_position.push_back(i);
   int size_ZPos = zero_position.size();
    
   clock_t begin = clock();
   for (int j = 0; j < 400000; ++j) {
      for (i = 0; i < size_ZPos; ++i)
         vec[zero_position[i]] = 0;
   }
   cout << "for " << (clock() - begin)/1000.0 << endl;
 
   fill(vec.begin(), vec.end(), 10); // вернем исходное значение
 
   // далее __asm
 
   vector <int> :: iterator ptr_ZPos = zero_position.begin();
   // он мне нужен, т.к. zero_position берется из vector<vector<int>>
   // чтобы знать смещение от начала (грубо говоря)
   clock_t asm_begin = clock();
   for (int j = 0; j < 400000; ++j) {
      __asm {
         mov ecx, size_ZPos
         mov eax, vec
         mov ebx, ptr_ZPos
cycle:
         mov edx, [ebx] // получили номер обнуляющей позиции
         shl edx, 2 // смещение для int кратно 4, делаю сдвиг
         mov dword ptr [eax + edx], 0
         add ebx, 4
         loop cycle
         mov edx, [ebx]
         shl edx, 2
         mov dword ptr [eax + edx], 0
      }
   }
   cout << "asm " << (clock() - asm_begin)/1000.0 << endl;
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.04.2014, 20:44     Обнулить элементы вектора через __asm
Еще ссылки по теме:
C++ Массивы. Обнулить элементы столбцов
Обнулить элементы матрицы A=176 C++
Обнулить четные элементы матрицы C++
C++ Обнулить все положительные элементы матрицы
Обнулить элементы заданного столбца матрицы C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
DrOffset
6922 / 4115 / 942
Регистрация: 30.01.2014
Сообщений: 6,910
10.04.2014, 20:44     Обнулить элементы вектора через __asm #20
mat_for_c, проверил, спасибо.
На своей системе получил 11с на коде компилятора, против 41с асма (который кстати еще можно улучшить). У меня i3.
По поводу твоего результата на AMD: в целом это значит, что VS делает свои оптимизации с заточкой на Intel платформу.

Однако тут попутно возникла пара проблем.
Во-первых, если я переношу код в функцию или немного меняю порядок или способ передачи векторов в нее, то программа начинает падать. Ну это было ожидаемо и об этом я предупреждал.
Во-вторых, и это более важно. После работы обоих алгоритмов векторы не равны между собой (я сохранил результата работы первого алгоритма и сравнил с результатом второго, векторы не равны). Это значит, что асм делает заполнение как-то иначе. И это - проблема.
Yandex
Объявления
10.04.2014, 20:44     Обнулить элементы вектора через __asm
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru