Не.
b |= mas[i + 0];
b |= mas[i + 1];
b |= mas[i + 2];
b |= mas[i + 3];Да.
b0 |= mas[i + 0];
b1 |= mas[i + 1];
b2 |= mas[i + 2];
b3 |= mas[i + 3];Это может спасти, если у твоего процессора нет другого узкого места (например, чтения из памяти не каждый такт запускать может).
IronPeter, пробовал и так и так — результат идентичен - 200мс. Также пробовал включать поддержку SSE в опциях компилятора, что никак не повлияло.)
Если кому интересно, насчет memcmp который посоветовал Sbtrn. Devil.
с таким кодом:
bool onlyZeros = mas[0] == 0 && memcmp(mas, mas+1, SIZE * sizeof(int) - 4) == 0;
при тех же условиях (1Гб массив int, все нули кроме последнего), получаются такие результаты:
memcmp #0: 220 ms, onlyZeros : 0 memcmp #1: 220 ms, onlyZeros : 0 memcmp #2: 221 ms, onlyZeros : 0 memcmp #3: 225 ms, onlyZeros : 0 memcmp #4: 222 ms, onlyZeros : 0
*стоит отметить, что в целом функция показывает лучшие результаты, по сравнению с другими (кроме специфического случая как в примере).
наскока я знаю архитектуру то есть жестокий аппаратный вариант.
на каждую страницу памяти можно повесить прерывании на чтения на запись,....
так вот у нас уже посчитано для каждой странице нулевая она или нет. и есть счетчик сколько не нулевых страниц.
также на каждой странице висит прерывания на попытку записи.
как тока произошла попытка записи в страницу будет прерывании мы метим данную страницу как неопределенную, отключаемся от прерывания для данной странице, и уменьшаем счетчик ненулевых страниц.
когда нам нужно знать нулевая область или нет то смотрим счетчик ненулевых страниц и если он не 0 то область ненулевая,
в противном случаи пробегаемся по всем неопределенным страницам(до первой ненулевой) и корректируем счетчик ну далее если = 0 то область нулевая если != 0 то нет.
А вобще смысл обсуждать 1гб нулевых данных?
Часто приходиться пробегаться по коллекции и проверять на значение какой нибудь bool. но там данные не упорядочены, количество редко превышает 10к.
ДА еще на GUI можно.
rAmpArk
> IronPeter, пробовал и так и так — результат идентичен - 200мс. Также пробовал
> включать поддержку SSE в опциях компилятора, что никак не повлияло.)
компилятор MS? покажи асм-выхлоп того кода, что привел IronPeter, возможно компилятор не сделал оптимизацию под sse.
Я и не надеялся на SSE от компилятора. Я просто считаю такты процессора. Если частота 2 гигагерца и он умеет запускать чтение из памяти и арифметическую операцию каждый такт, то тогда тот цикл должен требовать 100 ms, т.е. вчистую шина должна ограничивать.
IronPeter
стало интересно. решил тоже посчитать.
вообщем компилятор выдает такой код:
int i = 0; 00321021 xor eax,eax 00321023 jmp main+30h (321030h) 00321025 lea esp,[esp] 0032102C lea esp,[esp] for( ; i < size; i += 4) { b0 |= mas[i + 0]; 00321030 or ecx,dword ptr [ebp+eax*4-3E84h] b1 |= mas[i + 1]; 00321037 or edx,dword ptr [ebp+eax*4-3E80h] // эта пара инструкций спаривается b2 |= mas[i + 2]; 0032103E or esi,dword ptr [ebp+eax*4-3E7Ch] b3 |= mas[i + 3]; 00321045 or edi,dword ptr [ebp+eax*4-3E78h] // и эта 0032104C add eax,4 0032104F cmp eax,0FA0h // здесь спаривания нету, т.к. чтение после записи 00321054 jb main+30h ( 321030h) }
итого, с учетом спаривания инструкций я насчитал 5 тактов в цикле (или чуть больше, т.к. я не помню, какая инструкция сколько занимает тактов). поправьте меня, если я не прав.
получается, что на вычисления затрачивается 2 такта, а на организация цикла 3? тогда можно попробовать вынести в цикл чуть больше вычислений. дискасс :)
RaZOR
видимо отдельно выделять 4 переменные не так уж необходимо:
for(int i = 0; i < SIZE; i++) { b |= mas[i]; //000000013FCD11E0 mov ecx,dword ptr [rdx-8] //000000013FCD11E3 add rdx,10h //000000013FCD11E7 or ecx,dword ptr [rdx-14h] //000000013FCD11EA or ecx,dword ptr [rdx-0Ch] //000000013FCD11ED or ecx,dword ptr [rdx-10h] //000000013FCD11F0 or ebx,ecx //000000013FCD11F2 dec r8 //000000013FCD11F5 jne main+1E0h (13FCD11E0h) }
в итоге количество итераций получается SIZE/4
rAmpArk
итого,
у тебя: 6 тактов х size
у IronPeter: 5 тактов х (size/4)
вроде как...
edit: форматирование
RaZOR
> итого,
> у тебя: 6 тактов х size
> у IronPeter: 5 тактов х (size/4)
> вроде как...
да, из отличий - отсутствие мува, но все-таки (size/4) итераций, и время исполнения одинаково ~187мс, т.к., как я понял, одинаково число обращений к памяти.
for(int i = 0; i < SIZE; i+=4) { b0 |= mas[i]; //000000013FDF1110 or edi,dword ptr [rcx-8] b1 |= mas[i+1]; //000000013FDF1113 or esi,dword ptr [rcx-4] b2 |= mas[i+2]; //000000013FDF1116 or ebp,dword ptr [rcx] b3 |= mas[i+3]; //000000013FDF1118 or ebx,dword ptr [rcx+4] //000000013FDF111B add rcx,10h //000000013FDF111F dec rdx //000000013FDF1122 jne main+110h (13FDF1110h) }
susageP
к этому нет доступа из UserMode
RaZOR
а с __int64 что будет ?
небольшой анроллинг можно сделать однако
Pushkoff
> к этому нет доступа из UserMode
Вроде есть, называеться Protect у страниц
P.S. Смотри VirtualAlloc в MSDN и дальше по ссылкам
susageP
> на каждую страницу памяти можно повесить прерывании на чтения на запись,....
исключения
innuendo
> а с __int64 что будет ?
а он ему нужен? или что ты имеешь ввиду?
Тема в архиве.