Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> memcpy, реализация под VS (2010) 
:(
    Опции темы
ForceKeeper
Дата 6.9.2011, 02:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 25
Регистрация: 17.3.2010
Где: Минск

Репутация: нет
Всего: нет



Из праздного интереса сравнил производительность на своем ПК родного memcpy и такого цикла
Код

short* destination = (short*)mas;
short* source = (short*)mas + 300000;
for(int i = 0; i < 700000; ++i)
destination[i] = source[i];

Дефолтная функция оказалась в 10-11 раз быстрее. Может кто знает, что за сильное колдунство в ней применено?

P.S.
mas - интовский массив, так что, если я ничего не путаю, проблем с выравниванием по вордам не должно быть

PM MAIL WWW   Вверх
boostcoder
Дата 6.9.2011, 02:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



копирование двойными словами или четвертными словами.
PM WWW   Вверх
newbee
Дата 6.9.2011, 02:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: 3
Всего: 19



AFAIK в memcpy используются какие-то специальные ассемблерные функции. Как msvc не знаю, а GCC при -03 выравнивает производительность memcpy и наколеночной реализации.

Добавлено через 1 минуту и 9 секунд
Утром исходник посмотрю.


--------------------
You're face to face
With man who sold the world
PM   Вверх
volatile
Дата 6.9.2011, 02:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(ForceKeeper @  6.9.2011,  02:44 Найти цитируемый пост)
Может кто знает, что за сильное колдунство в ней применено

Посмотрите исходники. все ран-таймовские сорцы должны быть. 
Вот исходник от 2008 студии (2010 под рукой нет, но думаю там ничего кардинального с memcpy не произошло)
Код

void * __cdecl memcpy (
        void * dst,
        const void * src,
        size_t count
        )
{
        void * ret = dst;

#if defined (_M_IA64)

        {


        __declspec(dllimport)


        void RtlCopyMemory( void *, const void *, size_t count );

        RtlCopyMemory( dst, src, count );

        }

#else  /* defined (_M_IA64) */
        /*
         * copy from lower addresses to higher addresses
         */
        while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
        }
#endif  /* defined (_M_IA64) */

        return(ret);
}


Цитата(ForceKeeper @  6.9.2011,  02:44 Найти цитируемый пост)
Дефолтная функция оказалась в 10-11 раз быстрее.

Такая разница из-за того что вы скорей всего в дебаге собрали.
Нужно собирать в релизе, с ключами оптимизации на скорость.
к тому-же шорты немного медленней чем инты, или чары.
Но главное оптимизация!


Это сообщение отредактировал(а) volatile - 6.9.2011, 03:00
PM MAIL   Вверх
boostcoder
Дата 6.9.2011, 03:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



пример: http://notes.sochi.org.ru/1322/
в CRT GCC что-то вроде этой. но посложнее.
еще помню, однажды для копирования массивов, нужна была ооочень быстрая memcpy(). я в инетах нашел кучу. но тесты показали, что дефолтная нисколько не медленнее.

Добавлено через 1 минуту и 3 секунды
Цитата(volatile @  6.9.2011,  02:58 Найти цитируемый пост)
        while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
        }

позор! smile 
PM WWW   Вверх
volatile
Дата 6.9.2011, 03:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(boostcoder @  6.9.2011,  03:03 Найти цитируемый пост)
позор!

Почему позор?
PM MAIL   Вверх
boostcoder
Дата 6.9.2011, 03:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



побайтное копирование! smile

Добавлено через 6 минут и 56 секунд
volatile, посмотри на это? http://lxr.linux.no/linux+v3.0.4/arch/x86/...tring_32.h#L168
выше реализованы использованные в ней функции.

Добавлено через 8 минут и 31 секунду
одна из них в другом файле: http://lxr.linux.no/linux+v3.0.4/arch/x86/lib/mmx_32.c#L28
PM WWW   Вверх
volatile
Дата 6.9.2011, 03:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(boostcoder @  6.9.2011,  03:12 Найти цитируемый пост)
побайтное копирование!

Где-то в старом борланде я видел асмовую memcpy, с копированиями 32-разрядными словами.
Внешне очень красивая. с трюками и развернутыми циклами. щас не могу найти. может завтра..
Но в реале она боюсь окажется не на много быстрее... Это связано с современными процессорами.
Там основное время тратится на не попадание в внутренний кеш процессора.
(страница памяти). И это невелирует различия побайтного и пословного копирования.


Вообще может сравню раельную производительность, если будет время.
PM MAIL   Вверх
boostcoder
Дата 6.9.2011, 03:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



Цитата(volatile @  6.9.2011,  03:27 Найти цитируемый пост)
Там основное время тратится на не попадание в внутренний кеш процессора.

кеш может на что-то повлиять, если происходит копирование массивов размером меньше линии кеша. это первое.
второе - т.к. массивов два(источник-приемник), то тогда оба массива должны попасть каждый в свою линию(иначе толку от одного кеша не будет). а это маловероятно.
третье - копирование словами/двойными_словами - всегда быстрее. сравни.

Это сообщение отредактировал(а) boostcoder - 6.9.2011, 03:35
PM WWW   Вверх
volatile
Дата 6.9.2011, 03:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(boostcoder @  6.9.2011,  03:33 Найти цитируемый пост)
кеш может на что-то повлиять, если происходит копирование массивов размером меньше линии кеша.


Пример:
1. Побайтое копирование
читаем первый байт, который не находится в кеше. тратим на это 1000 тактов. (грубо)
читаем второй байт (а он уже в кеше) тратим на это 2 такта 
читаем 3 -ий байт тратим  2 такта 
читаем 4 -ый байт тратим  2 такта 
итого 1006 тактов.

2. Теперь читаем словами.
читаем слово, не попадаем в кеш, тратим 1000 тактов.

итого разница между побайтным и пословным копированием 1000 против 1006.

Цифры взял с потолка, просто чтоб объяснить свою мысль.

Цитата(boostcoder @  6.9.2011,  03:33 Найти цитируемый пост)
копирование словами/двойными_словами - всегда быстрее

не спорю. просто возможно что не на много.
Реально может сравню.

PM MAIL   Вверх
boostcoder
Дата 6.9.2011, 03:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



Цитата(volatile @  6.9.2011,  03:45 Найти цитируемый пост)
Пример:
1. Побайтое копирование
читаем первый байт, который не находится в кеше. тратим на это 1000 тактов. (грубо)
читаем второй байт (а он уже в кеше) тратим на это 2 такта 
читаем 3 -ий байт тратим  2 такта 
читаем 4 -ый байт тратим  2 такта 
итого 1006 тактов.

2. Теперь читаем словами.
читаем слово, не попадаем в кеш, тратим 1000 тактов.

итого разница между побайтным и пословным копированием 1000 против 1006.

размер линии кеша - 64 байта.
а теперь посчитай сколько тактов потребуется для копирования массива объемом 128 байт, к примеру ;)
PM WWW   Вверх
Silent
Дата 6.9.2011, 09:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 252
Регистрация: 3.10.2006

Репутация: 1
Всего: 9



Решил проверить, делая ставку на стандартную memcpy:
Код

#include <stdio.h>
#include <memory.h>
#include <Windows.h>
const int N = 70000000;

short mas[N];
short mas2[N];
short * dest = (short*)&mas,
      * source = (short*)&mas2;

void copy1()
{
    memcpy(dest,source,N*sizeof(short));
}

void copy2()
{
    for (int i = 0; i < N; i++)
        dest[i] = source[i];
}

int main()
{
    for (int i = 0; i < N; i++) source[i] = i+1;
    int time = GetTickCount();
    copy1();
    int end = GetTickCount();
    copy2();
    int end2 = GetTickCount();
    printf("Time1: %d\nTime2: %d\n",end-time,end2-end);
    return 0;
}


Результат неожиданный: 
Код

Time1: 79
Tim2: 46


Конфигурация - VS2010, WinXP SP3, i3, 2Gb. Проверил на VS2008 - результат аналогичный.

Посмотрел в ассемблерный листинг - самописанные процедуры в обоих студиях записались так:
Код

    push    esi
    push    edi

; 18   :    for (int i = 0; i < N; i++)
; 19   :        dest[i] = source[i];

    mov    ecx, 35000000                ; 02160ec0H
    mov    esi, OFFSET ?mas2@@3PAFA        ; mas2
    mov    edi, OFFSET ?mas@@3PAFA            ; mas
    rep movsd
    pop    edi
    pop    esi

(копирование строки с адреса ds:esi в адрес es:edi)

А вот memcpy - вызов внешней функции:
Код

    push    140000000                ; 08583b00H
    push    OFFSET ?mas2@@3PAFA            ; mas2
    push    OFFSET ?mas@@3PAFA            ; mas
    call    _memcpy
    add    esp, 12


Эм... дефолтная функция не умеет использовать процессор на всю катушку?
PM MAIL   Вверх
boostcoder
Дата 6.9.2011, 09:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



volatile же показал код memcpy() используемой в VC2008. чего он нее ожидать-то? smile 
PM WWW   Вверх
Silent
Дата 6.9.2011, 11:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 252
Регистрация: 3.10.2006

Репутация: 1
Всего: 9



ну я не знаю... надеялся на оптимизационные способности компилятора )))
PM MAIL   Вверх
volatile
Дата 6.9.2011, 12:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(Silent @  6.9.2011,  09:38 Найти цитируемый пост)
Time1: 79
Tim2: 46

Ребята, современные процессоры, довольно сложные штуковины.
там 3 уровня кеша.
К тому-же GetTickCount(); слишком груба чтобы сравнивать промежутки времени меньше минуты
у нее слишком большая дискретность.

Но дело здесь не в этом. Здесь дело в страничном выделении памяти.
Первая процедцра копирования работает с не выделенной памятью и тратит кучу времени на выделение этой памяти.
Вторая уже работает с выделенной памятью.
Просто поменяйте функции местами, и скорость получится не в вашу пользу с точность до наоборот


Код

system   = 100%
selfmade = 54%

Просто меняю очередность вызовов местами:
Код

system   = 100%
selfmade = 156%

Функции брал ваши без переделки.
 smile 
PM MAIL   Вверх
Estranged
Дата 6.9.2011, 14:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 30.8.2010

Репутация: нет
Всего: 3



Реализация в VS 2010 на ASM. Влезьте внутрь, все увидите.
PM MAIL   Вверх
volatile
Дата 6.9.2011, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(Estranged @  6.9.2011,  14:56 Найти цитируемый пост)
Влезьте внутрь, все увидите. 

Estranged, куда влезать то? В бинарник? Дык там конечно асмовые инструкции.
Просто приведите исходник, все исходники CRT идут со студией.

2010 студии под рукой нет, просто интуитивно, не думаю что в 2010 стали переписывать стандартные библиотеки на асме, времена не те...
PM MAIL   Вверх
voral
Дата 6.9.2011, 16:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 16.3.2008
Где: Иваново

Репутация: нет
Всего: нет



Вон, что гугл наше на микрософтовом сайте http://research.microsoft.com/en-us/um/red...rt/memcpy.c.htm
Правда есть и такое C:\Program Files\Microsoft Visual Studio 8\VC\crt\src\intel\memcpy.asm

Это сообщение отредактировал(а) voral - 6.9.2011, 16:22
PM MAIL WWW   Вверх
Silent
Дата 6.9.2011, 21:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 252
Регистрация: 3.10.2006

Репутация: 1
Всего: 9



А ведь есть еще великий и могучий SSE - никто не пользовался MOVDQA (sse2) или MOVNTDQA (sse4)?
PM MAIL   Вверх
boostcoder
Дата 6.9.2011, 21:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



вот: http://stackoverflow.com/questions/269408/...4-bit-processes
говорят что 2Гб/сек smile 
PM WWW   Вверх
volatile
Дата 6.9.2011, 23:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(voral @  6.9.2011,  16:20 Найти цитируемый пост)
Правда есть и такое C:\Program Files\Microsoft Visual Studio 8\VC\crt\src\intel\memcpy.asm

Да действительно, асмовая версия тоже есть.
Видимо подставляются разные в зависимости от способа вызова (intrinsic/ not intrinsic), и от ключей оптимизации.

Добавлено через 5 минут и 48 секунд
Цитата(Silent @  6.9.2011,  21:07 Найти цитируемый пост)
А ведь есть еще великий и могучий SSE 

Один мой знакомый программер как-то добивался максимальной скорости копирования. (игрушку делал)
И он уверял, что именно с SSE ему удалось добиться самой максимальной скорости копирования памяти. (чуть ли не в разы)
Но в подробности я не вникал, так как для моих задач и системной вполне хватает.

PM MAIL   Вверх
ForceKeeper
Дата 6.9.2011, 23:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 25
Регистрация: 17.3.2010
Где: Минск

Репутация: нет
Всего: нет



Насчет ассемблера, открыл в Олли откомпиленый под релизом экзеншник, зашел в memcpy и вот, какой цикл там нашел
Код

MOVDQA XMM0,DQWORD PTR DS:[ESI]
MOVDQA XMM1,DQWORD PTR DS:[ESI+10]
MOVDQA XMM2,DQWORD PTR DS:[ESI+20]
MOVDQA XMM3,DQWORD PTR DS:[ESI+30]
MOVDQA DQWORD PTR DS:[EDI],XMM0
MOVDQA DQWORD PTR DS:[EDI+10],XMM1
MOVDQA DQWORD PTR DS:[EDI+20],XMM2
MOVDQA DQWORD PTR DS:[EDI+30],XMM3
MOVDQA XMM4,DQWORD PTR DS:[ESI+40]
MOVDQA XMM5,DQWORD PTR DS:[ESI+50]
MOVDQA XMM6,DQWORD PTR DS:[ESI+60]
MOVDQA XMM7,DQWORD PTR DS:[ESI+70]
MOVDQA DQWORD PTR DS:[EDI+40],XMM4
MOVDQA DQWORD PTR DS:[EDI+50],XMM5
MOVDQA DQWORD PTR DS:[EDI+60],XMM6
MOVDQA DQWORD PTR DS:[EDI+70],XMM7
LEA ESI,[ESI+80]
LEA EDI,[EDI+80]
DEC EDX
JNE SHORT 72980A72
 
P.S.
Цитата
(игрушку делал)

Та же история)

Это сообщение отредактировал(а) ForceKeeper - 6.9.2011, 23:48
PM MAIL WWW   Вверх
boostcoder
Дата 7.9.2011, 00:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



Цитата(ForceKeeper @  6.9.2011,  23:37 Найти цитируемый пост)
и вот, какой цикл там нашел

значит с этим все в порядке.


ForceKeeper, покажи этот же асм-код но только с адресами.

Цитата(volatile @  6.9.2011,  23:28 Найти цитируемый пост)
(чуть ли не в разы)

повторюсь. я тоже копал в этом направлении. но оказалось, что стандартная функция работает быстрее всех реализаций использующих MMX/3DNow которые я нашел. я показал почему ;)

Добавлено через 5 минут и 21 секунду
только что обратил внимание на такой момент.
MMX регистров восемь.
но оба кода(последний и тот что я приводил из исходников linux-kernel) работают следующим образом:
1. из источника копируется в 4 регистра.
2. из этих регистров в приемник.
3. из источника копируется в остальные 4 регистра.
4. из них в приемник.

а почему не сразу из источника в 8 регистров?
PM WWW   Вверх
volatile
Дата 7.9.2011, 00:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(ForceKeeper @  6.9.2011,  23:37 Найти цитируемый пост)
зашел в memcpy и вот, какой цикл там нашел

ForceKeeper, ну раз так, то это в очередной раз показывает, что погоду в скорости копирования вносит не столько сам код, сколько попадания/промахи кеша. (верней разных кешей).
У вас ведь этот код работал медленней вашей самодельной, насколько я понял?
PM MAIL   Вверх
boostcoder
Дата 7.9.2011, 00:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



Цитата(volatile @  7.9.2011,  00:09 Найти цитируемый пост)
У вас ведь этот код работал медленней вашей самодельной, насколько я понял?

запутался smile 
PM WWW   Вверх
voral
Дата 7.9.2011, 00:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 158
Регистрация: 16.3.2008
Где: Иваново

Репутация: нет
Всего: нет



Кстати  у Страуструпа есть примерно следующая реализация копирования массива. Реально дает прирост по отношению к простому поэлементному копированию. (обсуждали както на киберфоруме)
Код

void mcpy (int *to, int *from, int count)
{
  int n = (count + 7) / 8;
  swith (count % 8)
  {
    case 0: do { *to++ = *from++;
    case 7:      *to++ = *from++;
    case 6:      *to++ = *from++;
    case 5:      *to++ = *from++;
    case 4:      *to++ = *from++;
    case 3:      *to++ = *from++;
    case 2:      *to++ = *from++;
    case 1:      *to++ = *from++;
            } while (--n > 0);
  }
}

PM MAIL WWW   Вверх
volatile
Дата 7.9.2011, 00:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(boostcoder @  7.9.2011,  00:13 Найти цитируемый пост)
запутался 

Ну он говорил, что системная работает медленней (почти в 2 раза) чем самодельная (с шортами)
Цитата(Silent @  6.9.2011,  09:38 Найти цитируемый пост)
Time1: 79
Tim2: 46


PM MAIL   Вверх
ForceKeeper
Дата 7.9.2011, 00:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 25
Регистрация: 17.3.2010
Где: Минск

Репутация: нет
Всего: нет



Цитата(boostcoder @  7.9.2011,  00:00 Найти цитируемый пост)
покажи этот же асм-код но только с адресами

Адреса команд этого кода в памяти?
Код

72980A72  |  MOVDQA XMM0,DQWORD PTR DS:[ESI]
72980A76  |  MOVDQA XMM1,DQWORD PTR DS:[ESI+10]
72980A7B  |  MOVDQA XMM2,DQWORD PTR DS:[ESI+20]
72980A80  |  MOVDQA XMM3,DQWORD PTR DS:[ESI+30]
72980A85  |  MOVDQA DQWORD PTR DS:[EDI],XMM0
72980A89  |  MOVDQA DQWORD PTR DS:[EDI+10],XMM1
72980A8E  |  MOVDQA DQWORD PTR DS:[EDI+20],XMM2
72980A93  |  MOVDQA DQWORD PTR DS:[EDI+30],XMM3
72980A98  |  MOVDQA XMM4,DQWORD PTR DS:[ESI+40]
72980A9D  |  MOVDQA XMM5,DQWORD PTR DS:[ESI+50]
72980AA2  |  MOVDQA XMM6,DQWORD PTR DS:[ESI+60]
72980AA7  |  MOVDQA XMM7,DQWORD PTR DS:[ESI+70]
72980AAC  |  MOVDQA DQWORD PTR DS:[EDI+40],XMM4
72980AB1  |  MOVDQA DQWORD PTR DS:[EDI+50],XMM5
72980AB6  |  MOVDQA DQWORD PTR DS:[EDI+60],XMM6
72980ABB  |  MOVDQA DQWORD PTR DS:[EDI+70],XMM7
72980AC0  |  LEA ESI,[ESI+80]
72980AC6  |  LEA EDI,[EDI+80]
72980ACC  |  DEC EDX
72980ACD  |  JNE SHORT 72980A72


Цитата(volatile @  7.9.2011,  00:09 Найти цитируемый пост)
У вас ведь этот код работал медленней вашей самодельной, насколько я понял?

Код в моих последних двух постах из родного memcpy и он работал многократно быстрее, чем мой примитивный тапок, копирующий по словам.
PM MAIL WWW   Вверх
boostcoder
Дата 7.9.2011, 00:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



Цитата(ForceKeeper @  7.9.2011,  00:24 Найти цитируемый пост)
Адреса команд этого кода в памяти?

да. спасибо.
PM WWW   Вверх
volatile
Дата 7.9.2011, 00:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(ForceKeeper @  7.9.2011,  00:24 Найти цитируемый пост)
из родного memcpy и он работал многократно быстрее


А это кто писал, или это было не из родного memcpy ?
Цитата(Silent @ 6.9.2011,  09:38)
Решил проверить, делая ставку на стандартную memcpy:
Код

#include <stdio.h>
#include <memory.h>
#include <Windows.h>
const int N = 70000000;

short mas[N];
short mas2[N];
short * dest = (short*)&mas,
      * source = (short*)&mas2;

void copy1()
{
    memcpy(dest,source,N*sizeof(short));
}

void copy2()
{
    for (int i = 0; i < N; i++)
        dest[i] = source[i];
}

int main()
{
    for (int i = 0; i < N; i++) source[i] = i+1;
    int time = GetTickCount();
    copy1();
    int end = GetTickCount();
    copy2();
    int end2 = GetTickCount();
    printf("Time1: %d\nTime2: %d\n",end-time,end2-end);
    return 0;
}


Результат неожиданный: 
Код

Time1: 79
Tim2: 46


Конфигурация - VS2010, WinXP SP3, i3, 2Gb. Проверил на VS2008 - результат аналогичный.



PM MAIL   Вверх
boostcoder
Дата 7.9.2011, 00:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



Цитата(volatile @  7.9.2011,  00:09 Найти цитируемый пост)
погоду в скорости копирования вносит не столько сам код, сколько попадания/промахи кеша. (верней разных кешей).

поясни. откуда такие выводы?
PM WWW   Вверх
volatile
Дата 7.9.2011, 00:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(boostcoder @  7.9.2011,  00:33 Найти цитируемый пост)
поясни. откуда такие выводы? 

Почитайте последний пост на первой странице. От простой перестановки вызовов функций, скорость меняется в 3 раза.

Впрочем, возможно скоро займусь этим вопросом поближе, и сам все тщательно проверю.
О результатах сообщу, если будет интересно.

PM MAIL   Вверх
boostcoder
Дата 7.9.2011, 00:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



Цитата(volatile @  7.9.2011,  00:40 Найти цитируемый пост)
Почитайте последний пост на первой странице.

тот пост подтверждает пользу привносимую кешированием самой ОС. но никак не кешем проца. ибо я понял что ты говоришь про именно про него.
PM WWW   Вверх
ForceKeeper
Дата 7.9.2011, 00:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 25
Регистрация: 17.3.2010
Где: Минск

Репутация: нет
Всего: нет



Цитата(volatile @  7.9.2011,  00:33 Найти цитируемый пост)
А это кто писал, или это было не из родного memcpy ?

Это был не я. 

Кстате, вот касательно выделения памяти. Когда ковырял свой тестирующий код и поменял местами выполнение своего цикла и родного memcpy так, чтобы дефолтная функция шла первой, так ее отработка стала медленнее (но все равно быстрее моего цикла). После этого я прямо перед ней кинул цикл, в котором пробегал весь массив и кидал туда числа - скорость отработки memcpy стала преждней (т.е. быстрой)
Код

int* mas = new int[1000000];

for(int i = 0; i < 1000000; ++i)
    mas[i] = i;

LARGE_INTEGER beforeMemcpy, afterMemcpy;
QueryPerformanceCounter(&beforeMemcpy);
TestMemcpy(mas);
QueryPerformanceCounter(&afterMemcpy);

LARGE_INTEGER beforeMemcpy_my, afterMemcpy_my;
QueryPerformanceCounter(&beforeMemcpy_my);
TestMemcpy_MY(mas);
QueryPerformanceCounter(&afterMemcpy_my);

delete[] mas;


Почему неинициализированный мусор медленнее копируется?

P.S.
Пока писал пост, тут уже успели упомянуть кэш операционки...

Это сообщение отредактировал(а) ForceKeeper - 7.9.2011, 01:01
PM MAIL WWW   Вверх
volatile
Дата 7.9.2011, 01:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(ForceKeeper @  7.9.2011,  00:56 Найти цитируемый пост)
Это был не я. 

ForceKeeper, упс, сорри. спутал вас. действительно сорри!! 

Цитата(boostcoder @  7.9.2011,  00:49 Найти цитируемый пост)
тот пост подтверждает пользу привносимую кешированием самой ОС. но никак не кешем проца. ибо я понял что ты говоришь про именно про него. 

Я вообще говорю о разных кешах. И о том что правильно измерить скорость очень трудно.
Сам не раз убеждался что от простой перестановки функций, скорость может меняться в 3-4 раза.
Поэтому судить о скорости по единичному измерениию не стоит.

ForceKeeper, еще раз сорри!
PM MAIL   Вверх
boostcoder
Дата 7.9.2011, 01:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



Цитата(ForceKeeper @  7.9.2011,  00:56 Найти цитируемый пост)
Почему неинициализированный мусор медленнее копируется?

уже ответил.

Цитата(volatile @  7.9.2011,  01:09 Найти цитируемый пост)
Я вообще говорю о разных кешах.

ты знаешь...из последних нескольких постов, сложно понять о каком кеше ты говоришь smile 
PM WWW   Вверх
volatile
Дата 7.9.2011, 01:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(boostcoder @  7.9.2011,  01:19 Найти цитируемый пост)
сложно понять о каком кеше ты говоришь   

я говорю просто о других (кроме кода) причинах (и кеши в том числе) влияющих на скорость.

PM MAIL   Вверх
xvr
Дата 8.9.2011, 12:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 35
Всего: 223



Цитата(boostcoder @  7.9.2011,  00:00 Найти цитируемый пост)
а почему не сразу из источника в 8 регистров? 

Видимо что бы не забить каналы чтения в память. Их ограниченное число и если запустить чтений больше, чем каналов, то те команды, на которые не хватило каналов, будут остановлены.

PM MAIL   Вверх
boostcoder
Дата 8.9.2011, 12:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



Цитата(xvr @  8.9.2011,  12:26 Найти цитируемый пост)
если запустить чтений больше, чем каналов, то те команды, на которые не хватило каналов, будут остановлены

не знал о таком. точнее - не задумывался.
PM WWW   Вверх
ForceKeeper
Дата 8.9.2011, 21:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 25
Регистрация: 17.3.2010
Где: Минск

Репутация: нет
Всего: нет



В итоге я наковырял такую функцию, она хоть и значительно быстрее простого цикла, но все равно на ПК медленнее где-то на 30-40%, а на нетбуке на 50-70% чем memcpy из VS2010
Код

static void TestMemcpy_sse(void* pDest, void* pSrc, int numOfBytes)
{
    if(numOfBytes < CACHE_LINE_SIZE)
    {
        _asm
        {
            mov    ecx, numOfBytes
            mov edi, pDest
            mov esi, pSrc
            rep movsb
        }
        return;
    }
    int destOffset = (int)pDest % 16;
    if(destOffset > 0)
    {
        _asm
        {
            mov    ecx, destOffset
            mov    edi, numOfBytes
            sub edi, ecx
            mov numOfBytes, edi
            mov    edi, pDest
            mov    esi, pSrc
            rep    movsb
            add    edi, destOffset
            add    esi, destOffset
            mov    pDest, edi
            mov    pSrc, esi
        }
    }
    if((int)pSrc % 16 == 0)
    {
        _asm
        {
            mov esi, pSrc
            prefetchnta [esi]
            mov ecx, numOfBytes
            mov edi, pDest

            cmp ecx, 128
            jb A64
A128:
            prefetchnta XMMWORD PTR[esi + 16 * 4]
            movdqa xmm0, XMMWORD PTR[esi]
            movdqa xmm1, XMMWORD PTR[esi + 16 * 1]
            movdqa xmm2, XMMWORD PTR[esi + 16 * 2]
            movdqa xmm3, XMMWORD PTR[esi + 16 * 3]
            movdqa XMMWORD PTR[edi], xmm0
            movdqa XMMWORD PTR[edi + 16 * 1], xmm1
            movdqa XMMWORD PTR[edi + 16 * 2], xmm2
            movdqa XMMWORD PTR[edi + 16 * 3], xmm3

            prefetchnta XMMWORD PTR[esi + 16 * 8]
            movdqa xmm4, XMMWORD PTR[esi + 16 * 4]
            movdqa xmm5, XMMWORD PTR[esi + 16 * 5]
            movdqa xmm6, XMMWORD PTR[esi + 16 * 6]
            movdqa xmm7, XMMWORD PTR[esi + 16 * 7]
            movdqa XMMWORD PTR[edi + 16 * 4], xmm4
            movdqa XMMWORD PTR[edi + 16 * 5], xmm5
            movdqa XMMWORD PTR[edi + 16 * 6], xmm6
            movdqa XMMWORD PTR[edi + 16 * 7], xmm7

            add esi, 128
            prefetchnta [esi]
            add edi, 128
            sub ecx, 128
            cmp ecx, 128
            jae A128
A64:
            cmp ecx, 64
            jb  A32
            prefetchnta XMMWORD PTR[esi]
            sub ecx, 64

            movdqa xmm0, XMMWORD PTR[esi]
            movdqa xmm1, XMMWORD PTR[esi + 16 * 1]
            movdqa xmm2, XMMWORD PTR[esi + 16 * 2]
            movdqa xmm3, XMMWORD PTR[esi + 16 * 3]
            movdqa XMMWORD PTR[edi], xmm0
            movdqa XMMWORD PTR[edi + 16 * 1], xmm1
            movdqa XMMWORD PTR[edi + 16 * 2], xmm2
            movdqa XMMWORD PTR[edi + 16 * 3], xmm3

            add esi, 64
            add edi, 64
A32:
            prefetchnta XMMWORD PTR[esi]
            cmp ecx, 32
            jb  A16
            sub ecx, 32

            movdqa xmm4, XMMWORD PTR[esi]
            movdqa xmm5, XMMWORD PTR[esi + 16 * 1]
            movdqa XMMWORD PTR[edi], xmm4
            movdqa XMMWORD PTR[edi + 16 * 1], xmm5

            add esi, 32
            add edi, 32
A16:
            cmp ecx, 16
            jb  A
            sub ecx, 16
            movdqa xmm6, XMMWORD PTR[esi]
            movdqa XMMWORD PTR[edi], xmm6
A:
            sfence
        }
    }
    else
    {
        _asm
        {
            mov ecx, numOfBytes
            mov esi, pSrc
            prefetchnta [esi]
            mov edi, pDest

            cmp ecx, 128
            jb U64
U128:
            prefetchnta XMMWORD PTR[esi + 16 * 4]
            movdqu xmm0, XMMWORD PTR[esi]
            movdqu xmm1, XMMWORD PTR[esi + 16 * 1]
            movdqu xmm2, XMMWORD PTR[esi + 16 * 2]
            movdqu xmm3, XMMWORD PTR[esi + 16 * 3]
            movdqu XMMWORD PTR[edi], xmm0
            movdqu XMMWORD PTR[edi + 16 * 1], xmm1
            movdqu XMMWORD PTR[edi + 16 * 2], xmm2
            movdqu XMMWORD PTR[edi + 16 * 3], xmm3

            prefetchnta XMMWORD PTR[esi + 16 * 8]
            movdqu xmm4, XMMWORD PTR[esi + 16 * 4]
            movdqu xmm5, XMMWORD PTR[esi + 16 * 5]
            movdqu xmm6, XMMWORD PTR[esi + 16 * 6]
            movdqu xmm7, XMMWORD PTR[esi + 16 * 7]
            movdqu XMMWORD PTR[edi + 16 * 4], xmm4
            movdqu XMMWORD PTR[edi + 16 * 5], xmm5
            movdqu XMMWORD PTR[edi + 16 * 6], xmm6
            movdqu XMMWORD PTR[edi + 16 * 7], xmm7

            add esi, 128
            prefetchnta [esi]
            add edi, 128
            sub ecx, 128
            cmp ecx, 128
            jae U128
U64:
            cmp ecx, 64
            jb  U32
            prefetchnta XMMWORD PTR[esi]
            sub ecx, 64

            movdqu xmm0, XMMWORD PTR[esi]
            movdqu xmm1, XMMWORD PTR[esi + 16 * 1]
            movdqu xmm2, XMMWORD PTR[esi + 16 * 2]
            movdqu xmm3, XMMWORD PTR[esi + 16 * 3]
            movdqu XMMWORD PTR[edi], xmm0
            movdqu XMMWORD PTR[edi + 16 * 1], xmm1
            movdqu XMMWORD PTR[edi + 16 * 2], xmm2
            movdqu XMMWORD PTR[edi + 16 * 3], xmm3
 
            add esi, 64
            add edi, 64
U32:
            prefetchnta XMMWORD PTR[esi]
            cmp ecx, 32
            jb  U16
            sub ecx, 32

            movdqu xmm4, XMMWORD PTR[esi]
            movdqu xmm5, XMMWORD PTR[esi + 16 * 1]
            movdqu XMMWORD PTR[edi], xmm4
            movdqu XMMWORD PTR[edi + 16 * 1], xmm5

            add esi, 32
            add edi, 32
U16:
            cmp ecx, 16
            jb  U
            sub ecx, 16

            movdqu xmm6, XMMWORD PTR[esi]
            movdqu XMMWORD PTR[edi], xmm6
U:
            sfence
        }
    }
    int residue = numOfBytes % 16;
    if(residue > 0)
    {
        _asm
        {
            mov ecx, residue
            mov ebx, numOfBytes
            mov edi, pDest
            add edi, ebx
            sub edi, ecx
            mov esi, pSrc
            add esi, ebx
            sub esi, ecx
            rep movsb
        }
    }

    return;
}

PM MAIL WWW   Вверх
boostcoder
Дата 8.9.2011, 21:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 20
Всего: 110



фигасе функция smile 
PM WWW   Вверх
ForceKeeper
Дата 8.9.2011, 22:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 25
Регистрация: 17.3.2010
Где: Минск

Репутация: нет
Всего: нет



Основной цикл копирования моей функции в результирующем бинарнике идентичен тому, что в мемцпу (равзе что у меня счетчик в ecx, а в родной функции в edx) Но ощутимое отстование в скорости все равно есть, хотя во всем остальном коде есть еще только 3 цикла и то, они каждый на 64, 16 и 16 соотвественно итераций макисмум.

P.S.
наверно родная функция еще что-то делает с данными, т.к. при увеличение объема копируемой информации разрыв в скорости растет, а основной цикл копирования идентичен, в то время как весь окруающий его код в моей функции можно принять сложность за константу

Это сообщение отредактировал(а) ForceKeeper - 8.9.2011, 22:45
PM MAIL WWW   Вверх
Страницы: (3) [Все] 1 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1987 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.