Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.80/15: Рейтинг темы: голосов - 15, средняя оценка - 4.80
223 / 213 / 80
Регистрация: 26.04.2013
Сообщений: 972
1

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

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

Author24 — интернет-сервис помощи студентам
Хочу обнулить элементы вектора через __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]. Как это реализовать?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
06.04.2014, 15:06
Ответы с готовыми решениями:

обнулить каждый 5-ый элемент вектора
Вроде все должно работать, в компиляторе CodeBlocks все работает, а в Visual Studio 2012 выводится...

Дан список, элементы которого являются координатами вектора. Найти длину вектора
1. Дан список, элементы которого являются координатами вектора в n-мерном пространстве. Найти длину...

STL. Функция, которая будет искать элементы большее среднего арифметического вектора и удалять их из вектора
у меня есть вектор, помогите пожалуйста дописать функцию, которая будет искать элементы большее...

Используя алгоритм adjacent_find, обнулить первую пару соседних элементов вектора, имеющих одинаковую чётность
Дан вектор V. Обнулить первую пару соседних элементов, имеющих одинаковую четность. Например,...

24
18893 / 9850 / 2410
Регистрация: 30.01.2014
Сообщений: 17,293
06.04.2014, 17:14 2
mat_for_c, зачем это нужно?
Индексация в векторе - это вызов метода (operator[]). Для того чтобы правильно обратиться к внутренностям вектора через asm нужно знать устройство вектора. А так же про всякие штуки типа выравнивания. Внутреннее устройство вектора в общем случае не обязано быть идентичным на разных компиляторах или версиях одного и того же. Более того, код, который компилятор сделает из С++ кода вектора тоже зависит от многих вещей. Может так случиться, что с одним уровнем оптимизации твой асм будет работать, а с другим - нет.
0
223 / 213 / 80
Регистрация: 26.04.2013
Сообщений: 972
07.04.2014, 19:19  [ТС] 3
Цитата Сообщение от DrOffset Посмотреть сообщение
Может так случиться, что с одним уровнем оптимизации твой асм будет работать, а с другим - нет.
С этим я уже познакомился: например, в Debug не работает то, что работает в Release

Цитата Сообщение от DrOffset Посмотреть сообщение
А так же про всякие штуки типа выравнивания
А что именно знать надо? Пример можешь привести?
0
18893 / 9850 / 2410
Регистрация: 30.01.2014
Сообщений: 17,293
07.04.2014, 20:31 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

В принципе можно отталкиваться от приведенных примеров для написания своего (только с учетом компилятора и версии, конечно же) Но на самом деле я привел их для того, чтобы показать, что компилятор не дурак и код будет эффективен, если изначально правильно написан. А главное его можно будет перенести без проблем на другой компилятор.
1
223 / 213 / 80
Регистрация: 26.04.2013
Сообщений: 972
07.04.2014, 22:10  [ТС] 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;
   }
}


почему когда делаешь через итератор, изменения не сохраняются ???
0
18893 / 9850 / 2410
Регистрация: 30.01.2014
Сообщений: 17,293
08.04.2014, 00:12 6
mat_for_c, потому что так вообще нельзя делать. vector < vector <int> > - это ведь не просто двумерный массив. А итератор - это не просто указатель. И адрес его не обязан совпадать с адресом элемента. Вектор гарантирует только, что:
1) Память будет распределена непрерывной областью.
2) Операция взятия адреса от элемента даст адрес памяти в которой он находится.
&v[0] - адрес первого вектора vector<int>
&v[0][0] - адрес элемента int первого вектора.
Чтобы правильно адресовать элементы - нужно выяснить механизм адресации, который использует компилятор. Лучший способ это выяснить - декомпилировать программу с нормальным обращением (код на С++) к элементу.
0
223 / 213 / 80
Регистрация: 26.04.2013
Сообщений: 972
08.04.2014, 19:08  [ТС] 7
DrOffset, через итераторы работает )). Это я не правильно написал:

Assembler
1
2
mov edi, [ptr_v] ; не так надо
mov edi, [edi] ; о как
и все изменения сохраняет
0
18893 / 9850 / 2410
Регистрация: 30.01.2014
Сообщений: 17,293
08.04.2014, 19:21 8
Цитата Сообщение от mat_for_c Посмотреть сообщение
через итераторы работает ))
повезло.
Так зачем оно нужно-то?
0
223 / 213 / 80
Регистрация: 26.04.2013
Сообщений: 972
08.04.2014, 20:50  [ТС] 9
Цитата Сообщение от DrOffset Посмотреть сообщение
зачем оно нужно-то?
хочу проверить, получится ли разогнать цикл или нет...

Спасибо за помощь )
0
18893 / 9850 / 2410
Регистрация: 30.01.2014
Сообщений: 17,293
08.04.2014, 22:09 10
Цитата Сообщение от mat_for_c Посмотреть сообщение
хочу проверить, получится ли разогнать цикл или нет...
Используй memset вместо цикла. Твой асм код пока что медленнее, чем делает компилятор.
0
223 / 213 / 80
Регистрация: 26.04.2013
Сообщений: 972
10.04.2014, 18:52  [ТС] 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
0
3257 / 2059 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
10.04.2014, 18:56 12
Цитата Сообщение от mat_for_c Посмотреть сообщение
протестил я програмки (c __asm и без)
Тут еще надо детально закапываться в то, как именно тестили. Кастануть бы на форум Андрея Аксенова - он в паре матерных фраз объяснил бы как надо бенчмаркать)
0
18893 / 9850 / 2410
Регистрация: 30.01.2014
Сообщений: 17,293
10.04.2014, 18:59 13
Цитата Сообщение от mat_for_c Посмотреть сообщение
14 сек __asm проиграл компилятору на Intel'е
~ 1 мин __asm выйграл компилятора на AMD
А можно код бенчмарков посмотреть? Интересно же
0
223 / 213 / 80
Регистрация: 26.04.2013
Сообщений: 972
10.04.2014, 19:05  [ТС] 14
Цитата Сообщение от DrOffset Посмотреть сообщение
можно код бенчмарков посмотреть
а что это ???

Добавлено через 2 минуты
Цитата Сообщение от 0x10 Посмотреть сообщение
Тут еще надо детально закапываться в то, как именно тестили
обычным способом: запускаем .exe и в самой программе через clock() замеряем время.
0
18893 / 9850 / 2410
Регистрация: 30.01.2014
Сообщений: 17,293
10.04.2014, 19:06 15
mat_for_c, Тест производительности

Добавлено через 44 секунды
Цитата Сообщение от mat_for_c Посмотреть сообщение
обычным способом: запускаем .exe и в самой программе через clock() замеряем время.
Я думаю он тоже имел в виду код, а не способ замера (хотя это тоже важно).
0
223 / 213 / 80
Регистрация: 26.04.2013
Сообщений: 972
10.04.2014, 19:14  [ТС] 16
а вам весь код нужен (он оч. большой)? или только того участка, за место чего __asm вставлялась?
0
3257 / 2059 / 351
Регистрация: 24.11.2012
Сообщений: 4,909
10.04.2014, 19:16 17
Минимальный компилируемый код, на котором можно пронаблюдать разницу в производительности.
0
18893 / 9850 / 2410
Регистрация: 30.01.2014
Сообщений: 17,293
10.04.2014, 19:19 18
mat_for_c, если кинешь вложением в личку или сюда (как удобнее), то мне все равно какого он размера Компилятор Visual Studio я так понимаю?
0
223 / 213 / 80
Регистрация: 26.04.2013
Сообщений: 972
10.04.2014, 19:59  [ТС] 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;
}
0
18893 / 9850 / 2410
Регистрация: 30.01.2014
Сообщений: 17,293
10.04.2014, 20:44 20
mat_for_c, проверил, спасибо.
На своей системе получил 11с на коде компилятора, против 41с асма (который кстати еще можно улучшить). У меня i3.
По поводу твоего результата на AMD: в целом это значит, что VS делает свои оптимизации с заточкой на Intel платформу.

Однако тут попутно возникла пара проблем.
Во-первых, если я переношу код в функцию или немного меняю порядок или способ передачи векторов в нее, то программа начинает падать. Ну это было ожидаемо и об этом я предупреждал.
Во-вторых, и это более важно. После работы обоих алгоритмов векторы не равны между собой (я сохранил результата работы первого алгоритма и сравнил с результатом второго, векторы не равны). Это значит, что асм делает заполнение как-то иначе. И это - проблема.
0
10.04.2014, 20:44
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
10.04.2014, 20:44
Помогаю со студенческими работами здесь

Заменить первые два нулевые элементы заданного вектора В на два первых НЕ нулевые элементы этого вектора
Дано вектор В, состоящий из N действительных чисел. Заменить первые два нулевые элементы заданного...

Заменить первых 2 нулевые элементы заданного вектора соответственно на первых 2 не нулевые элементы этого вектора
Заданный вектор Т, который состоит из n действительных чисел. Заменить первых 2 нулевые элементы...

Из вектора С(n) сформировать вектор A, содержащий чётные элементы вектора С и вектор В содержащий нечётные элементы
С++, массив из вектора С(n) сформировать вектор A, содержащий чётные элементы вектора С и вектор В...

Обнулить элементы матрицы
Элементы матрицыT стоящие на пересечение четных строк и четных столбцов обнулить! РЕшите...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru