Re[6]: Быстрый способ обнулить блок памяти?
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.09.11 12:44
Оценка: 8 (4)
Здравствуйте, nbie, Вы писали:

N>Поясните еще раз эту мысль ("А из кеша в память льется струей" — к чему это).

N>Я, конечно пойду читать про кеш, но я думал я заполняю память по указателю непосредственно.

Вы пишете в кеш. Это такая маленькая быстрая память, припаянная прямо к процессору. Процессор потом, по своему усмотрению и без вашего участия, перемещает данные из кеша в память — да еще и с промежуточным буферированием в контроллере памяти.

Из кеша в контроллер памяти данные уходят блоками размером с cache line (это минимальная единица обмена между кешом и системной памятью). У современных x86-х процессоров кеш-лайн имеет размер 64 байта. Контроллер же памяти старается склеить эти обращения так, чтобы набрать целую "строку": работа "строками" — это самый быстрый способ работы с памятью. Чему сейчас равна строка, я даже и не знаю.

В общем, все сложно
Re[7]: Быстрый способ обнулить блок памяти?
От: watch-maker  
Дата: 12.09.11 13:32
Оценка: 4 (2)
Здравствуйте, Pzz, Вы писали:

N>>Поясните еще раз эту мысль ("А из кеша в память льется струей" — к чему это).

N>>Я, конечно пойду читать про кеш, но я думал я заполняю память по указателю непосредственно.

Pzz>Вы пишете в кеш. Это такая маленькая быстрая память, припаянная прямо к процессору. Процессор потом, по своему усмотрению и без вашего участия, перемещает данные из кеша в память — да еще и с промежуточным буферированием в контроллере памяти.


Pzz>Из кеша в контроллер памяти данные уходят блоками размером с cache line (это минимальная единица обмена между кешом и системной памятью). У современных x86-х процессоров кеш-лайн имеет размер 64 байта. Контроллер же памяти старается склеить эти обращения так, чтобы набрать целую "строку": работа "строками" — это самый быстрый способ работы с памятью. Чему сейчас равна строка, я даже и не знаю.


На самом деле запись в кеш не обязательна для объединения множественных записей в одну транзакцию.
Конечно, в кеш писать можно очень быстро. И если ваша цель сделать быструю функцию memset, то смело пишите в кеш.
Вот только проблема тут в том, что такая функция будет при своей работе вытеснять из кеша другие полезные данные. В результате чего получается ситуация, когда функция memset работает быстро, но код после её вызова начинает внезапно тормозить — причина проста, быстрый memset выкинул из кеша нужные в дальнейшем данные, оставив в нём лишь много-много нулей.
И понятно, что хотелось бы не только оптимизировать memset, но и не замедлять работу окружающего кода (ведь в жизни важна суммарная производительность программы, а не отдельных её кусочков).
Для этого в x86 процессорах есть streamming-инструкции (семейство movnt*), которые служат для записи в память минуя кеш. Грубо говоря, у этих инструкций есть как бы собственный кеш, но который не пересекается с основным, и для которого даже не поддерживается неявная когерентность. То есть можно записывать те же 16 байт из sse регистнов в этот буфер, где они будут объединятся в транзакции, и после этого записываться в память строками, минуя опять же кеш. Если данных в память записывается много (очевидно, что если мы обнуляем количество байт сравнимое с размером L2 кеша, то это уже много), то имеет смысл именно писать через streamming-инструкции, ведь в этом случае кешированная версия memset никак не будет быстрее чем streamming-версия, ибо первая версия будет даже сама себя из кеша вытеснять, а вторая просто будет лить данные прямо в память.
Re[5]: Быстрый способ обнулить блок памяти?
От: dilmah США  
Дата: 10.09.11 09:56
Оценка: 3 (2)
D>>за счет откладывания уплаты стоимости на момент(ы) первого доступа к этой памяти

N>Очень интересно. Подобного в Windows нет?

N>Могли бы сказать ключевые слова для поиска инф, чтобы понять смысл этих слов? ) Или разъяснить.

http://en.wikipedia.org/wiki/Memory_management_unit

примерно по тем же принципам по которым работает своп.
Современные процессоры автоматически отображают виртуальные адреса в физические. Если код пытается обратиться по виртуальному адресу который ни на что не отображается, то происходит trap и управление передается ОС. ОС смотрит что такое, и может разрешить это обращение, настроив отображение для этого адреса (для этой страницы памяти)

Когда ты делаешь mmap на /dev/zero то тебе просто выдают указатель на неициализированную память (которая не отображена ни на какие реальные адреса). Когда ты пытаешься обратится к ней, то срабатывает ловушка и ОС выделяет страницу памяти заполненную нулями.
Re: Быстрый способ обнулить блок памяти?
От: rm822 Россия  
Дата: 11.09.11 00:09
Оценка: 2 (1) +1
Здравствуйте, nbie, Вы писали:

N>Добрый день, коллеги.

N>Подскажите самый быстрый способ обнулить блок памяти (1000000 байт)?
самый бйстрый способ его просто выкинуть и выделить новый через virtualalloc
там он гарантированно будет забит нулями и занимается этим system idle process
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Быстрый способ обнулить блок памяти?
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.09.11 10:54
Оценка: 1 (1)
Здравствуйте, nbie, Вы писали:

N>Подскажите самый быстрый способ обнулить блок памяти (1000000 байт)?


Я бы начал с memset(), собрав программу под соответствующий процессор (а не под generic i386), и разрешив компилятору инлайнить такие функции. memset() не так уж наивно устроен. Потом я бы померил получившуюся скорость, сравнил бы ее с теоретическим пределом, и либо успокоился, либо сел бы думать дальше.
Re[2]: Быстрый способ обнулить блок памяти?
От: ononim  
Дата: 11.09.11 20:52
Оценка: 1 (1)
N>>Добрый день, коллеги.
N>>Подскажите самый быстрый способ обнулить блок памяти (1000000 байт)?
R>самый бйстрый способ его просто выкинуть и выделить новый через virtualalloc
R>там он гарантированно будет забит нулями и занимается этим system idle process
VirtualAlloc то сам по себе может и окажется быстрее чем memset на уже выделенную память, но вот последующее первое обращение к этой памяти... Ой ой ой. Поясняю на живом примере:
int wmain(int argc, wchar_t* argv[])
{
        volatile char *p = (volatile char *)malloc(0x100000);
        DWORD ticks = ::GetTickCount();
        for (int i = 0; i<10000; ++i)
        {
            memset((void *)p, 0, 0x100000);
        }
        printf("memset time: %u msec\n", ::GetTickCount() - ticks);
        free((void *)p);
        
        ticks = ::GetTickCount();
        for (int i = 0; i<10000; ++i)
        {
            volatile char *p = (volatile char *)::VirtualAlloc(0, 0x100000, MEM_COMMIT, PAGE_READWRITE);
            ::VirtualFree((void *)p, 0, MEM_RELEASE);
        }
        printf("VM time: %u msec\n", ::GetTickCount() - ticks);
        return 0;
}

Результаты:
memset time: 641 msec
VM time: 47 msec



Смеемся и плачем от счастья.. Потом думаем — ведь Virtual* теоретически подразумевают собой нехиый оверхед.. Идти в ядро, ковыряцца в таблицах страниц, дереве VAD процесса, Чота тут не так..
Слегка модифицируем тест:
void TouchMemory(volatile char *p, size_t l)
{
    while (l>=0x1000)
    {
        *p = *p;
        l-= 0x1000;
        p+= 0x1000;
    }
};

int wmain(int argc, wchar_t* argv[])
{
        volatile char *p = (volatile char *)malloc(0x100000);
        DWORD ticks = ::GetTickCount();
        for (int i = 0; i<10000; ++i)
        {
            memset((void *)p, 0, 0x100000);
            TouchMemory(p, 0x100000);
        }
        printf("memset time: %u msec\n", ::GetTickCount() - ticks);
        free((void *)p);
        
        ticks = ::GetTickCount();
        for (int i = 0; i<10000; ++i)
        {
            volatile char *p = (volatile char *)::VirtualAlloc(0, 0x100000, MEM_COMMIT, PAGE_READWRITE);
            TouchMemory(p, 0x100000);
            ::VirtualFree((void *)p, 0, MEM_RELEASE);
        }
        printf("VM time: %u msec\n", ::GetTickCount() - ticks);
        return 0;
}

Теперь результаты:
memset time: 688 msec
VM time: 2953 msec


Вот все и встало на свои места.. Итак винда похоже тоже практикует ленивую отдачу страниц, так что постоянный VirtualAlloc будет быстрее однократного malloc + многократного memset тока если не не планируете этой памятью пользоваться Справедливости ради, если делать многократные malloc/memset/free то оно все же медленее чем VM... Во всяком случае пока у винды не наступит жесткий голодняк свободных и уже обнуленных в бэкграундее страниц.
Как много веселых ребят, и все делают велосипед...
Re[6]: Быстрый способ обнулить блок памяти?
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.09.11 10:51
Оценка: +1
Здравствуйте, dilmah, Вы писали:

D>Когда ты делаешь mmap на /dev/zero то тебе просто выдают указатель на неициализированную память (которая не отображена ни на какие реальные адреса). Когда ты пытаешься обратится к ней, то срабатывает ловушка и ОС выделяет страницу памяти заполненную нулями.


Угу. Иными словами, к цене memset() добавляется цена обработки (аппаратного) исключения.
Re: Быстрый способ обнулить блок памяти?
От: DorfDepp  
Дата: 11.09.11 20:36
Оценка: :)
Здравствуйте, nbie, Вы писали:

N>Добрый день, коллеги.

N>Подскажите самый быстрый способ обнулить блок памяти (1000000 байт)?

N>PS Кроме SSE инструкций (заполнять по 16 байт) ничего нет?


В микроволновку на 2-3 секунды. Обнулится по первому классу.
Быстрый способ обнулить блок памяти?
От: nbie  
Дата: 10.09.11 09:08
Оценка:
Добрый день, коллеги.
Подскажите самый быстрый способ обнулить блок памяти (1000000 байт)?

PS Кроме SSE инструкций (заполнять по 16 байт) ничего нет?
Re: Быстрый способ обнулить блок памяти?
От: Аноним  
Дата: 10.09.11 09:11
Оценка:
Здравствуйте, nbie, Вы писали:

N>Добрый день, коллеги.

N>Подскажите самый быстрый способ обнулить блок памяти (1000000 байт)?

N>PS Кроме SSE инструкций (заполнять по 16 байт) ничего нет?


А что за ОС?
В Линукс можно выполнить mmap() нужного размера куска файла /dev/zero в память.
Re[2]: Быстрый способ обнулить блок памяти?
От: nbie  
Дата: 10.09.11 09:17
Оценка:
А>А что за ОС?
А>В Линукс можно выполнить mmap() нужного размера куска файла /dev/zero в память.

Пардон, Windows.

PS Но если говорить про linux: за счет чего такая операция имеет выигрыш производительности? Разве работа функции не сводится к побайтовому копированию или блочному по 16?
Re[3]: Быстрый способ обнулить блок памяти?
От: dilmah США  
Дата: 10.09.11 09:21
Оценка:
N>PS Но если говорить про linux: за счет чего такая операция имеет выигрыш производительности? Разве работа функции не сводится к побайтовому копированию или блочному по 16?

за счет откладывания уплаты стоимости на момент(ы) первого доступа к этой памяти
Re[4]: Быстрый способ обнулить блок памяти?
От: nbie  
Дата: 10.09.11 09:27
Оценка:
N>>PS Но если говорить про linux: за счет чего такая операция имеет выигрыш производительности? Разве работа функции не сводится к побайтовому копированию или блочному по 16?
D>за счет откладывания уплаты стоимости на момент(ы) первого доступа к этой памяти

Очень интересно. Подобного в Windows нет?
Могли бы сказать ключевые слова для поиска инф, чтобы понять смысл этих слов? ) Или разъяснить.
Re[2]: Быстрый способ обнулить блок памяти?
От: Pavel Dvorkin Россия  
Дата: 10.09.11 11:21
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, nbie, Вы писали:


N>>Подскажите самый быстрый способ обнулить блок памяти (1000000 байт)?


Pzz>Я бы начал с memset(), собрав программу под соответствующий процессор (а не под generic i386), и разрешив компилятору инлайнить такие функции. memset() не так уж наивно устроен. Потом я бы померил получившуюся скорость, сравнил бы ее с теоретическим пределом, и либо успокоился, либо сел бы думать дальше.


memset внутри себя вызывает SSE2 в определенных случаях. Случай ТС как раз такой. Поэтому имеет смысл попробовать SSE2 напрямую — обойтись без лишних проверок (а у ТС размер массива кратен 4). Будет ли эффект — трудно сказать.

Насчет инлайнить — можн поподробнее ? Трассировка в режиме релиз показывает, что она вызывается из библиотеки.
With best regards
Pavel Dvorkin
Re[3]: Быстрый способ обнулить блок памяти?
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.09.11 12:13
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>memset внутри себя вызывает SSE2 в определенных случаях. Случай ТС как раз такой. Поэтому имеет смысл попробовать SSE2 напрямую — обойтись без лишних проверок (а у ТС размер массива кратен 4). Будет ли эффект — трудно сказать.


При таком размере накладные расходы от этих проверок — копейки. Я бы не стал тратить время на возню с SSE, если memset достаточно хорош.

PD>Насчет инлайнить — можн поподробнее ? Трассировка в режиме релиз показывает, что она вызывается из библиотеки.


Это от компилятора зависит. gcc инлайнит эти функции, если оптимизация включена. Насчет MSVC я не особенно копенгаген . Смотрите здесь: http://msdn.microsoft.com/en-us/library/26td21ds.aspx
Re[3]: Быстрый способ обнулить блок памяти?
От: nbie  
Дата: 10.09.11 12:15
Оценка:
N>>>Подскажите самый быстрый способ обнулить блок памяти (1000000 байт)?

Pzz>>Я бы начал с memset(), собрав программу под соответствующий процессор (а не под generic i386), и разрешив компилятору инлайнить такие функции. memset() не так уж наивно устроен. Потом я бы померил получившуюся скорость, сравнил бы ее с теоретическим пределом, и либо успокоился, либо сел бы думать дальше.


PD>memset внутри себя вызывает SSE2 в определенных случаях. Случай ТС как раз такой. Поэтому имеет смысл попробовать SSE2 напрямую — обойтись без лишних проверок (а у ТС размер массива кратен 4). Будет ли эффект — трудно сказать.


Присоединяюсь к вопросу. Если заполнение блоками по 16 байт — это максимум скорости, то проделать это самому в цикле разве не будет оптимальным?
PS Кстати, может кто сказать почему в SSE 16 максимум (?)? Почему не больше?
И, пардон, что такое "TC"?
Re[4]: Быстрый способ обнулить блок памяти?
От: Pavel Dvorkin Россия  
Дата: 10.09.11 12:23
Оценка:
Здравствуйте, nbie, Вы писали:

N>Присоединяюсь к вопросу. Если заполнение блоками по 16 байт — это максимум скорости, то проделать это самому в цикле разве не будет оптимальным?


Тот же memset, только без проверок на случай, если размер не кратен 16.

N>PS Кстати, может кто сказать почему в SSE 16 максимум (?)? Почему не больше?


16 * 8 = 128 — разрядность SSE

N>И, пардон, что такое "TC"?


Не что, а кто Topic Starter.
With best regards
Pavel Dvorkin
Re[4]: Быстрый способ обнулить блок памяти?
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.09.11 12:23
Оценка:
Здравствуйте, nbie, Вы писали:

PD>>memset внутри себя вызывает SSE2 в определенных случаях. Случай ТС как раз такой. Поэтому имеет смысл попробовать SSE2 напрямую — обойтись без лишних проверок (а у ТС размер массива кратен 4). Будет ли эффект — трудно сказать.


N>Присоединяюсь к вопросу. Если заполнение блоками по 16 байт — это максимум скорости, то проделать это самому в цикле разве не будет оптимальным?


Это вы кеш заполняете блоками по 16 байт. А из кеша в память льется струей.

N>PS Кстати, может кто сказать почему в SSE 16 максимум (?)? Почему не больше?


Потому что самые большие програмно доступные регистры у x86 — это 16-байтные регистры SSE

N>И, пардон, что такое "TC"?


Topic Starter, вестимо
Re[4]: Быстрый способ обнулить блок памяти?
От: Pavel Dvorkin Россия  
Дата: 10.09.11 12:28
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Это от компилятора зависит. gcc инлайнит эти функции, если оптимизация включена. Насчет MSVC я не особенно копенгаген . Смотрите здесь: http://msdn.microsoft.com/en-us/library/26td21ds.aspx


Черт его знает. /Oi установил, Release, но все равно call и jmp в адреса 0x7xxxxxxx. Может, что-то не так делаю. А впрочем, ты прав — на миллион байт это все копейки.
With best regards
Pavel Dvorkin
Re[5]: Быстрый способ обнулить блок памяти?
От: nbie  
Дата: 10.09.11 12:38
Оценка:
Коллеги, все понял, кроме этого:

N> Если заполнение блоками по 16 байт — это максимум скорости, то проделать это самому в цикле разве не будет оптимальным?

P> Это вы кеш заполняете блоками по 16 байт. А из кеша в память льется струей.

Поясните еще раз эту мысль ("А из кеша в память льется струей" — к чему это).
Я, конечно пойду читать про кеш, но я думал я заполняю память по указателю непосредственно.
Re: Быстрый способ обнулить блок памяти?
От: MasterZiv СССР  
Дата: 10.09.11 17:16
Оценка:
On 10.09.2011 13:08, nbie wrote:
memset
Posted via RSDN NNTP Server 2.1 beta
Re: Быстрый способ обнулить блок памяти?
От: buver  
Дата: 11.09.11 20:01
Оценка:
N>Добрый день, коллеги.
N>Подскажите самый быстрый способ обнулить блок памяти (1000000 байт)?

N>PS Кроме SSE инструкций (заполнять по 16 байт) ничего нет?


вот тут есть какие-то слова по этому поводу
http://lwn.net/Articles/255364/
общая идея в том, что кеш использовать в этом случае не надо — это дополнительные затраты на чтение кешлайна, модификацию и запись назад.

кстат про sse, если у gcc задать уровень оптимизации -O3, то он даже для

for(i = 0; i<много; i++)
   buffer[i] = 0;


будет использовать sse инструкции, и я думаю в этих вопросах можно положиться на libc и gcc, ну или их виндовые аналоги.
Re: Быстрый способ обнулить блок памяти?
От: av_coder Украина  
Дата: 11.09.11 20:40
Оценка:
N>PS Кроме SSE инструкций (заполнять по 16 байт) ничего нет?

еще есть AVX инструкции там 32 байта
Re[3]: Быстрый способ обнулить блок памяти?
От: rm822 Россия  
Дата: 11.09.11 22:16
Оценка:
O>Вот все и встало на свои места.. Итак винда похоже тоже практикует ленивую отдачу страниц
валлок будет все время выдавать разные блоки памяти.
Ты всего лишь сравнил скорость зануления 1мб блока в кэше процессора vs 1мб блок в оперативке.
Понятно что в кэше-то их занулять намного быстрее.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[4]: Быстрый способ обнулить блок памяти?
От: ononim  
Дата: 12.09.11 06:39
Оценка:
O>>Вот все и встало на свои места.. Итак винда похоже тоже практикует ленивую отдачу страниц
R>валлок будет все время выдавать разные блоки памяти.
R>Ты всего лишь сравнил скорость зануления 1мб блока в кэше процессора vs 1мб блок в оперативке.
R>Понятно что в кэше-то их занулять намного быстрее.
Даже если и изза кэша, все равно медленно ведь
Как много веселых ребят, и все делают велосипед...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.