Re[3]: замеры)
От: McQwerty Россия  
Дата: 26.07.23 13:40
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>Замерил на годболте через chrono: https://godbolt.org/z/dK4jsoxG3

S>На массиве с 90к элементов

Дополнил тест следующим вариантом (с предварительным resize и последующим erase для v_dest):
    {
        v_dest.clear();
        v_dest. resize (v_src. size ());
        const some_time v_start = std::chrono::system_clock::now();
        my_container::iterator d = v_dest. begin ();
        for (auto x : v_src)
        {
            * d = x >> 1;
            d += x & 1 ^ 1;
        }
        v_dest. erase (d, v_dest. end ());
        const some_time v_stop = std::chrono::system_clock::now();
        std::cout
            << "mcq: "
            << std::chrono::duration_cast<std::chrono::microseconds>(v_stop - v_start)
            << '\n'
        ;
    }


Выхлоп для тех-же 90'000 элементов:

Program returned: 0
for: 337us
mcq: 132us
for: 195us
algo: 181us
algo: 192us
for div: 415us
for div: 457us
algo div: 526us
algo div: 600us

Отредактировано 26.07.2023 13:44 McQwerty . Предыдущая версия .
Re[5]: Может я чего-то не понимаю....
От: bnk СССР http://unmanagedvisio.com/
Дата: 26.07.23 13:44
Оценка:
Здравствуйте, so5team, Вы писали:

bnk>>>
numbers_in.filter(x => x % 2 == 0).map(x => x / 2)


R>>Ну ты же жульничаешь — ты не положил числа в выходной массив. Ты предоставь законченное решение, тогда и сравним.


S>Это, кстати, от языка зависит. В некоторых языках map именно что создает новый контейнер:

S>
r = [3, 4, 5, 6, 7, 8].filter {|x| x % 2 == 0}.map {|x| x/2}


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


Ну я и имел в виду, что новый контейнер создается. В смысле, должно быть
numbers_out = numbers_in.filter(x => x % 2 == 0).map(x => x / 2)

Т.е. я нарочно опустил присваивание "numbers_out" для того чтобы результат казался чуть короче.
Про что rg45 и пишет что "сжульничал". У тебя его кстати тоже нет.
В "функциональном стиле" (т.е. с использованием std::ranges) синтаксический оверхед (тм) примерно такой же
Кстати почему-то у меня код с "transformed" и "filtered" не компилируется в таком виде как дан (говорит что нет такой буквы в C++ 20)
Я думаю если компилируемый код сделать там еще процентов 50 запросто прибавится на всяких приседаниях.
Re[6]: Может я чего-то не понимаю....
От: so5team https://stiffstream.com
Дата: 26.07.23 13:56
Оценка:
Здравствуйте, bnk, Вы писали:

S>>Это, кстати, от языка зависит. В некоторых языках map именно что создает новый контейнер:

S>>
r = [3, 4, 5, 6, 7, 8].filter {|x| x % 2 == 0}.map {|x| x/2}


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


bnk>Ну я и имел в виду, что новый контейнер создается. В смысле, должно быть

bnk>
numbers_out = numbers_in.filter(x => x % 2 == 0).map(x => x / 2)

bnk>Т.е. я нарочно опустил присваивание "numbers_out" для того чтобы результат казался чуть короче.
bnk>Про что rg45 и пишет что "сжульничал". У тебя его кстати тоже нет.

Вообще-то есть, r называется.

Но чтобы быть совсем уж близко к первоисточнику, то следовало бы написать:
numbers_out = numbers_in.filter {|x| x % 2 == 0}.map {|x| x/2}
Re[4]: замеры)
От: Sm0ke Россия ksi
Дата: 26.07.23 14:12
Оценка: +1
Здравствуйте, McQwerty, Вы писали:

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


S>>Замерил на годболте через chrono: https://godbolt.org/z/dK4jsoxG3

S>>На массиве с 90к элементов

MQ>Дополнил тест следующим вариантом (с предварительным resize и последующим erase для v_dest):

MQ>
MQ>    {
MQ>        v_dest.clear();
MQ>        v_dest. resize (v_src. size ()); // 1
MQ>        const some_time v_start = std::chrono::system_clock::now(); // 2
MQ>        my_container::iterator d = v_dest. begin ();
MQ>        for (auto x : v_src)
MQ>        {
MQ>            * d = x >> 1;
MQ>            d += x & 1 ^ 1;
MQ>        }
MQ>        v_dest. erase (d, v_dest. end ());
MQ>        const some_time v_stop = std::chrono::system_clock::now();
MQ>        std::cout
MQ>            << "mcq: "
MQ>            << std::chrono::duration_cast<std::chrono::microseconds>(v_stop - v_start)
MQ>            << '\n'
MQ>        ;
MQ>    }
MQ>


А если всё же поменять местами строчки 1 и 2 ?
Ведь остальные способы работают изначально с пустым dst

Пофиксил, и почистил от остатков неполного рефактора: https://godbolt.org/z/5E8sco1Pv

mcq: 266us
mcq: 113us
for: 108us
for: 107us
algo: 118us
algo: 152us
for div: 382us
for div: 318us
algo div: 481us
algo div: 474us
Отредактировано 26.07.2023 14:21 Sm0ke . Предыдущая версия .
Re[6]: Может я чего-то не понимаю....
От: rg45 СССР  
Дата: 26.07.23 14:48
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>Кстати почему-то у меня код с "transformed" и "filtered" не компилируется в таком виде как дан (говорит что нет такой буквы в C++ 20)


Ты имеешь в виду вот этот код? Так это же boost, а не std. Причем древняя как мир библиотека. Ну и по ссылке видно, что копмилируется и работает.
--
Re[3]: Может я чего-то не понимаю....
От: rg45 СССР  
Дата: 26.07.23 14:51
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Мне кажется, что подобную задачу в качестве примера я не первый раз встречаю. Все её решают почему-то через промежуточный буфер... Отсюда и вопрос.


Ну так кто-то один написал, а остальные копипастят. Та же самая история, почему во всех примерах с циклом используется постинкремент переменной цикла.
--
Re[7]: Может я чего-то не понимаю....
От: bnk СССР http://unmanagedvisio.com/
Дата: 26.07.23 15:08
Оценка:
Здравствуйте, rg45, Вы писали:

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


bnk>>Кстати почему-то у меня код с "transformed" и "filtered" не компилируется в таком виде как дан (говорит что нет такой буквы в C++ 20)


R>Ты имеешь в виду вот этот код? Так это же boost, а не std. Причем древняя как мир библиотека. Ну и по ссылке видно, что копмилируется и работает.


А, понял
Re[4]: Может я чего-то не понимаю....
От: B0FEE664  
Дата: 26.07.23 15:08
Оценка:
Здравствуйте, rg45, Вы писали:

R>И почему здесь так важен этот const, не объяснишь? Помимо правил хорошего стиля.

Потому, что ближе к функциональному программированию, меньше ошибок.
Вообще говоря я в последние время редко использую неконстантные локальные переменные. Неконстантные локальные переменные — это обычно переменные для ввода-вывода. Так получается, что все изменения состояний лежат в объектах, которые живут всё время от запуска до завершения программы. Либо, как уже написал, в вводе/выводе.
И каждый день — без права на ошибку...
Re[2]: Может я чего-то не понимаю....
От: B0FEE664  
Дата: 26.07.23 15:11
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>В одну строчку — это для любителей. А профессионал напишет полэкрана текста, как в приведенном тобой примере. Потому, что он профессионал.

У профессионала вообще не возникает таких ситуаций, когда в массиве лежат данные, которые следует выкинут.
И каждый день — без права на ошибку...
Re[5]: Может я чего-то не понимаю....
От: rg45 СССР  
Дата: 26.07.23 16:18
Оценка:
Здравствуйте, B0FEE664, Вы писали:

R>>И почему здесь так важен этот const, не объяснишь? Помимо правил хорошего стиля.

BFE>Потому, что ближе к функциональному программированию, меньше ошибок.
BFE>Вообще говоря я в последние время редко использую неконстантные локальные переменные. Неконстантные локальные переменные — это обычно переменные для ввода-вывода. Так получается, что все изменения состояний лежат в объектах, которые живут всё время от запуска до завершения программы. Либо, как уже написал, в вводе/выводе.

Тут я с тобой полностью согласен. Но мы тут затеяли длиной меряться, а в данном конкретном случае наличие или отсутствие const на результат никак не влияет и я пошел на сделку со своей совестью и выбросил его. Целых пять букв, шутка ли. А с пробелом все шесть!
--
Отредактировано 26.07.2023 16:21 rg45 . Предыдущая версия . Еще …
Отредактировано 26.07.2023 16:20 rg45 . Предыдущая версия .
Re[5]: замеры)
От: ArtDenis Россия  
Дата: 26.07.23 16:54
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>Пофиксил, и почистил от остатков неполного рефактора: https://godbolt.org/z/5E8sco1Pv


Мерить скорость на годболте — так себе идея
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[6]: замеры)
От: Sm0ke Россия ksi
Дата: 26.07.23 17:40
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Мерить скорость на годболте — так себе идея


Откомпилировал на ноутбуке, vs community 2022

mcq: 497us
mcq: 177us
for: 148us
for: 292us
algo: 239us
algo: 281us
for div: 1073us
for div: 1070us
algo div: 1788us
algo div: 1796us


mcq: 579us
mcq: 194us
for: 220us
for: 256us
algo: 219us
algo: 269us
for div: 1063us
for div: 1063us
algo div: 2196us
algo div: 2281us


Судя по разбросу мерить скорость на винде тоже не айс :Р
Так на чём мерить?
Re[7]: замеры)
От: pilgrim_ Россия  
Дата: 26.07.23 18:03
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>Судя по разбросу мерить скорость на винде тоже не айс :Р

S>Так на чём мерить?

А если вначале сделать "разогрев"?
Вставить перед замерами что-то типа:

    {
        for (auto it : v_src) {
            v_dest.push_back(it);
        }
    }


Похоже что после 1-й пробежки по памяти векторов данные остаются в кэше процессора и последующие обращения к памяти идут существенно шустрее.

Тут s_count=80'000.
https://godbolt.org/z/fK6boY8qn

mcq: 139us
mcq: 145us
for: 107us
for: 107us
algo: 127us
algo: 132us
for div: 359us
for div: 324us
algo div: 478us
algo div: 495us

Re[7]: замеры)
От: ArtDenis Россия  
Дата: 27.07.23 05:53
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>Судя по разбросу мерить скорость на винде тоже не айс :Р

S>Так на чём мерить?

Как тут уже сказали, перед замером надо "прогревать" процессор. ОС выставит для него максимальную частоту и переключит твой поток на мощное ядро. Затем, один и тот же тест надо прогонять много раз, каждый раз считать время, а затем брать например, медианное значение. Но я бы не заморачивался и использовал какую-нибудь готовую либу для бенчмаркинга. В неё это всё будет уже встроено
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Отредактировано 27.07.2023 12:54 ArtDenis . Предыдущая версия .
Re[8]: замеры)
От: Sm0ke Россия ksi
Дата: 27.07.23 12:45
Оценка:
Здравствуйте, pilgrim_, Вы писали:

_>Тут s_count=80'000.

_>https://godbolt.org/z/fK6boY8qn

_>

_>mcq: 139us
_>mcq: 145us
_>for: 107us
_>for: 107us
_>algo: 127us
_>algo: 132us
_>for div: 359us
_>for div: 324us
_>algo div: 478us
_>algo div: 495us


Мне интересно почему for + div() медленнее, чем for?
Ведь казалось бы мы делаем две операции (деление и остаток) за одну инструкцию. Но видимо в std накосячили и что-то пошло не так. Или вообще что случилось?
Re[9]: замеры)
От: sergii.p  
Дата: 27.07.23 14:42
Оценка: +1
Здравствуйте, Sm0ke, Вы писали:

S>Мне интересно почему for + div() медленнее, чем for?

S>Ведь казалось бы мы делаем две операции (деление и остаток) за одну инструкцию. Но видимо в std накосячили и что-то пошло не так. Или вообще что случилось?

сделал маленький рефакторинг https://godbolt.org/z/1aW4zzvoY
Получил

mcq: 52ms
for_loop: 45ms
algo: 45ms
for_loop_div: 252ms
algo_div: 345ms


с std::div реально какая-то шляпа. Меняю на my_div — все значения в пределах погрешности.

в итоге, если отбросить аномалию с std::div, то можно сказать, что результаты примерно одинаковые
Re[9]: замеры)
От: pilgrim_ Россия  
Дата: 27.07.23 14:50
Оценка: +1
Здравствуйте, Sm0ke, Вы писали:

S>Мне интересно почему for + div() медленнее, чем for?

S>Ведь казалось бы мы делаем две операции (деление и остаток) за одну инструкцию. Но видимо в std накосячили и что-то пошло не так. Или вообще что случилось?

Похоже что из-за отсутствия инлайна std::div (выполняется call)

Добавил mydiv и mydiv_noinline (эмуляция вызова std::div):

std::div_t mydiv(int x, int y)
{
    return { x / y, x % y };
}

std::div_t __attribute__ ((noinline)) mydiv_noinline(int x, int y)
{
    return { x / y, x % y };
}


Судя по asm смартовый оптимизатор выполняет idiv — та самая одна инструкция (частное в rax, остаток в rdx), а при инлайне mydiv заменяет её код на test (AND) и сдвиг (как в варианте mcq, да и в for такой же код генерится)

mydiv_noinline(int, int):
        mov     eax, edi
        cdq
        idiv    esi
        sal     rdx, 32
        or      rax, rdx
        ret


https://godbolt.org/z/a98Wv3bTM

for mydiv_noinline: 670us
for mydiv_noinline: 493us
for mydiv: 130us
for mydiv: 129us
mcq: 140us
mcq: 148us
for: 159us
for: 133us
algo: 264us
algo: 265us
for div: 529us
for div: 645us
algo div: 1039us
algo div: 765us

Отредактировано 27.07.2023 14:54 pilgrim_ . Предыдущая версия .
Re[4]: Может я чего-то не понимаю....
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 28.07.23 18:55
Оценка:
Здравствуйте, rg45, Вы писали:

BFE>>Мне кажется, что подобную задачу в качестве примера я не первый раз встречаю. Все её решают почему-то через промежуточный буфер... Отсюда и вопрос.


R>Ну так кто-то один написал, а остальные копипастят. Та же самая история, почему во всех примерах с циклом используется постинкремент переменной цикла.



Я всегда префиксный инкремент использую, для любых типов. Привычка. Впрочем, я сознательно себя к этому приучал в своё время
Маньяк Робокряк колесит по городу
Re[3]: Может я чего-то не понимаю....
От: T4r4sB Россия  
Дата: 30.07.23 08:10
Оценка: :)
Здравствуйте, ArtDenis, Вы писали:

AD>Для плюсов — идеальный вариант, т.к. другие или корявые или сложные


Слишком простой код, нет клёвой функциональщины. Код сразу выдаёт старпёра, с которыми и смузи выпить не о чем, и на одном электросамокате не покататься.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[4]: Может я чего-то не понимаю....
От: ArtDenis Россия  
Дата: 30.07.23 09:01
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Слишком простой код, нет клёвой функциональщины. Код сразу выдаёт старпёра, с которыми и смузи выпить не о чем, и на одном электросамокате не покататься.


Если бы плюсы позволяли удобную и понятную функциональщину, я бы предпочёл её
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.