Re[12]: C# - from indians by indians
От: MT-Wizard Украина  
Дата: 02.06.15 07:07
Оценка:
Здравствуйте, gandjustas, Вы писали:

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

G>Не знаю как на Java, а на .NET есть прекрасный пример — компилятор C# (Roslyn). Мало того, что он на .NET, так написан еще и в функциональном стиле, он генерирует кучу мелких объектов и создает изрядный gc pressure. Тем не менее работает быстрее старого csc компилятора, написанного на C++. В интернетах можно найти докалды как оптимизировали Roslyn. Там вообще не космос, постигнуть может практически кто угодно. И никакого unamanaged не надо. А с unmanaged можно писать на C# как на С (c соответствующими скоростями). Разве что математика не такая быстрая получается, но это вроде новым джитом исправляется.

Просто прекрасный пример
Только что полазил по отчётам производительности — лучшее что там есть это на 14% медленнее старого компилера (который и не трогают давно) на одном конкретном тесте. Пустите столько же ресурсов в него — и шарп его не догонит ещё лет 200
А ти, москалику, вже приїхав (с)
Отредактировано 02.06.2015 7:11 MT-Wizard . Предыдущая версия .
Re[13]: C# - from indians by indians
От: Sinix  
Дата: 02.06.15 07:41
Оценка:
Здравствуйте, MT-Wizard, Вы писали:

MW>Просто прекрасный пример

MW>Только что полазил по отчётам производительности — лучшее что там есть это на 14% медленнее старого компилера (который и не трогают давно) на одном конкретном тесте. Пустите столько же ресурсов в него — и шарп его не догонит ещё лет 200

Они закрытые вроде были, тынц. Что-то поменялось?
Re[19]: C# - from indians by indians
От: Aртём Австралия жж
Дата: 02.06.15 08:15
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>
EP>using namespace std;
// Bad practice?

EP>struct Complex
EP>{
EP>    double re = 0., im = 0.;
EP>};

EP>Complex operator+(Complex x, Complex y)
// Copy constructors ( Complex const &x, )
EP>{
EP>    return {x.re + y.re, x.im + y.im};
EP>}

EP>Complex operator*(Complex x, Complex y)
EP>{
EP>    return {x.re*y.re - x.im*y.im, x.re*y.im + x.im*y.re};
EP>}

EP>Complex random_complex()
EP>{
// std::rand:   #define RAND_MAX /*implementation defined*/. What's the magic number 1000?
EP>    return {rand() / 1000. - 1000., rand() / 1000. - 1000.};
EP>}

EP>int main()
EP>{
EP>    constexpr auto N = 1u << 24;
// Magic number?
EP>



Как там насчёт stack trace в лог при исключении?

EP>Простоту работы со struct-like вещами, а конкретнее — скорость выполнения и удобство кода.


EP>P.S. На Java можно писать быстрый код, но если выходить за рамки каких-то примитивнейших случаев (типа сортировки массива int'ов)

Нужно сделать то же самое, но с объектами на Java- и сравнить производительность.

EP> — то приходится работать против языка, а не вместе с ним — нужно отказываться от GC и даже классов,

Для начала находить узкие места профилировщиком.
Re[20]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 02.06.15 08:37
Оценка:
Здравствуйте, Aртём, Вы писали:

Aё>Как там насчёт stack trace в лог


В ISO C++ такого нет, но есть платформенно-зависимые варианты.

Aё>при исключении?


А зачем stack trace при исключении? Я понимаю если там что-то типа assertion failure — то да, stack trace полезен, правда в таких случаях лучше как можно быстрее пристрелить программу/dump'ить core/присоединить отладчик, а не пытаться раскручивать стэк.

Да и при чём тут исключения в этом конкретном примере? Тут они возможны разве что при первоначальной аллокации

EP>>Простоту работы со struct-like вещами, а конкретнее — скорость выполнения и удобство кода.

EP>>P.S. На Java можно писать быстрый код, но если выходить за рамки каких-то примитивнейших случаев (типа сортировки массива int'ов)
Aё>Нужно сделать то же самое, но с объектами на Java- и сравнить производительность.

Сделай С Java'овскими объектами будет медленнее в несколько раз, а то и на порядок.

EP>> — то приходится работать против языка, а не вместе с ним — нужно отказываться от GC и даже классов,

Aё>Для начала находить узкие места профилировщиком.

А ещё лучше знать как оно работает внутри, представлять где и какие издержки получаются — тогда можно принимать оптимальные решения на более ранних этапах.
Re[20]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 02.06.15 08:54
Оценка: +2 :)
Здравствуйте, Aртём, Вы писали:

Сразу не увидел твои комментарии.

EP>>using namespace std;

Aё>// Bad practice?

Нет, не bad — для небольших примеров самое то

EP>>Complex operator+(Complex x, Complex y)

Aё>// Copy constructors ( Complex const &x, )

Для небольших объектов не проблема (а даже наоборот рекомендация), тем более на x64, тем более при инлайнинге. Можешь сравнить ASM вывод, он скорей всего будет идентичным

EP>>Complex random_complex()

EP>>{
Aё>// std::rand: #define RAND_MAX /*implementation defined*/. What's the magic number 1000?
EP>> return {rand() / 1000. — 1000., rand() / 1000. — 1000.};
EP>>}

Для этого примера совершенно не важно. Ты ещё скажи что srand'а нет, или что надо использовать <random>

EP>> constexpr auto N = 1u << 24;

Aё>// Magic number?

Это Да, N — это magic number
Re[18]: C# - from indians by indians
От: Sinclair Россия https://github.com/evilguest/
Дата: 02.06.15 09:42
Оценка:
Здравствуйте, mik1, Вы писали:

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


S>>Я по-прежнему жду убедительного примера про умножение комплексных массивов на Java. Можете продемонстрировать чудеса владения sun.misc.Unsafe, если это поможет.


M>Вас не затруднит дать ссылку на аналогичный код на плюсах ? Это чтобы было с чем сравнивать.

M>Для чистоты экперимента — без нестандартных зависимостей, чтобы мне, не работавшему с плюсами много веков, не так сложно было собирать и запускать этот код
Тупой наивный код:
#include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <numeric>

typedef std::complex<double> complex;
typedef std::vector<complex> chunk;

// вот начинается наша реализация векторной арифметики
chunk& operator*=(chunk& lhs, const chunk& rhs)
{
    for (size_t k = 0; k < lhs.size(); k++)
        lhs[k] *= rhs[k];
    return lhs;
}

chunk operator*(const chunk& lhs, const chunk& rhs)
{
    chunk res(lhs);
    return res *= rhs;
}
// а вот она закончилась.

int main()
{
    std::cout << std::fixed << std::setprecision(1);

    auto i = complex(0., 1.); // определили корень из минус единицы

    auto const s = 40000;
    auto data = std::vector<complex>(s, i); // создали массив размером в s элементов из i

    auto data2 = data * data; // возвели его в квадрат при помощи только что навелосипеженного оператора умножения

    auto sum = std::accumulate(data2.begin(), data2.end(), complex(0.)); // посчитали сумму массива
    std::cout << "sum(data2[]) = " << sum << '\n'; // чтобы проверить, что она равна -s.
    

}

M>Попутно хотелось бы определить, по каким критериям мы сравниваем.
Во-первых — по читаемости кода. Код читается чаще, чем пишется, поэтому арифметике лучше выглядеть как арифметике.
Во-вторых — по производительности. Желательно, чтобы в этом простом тесте джава-код выполнялся хотя бы в пределах 2х от времени, потраченного С++ кодом.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 02.06.15 10:01
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>typedef std::complex<double> complex;


Я думал изначально речь шла о том чтобы показать как реализуется complex, а не использовать стандартный. А то так можно дойти и до использования библиотек типа Eigen со своим Embeded Domain Specific Language, и оптимизатором выражений в compile-time.

S>Во-первых — по читаемости кода. Код читается чаще, чем пишется, поэтому арифметике лучше выглядеть как арифметике.


Вообще, отсутствие структур в Java сказывается далеко не только на арифметике и подобном — оно сказывается практически на всём. Любой struct-like под-объект это уже penalty.

Кстати, в C# хоть и есть структуры — ими не всегда удобно пользоваться — например когда есть class, хотя в одном из контекстов он мог бы быть и struct. Или даже вот такой пример
Автор: Evgeny.Panasyuk
Дата: 11.10.14
.

S>Во-вторых — по производительности. Желательно, чтобы в этом простом тесте джава-код выполнялся хотя бы в пределах 2х от времени, потраченного С++ кодом.


Для пущего эффекта элементы массива нужно как-нибудь перетасовать.
Re[21]: C# - from indians by indians
От: Aртём Австралия жж
Дата: 02.06.15 10:25
Оценка: :))
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Нет, не bad — для небольших примеров самое то

Небольшой пример простит бэд практис?

EP>>>Complex operator+(Complex x, Complex y)

Aё>>// Copy constructors ( Complex const &x, )

EP>Для небольших объектов не проблема (а даже наоборот рекомендация), тем более на x64, тем более при инлайнинге. Можешь сравнить ASM вывод, он скорей всего будет идентичным

Я уже не знаток плюсов- просто выделил, что сразу бросается в глаза Дальше уже Ваши домыслы "скорей всего" "тем более" и т.п.


EP>Для этого примера совершенно не важно. Ты ещё скажи что srand'а нет, или что надо использовать <random>

Обычно вычисления производят ради какого-то смысла.

EP>>> constexpr auto N = 1u << 24;

Aё>>// Magic number?

EP>Это Да, N — это magic number

2^24 можно было записать числом.

PS Суммируя- векторные инструкции и размер кода для попадания в кэш CPU почему-то знатоки C++ не упомянули, вразумительный ответ на вопрос про обработчик исключения с стек трейс в лог не привели. Зато голословные утверждения про скорость C++ с ложным примером.
Re[22]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 02.06.15 11:06
Оценка: +2
Здравствуйте, Aртём, Вы писали:

EP>>Нет, не bad — для небольших примеров самое то

Aё>Небольшой пример простит бэд практис?

Нет, ты не понял. Что называется "гуд/бэд практис" зависит от характера задачи.
То что для больших проектов может быть "бэд практис", для небольших примеров может быть вполне нормальным.

EP>>>>Complex operator+(Complex x, Complex y)

Aё>>>// Copy constructors ( Complex const &x, )
EP>>Для небольших объектов не проблема (а даже наоборот рекомендация), тем более на x64, тем более при инлайнинге. Можешь сравнить ASM вывод, он скорей всего будет идентичным
Aё>Я уже не знаток плюсов- просто выделил, что сразу бросается в глаза

О том и речь — ты не знаешь о чём говоришь.

Aё>Дальше уже Ваши домыслы "скорей всего" "тем более" и т.п.


Это не домыслы, а опыт. Если ты в этом сомневаешься — то открой ссылку с Live Demo, добавь ключик -S и сравни ASM для обоих вариантов

EP>>Для этого примера совершенно не важно. Ты ещё скажи что srand'а нет, или что надо использовать <random>

Aё>Обычно вычисления производят ради какого-то смысла.

Опять мимо. Если требуется сравнить скорость двух вариантов hadamard product, то можно обойтись и случайными данными, главное не денормализированными.

EP>>>> constexpr auto N = 1u << 24;

Aё>>>// Magic number?
EP>>Это Да, N — это magic number
Aё>2^24 можно было записать числом.

Зачем?

Aё>PS Суммируя- векторные инструкции


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

Да даже если в Java-версии с Complex объектами будет векторизация, она всё равно будет медленнее C++ версии без векторизации — из-за плохого паттерна доступа к памяти — сути примера это никак не поменяет.

Aё>и размер кода для попадания в кэш CPU почему-то знатоки C++ не упомянули,


А зачем его упоминать? Думаешь код перемножения массивов не уместится в intruction cache?

Aё>вразумительный ответ на вопрос про обработчик исключения с стек трейс в лог не привели.


Это вообще какой-то левый запрос совершенно не относящийся к теме

Aё>Зато голословные утверждения про скорость C++ с ложным примером.


Твоё мнение обоснованно и очень интересно
Re[23]: C# - from indians by indians
От: Aртём Австралия жж
Дата: 02.06.15 11:22
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Нет, ты не понял. Что называется "гуд/бэд практис" зависит от характера задачи.

EP>То что для больших проектов может быть "бэд практис", для небольших примеров может быть вполне нормальным.
Небольшой пример стерпит, ну я про то и написал.

EP>>>>>Complex operator+(Complex x, Complex y)

Aё>>>>// Copy constructors ( Complex const &x, )
EP>>>Для небольших объектов не проблема (а даже наоборот рекомендация), тем более на x64, тем более при инлайнинге. Можешь сравнить ASM вывод, он скорей всего будет идентичным
Aё>>Я уже не знаток плюсов- просто выделил, что сразу бросается в глаза

EP>О том и речь — ты не знаешь о чём говоришь.

Переход на личности засчитан

Aё>>Дальше уже Ваши домыслы "скорей всего" "тем более" и т.п.


EP>Это не домыслы, а опыт. Если ты в этом сомневаешься — то открой ссылку с Live Demo, добавь ключик -S и сравни ASM для обоих вариантов

Не удивлюсь, что опыта именно в C++ у меня поболее Вашего окажется

EP>Для векторизации есть готовые библиотеки и опции компилятора. В данном конкретном примере в первую очередь нужно распараллеливание, а не векторизация.

Что?!

EP>Да даже если в Java-версии с Complex объектами будет векторизация, она всё равно будет медленнее C++ версии без векторизации — из-за плохого паттерна доступа к памяти — сути примера это никак не поменяет.

Вы так ничего и не поняли. А ведь я указывал парой сообщений выше- что Python с NumPy порвёт ваш плюснутый код, как тузик грелку. Потому что узкие места ускоряются через использование заточенной библиотеки. А вот в качестве "клея" С++ — далеко не лучший вариант, и Вы не хотите этой очевидной вещи замечать.

Aё>>и размер кода для попадания в кэш CPU почему-то знатоки C++ не упомянули,

EP>А зачем его упоминать? Думаешь код перемножения массивов не уместится в intruction cache?
Думаю, что реальные задачи сложнее Вашего примера, а шаблоны C++ имеют дурную репутацию разбухания кода.

Aё>>вразумительный ответ на вопрос про обработчик исключения с стек трейс в лог не привели.

EP>Это вообще какой-то левый запрос совершенно не относящийся к теме
Если сравнивать абстрактного коня в вакууме- не относящийся. А если критическая отказоустойчивая система 24/7 без потери производительности от фрагментации кучи и при этом быстрая- то Java со специализированными библиотеками оказывается более разумным выбором.
Re[24]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 02.06.15 11:55
Оценка: +1 :)
Здравствуйте, Aртём, Вы писали:

EP>>Нет, ты не понял. Что называется "гуд/бэд практис" зависит от характера задачи.

EP>>То что для больших проектов может быть "бэд практис", для небольших примеров может быть вполне нормальным.
Aё>Небольшой пример стерпит, ну я про то и написал.

Нет, дело не в том что "стерпит".

Ок, другой пример — глобальные объекты для многих проектов это "бэд практис", для некоторых же это вполне стандартное решение — типа микроконтроллеров
Практически у каждой языковой фичи есть вполне хорошие применения, даже несмотря на то что в некоторых контекстах это считается "бэд практис".

EP>>>>>>Complex operator+(Complex x, Complex y)

Aё>>>>>// Copy constructors ( Complex const &x, )
EP>>>>Для небольших объектов не проблема (а даже наоборот рекомендация), тем более на x64, тем более при инлайнинге. Можешь сравнить ASM вывод, он скорей всего будет идентичным
Aё>>>Я уже не знаток плюсов- просто выделил, что сразу бросается в глаза
EP>>О том и речь — ты не знаешь о чём говоришь.
Aё>Переход на личности засчитан

А где переход на личности? Ты ведь действительно не знаешь что там внутри происходит, разве нет? При этом делаешь какие-то нелепые попытки придраться.
ASM уже посмотрел?

Aё>>>Дальше уже Ваши домыслы "скорей всего" "тем более" и т.п.

EP>>Это не домыслы, а опыт. Если ты в этом сомневаешься — то открой ссылку с Live Demo, добавь ключик -S и сравни ASM для обоих вариантов
Aё>Не удивлюсь, что опыта именно в C++ у меня поболее Вашего окажется

Даже если и больше по продолжительности, то по качеству — судя по всему нет

EP>>Для векторизации есть готовые библиотеки и опции компилятора. В данном конкретном примере в первую очередь нужно распараллеливание, а не векторизация.

Aё>Что?!

Что не понятно? Распараллеливание даст больший эффект нежели векторизация.

EP>>Да даже если в Java-версии с Complex объектами будет векторизация, она всё равно будет медленнее C++ версии без векторизации — из-за плохого паттерна доступа к памяти — сути примера это никак не поменяет.

Aё>Вы так ничего и не поняли.

Куда уж там.

Aё>А ведь я указывал парой сообщений выше- что Python с NumPy порвёт ваш плюснутый код, как тузик грелку.


По какому критерию?

Aё>Потому что узкие места ускоряются через использование заточенной библиотеки.


Которая далеко не всегда существует.

Aё>А вот в качестве "клея" С++ — далеко не лучший вариант,


Аргументы?

Aё>и Вы не хотите этой очевидной вещи замечать.


Вещь совершенно не очевидная.

Aё>>>и размер кода для попадания в кэш CPU почему-то знатоки C++ не упомянули,

EP>>А зачем его упоминать? Думаешь код перемножения массивов не уместится в intruction cache?
Aё>Думаю, что реальные задачи сложнее Вашего примера, а шаблоны C++ имеют дурную репутацию разбухания кода.

В реальных задачах там где нужно используется динамический полиморфизм вместо статического, причём обычно где-то наверху. Это на порядки проще чем "работа вопреки языку" (как в тех случаях когда нужна скорость на Java).

Aё>>>вразумительный ответ на вопрос про обработчик исключения с стек трейс в лог не привели.

EP>>Это вообще какой-то левый запрос совершенно не относящийся к теме
Aё>Если сравнивать абстрактного коня в вакууме- не относящийся. А если критическая отказоустойчивая система 24/7 без потери производительности от фрагментации кучи и при этом быстрая- то Java со специализированными библиотеками оказывается более разумным выбором.

Даже если допустить что это так — того факта что в Java нет структур, и связанными с этим тормозами или танцами с ручной нарезкой массивов байт на структуры, или факта того что в нагруженных приложениях частенько отказываются от GC — это никак не отменяет.
Re[25]: C# - from indians by indians
От: Sinix  
Дата: 02.06.15 12:12
Оценка: 1 (1) +2 :))
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Нет, дело не в том что "стерпит".

Сорри, но вы кормите тролля. Тема конечно интересная, но толку от этого не будет.
Зато наездов, перескоков на исключения и сторонние библиотеки типа Colt/NumPy будет выше крыши.

UPD Надо же, с NumPy угадал
Re[20]: C# - from indians by indians
От: Sinclair Россия https://github.com/evilguest/
Дата: 02.06.15 12:12
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Я думал изначально речь шла о том чтобы показать как реализуется complex, а не использовать стандартный. А то так можно дойти и до использования библиотек типа Eigen со своим Embeded Domain Specific Language, и оптимизатором выражений в compile-time.
На мой взгляд речь, в основном, о том, как дописать арифметику последовательностей на основе value-types.
Важно не то, самописаные там комплексы или нет. Важно то, что мы работаем не с byte[], а с complex[], и имеем нулевой penalty по памяти.
А с учётом инлайнинга мы ещё и можем рассчитывать на некоторый бонус в смысле отсутствия penalty на абстрактность операций умножения.
Не глядя в дизассемблер, я предположу, что более-менее любой компилятор с++, выпущенный после 2000 года, не оставит от строчки data3 = data1 * data2 ни одного call. Будет примерно такая же double арифметика, которую бы я выписал руками в виде
data3_as_doubles[2*i] = data1_as_doubles[2*i]*data2_as_doubles[2*i]-data1_as_doubles[2*i+1]*data2_as_doubles[2*i+1];
data3_as_doubles[2*i+1] = data1_as_doubles[2*i]*data2_as_doubles[2*i+1]+data1_as_doubles[2*i+1]*data2_as_doubles[2*i];


EP>Вообще, отсутствие структур в Java сказывается далеко не только на арифметике и подобном — оно сказывается практически на всём. Любой struct-like под-объект это уже penalty.

Просто далеко не везде это так важно.

EP>Кстати, в C# хоть и есть структуры — ими не всегда удобно пользоваться — например когда есть class, хотя в одном из контекстов он мог бы быть и struct.

Для вашей синтетической задачи есть не менее синтетическое решение в видe struct Triangle : IShape. В реальной жизни вы вспотеете искать такие примеры, где нужно наследование реализации для value типов.

EP>Для пущего эффекта элементы массива нужно как-нибудь перетасовать.

Это вовсе необязательно. Давайте сначала посмотрим на код, который нам предложат матёрые спецы по number-crunching в Java.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[21]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 02.06.15 12:33
Оценка:
Здравствуйте, Sinclair, Вы писали:

EP>>Я думал изначально речь шла о том чтобы показать как реализуется complex, а не использовать стандартный. А то так можно дойти и до использования библиотек типа Eigen со своим Embeded Domain Specific Language, и оптимизатором выражений в compile-time.

S>На мой взгляд речь, в основном, о том, как дописать арифметику последовательностей на основе value-types.
S>Важно не то, самописаные там комплексы или нет. Важно то, что мы работаем не с byte[], а с complex[], и имеем нулевой penalty по памяти.

Да, согласен. Изначально подумал что с самописным complex будет нагляднее.

S>А с учётом инлайнинга мы ещё и можем рассчитывать на некоторый бонус в смысле отсутствия penalty на абстрактность операций умножения.

S>Не глядя в дизассемблер, я предположу, что более-менее любой компилятор с++, выпущенный после 2000 года, не оставит от строчки data3 = data1 * data2 ни одного call. Будет примерно такая же double арифметика, которую бы я выписал руками в виде
S>
S>data3_as_doubles[2*i] = data1_as_doubles[2*i]*data2_as_doubles[2*i]-data1_as_doubles[2*i+1]*data2_as_doubles[2*i+1];
S>data3_as_doubles[2*i+1] = data1_as_doubles[2*i]*data2_as_doubles[2*i+1]+data1_as_doubles[2*i+1]*data2_as_doubles[2*i];
S>


Да, там конечно же всё хорошо заинлайнится, и не будет уступать "ручной" версии.

Кстати, библиотека типа Eigen реализует дополнительные оптимизации — например конструкция вида
Vector result = v1 * v2 * v3 * v4;
Развернётся в один цикл сразу по всем векторам.

EP>>Вообще, отсутствие структур в Java сказывается далеко не только на арифметике и подобном — оно сказывается практически на всём. Любой struct-like под-объект это уже penalty.

S>Просто далеко не везде это так важно.

Не везде, но всё же бывает важно в том числе и для вещей без всякой арифметики.

EP>>Для пущего эффекта элементы массива нужно как-нибудь перетасовать.

S>Это вовсе необязательно. Давайте сначала посмотрим на код, который нам предложат матёрые спецы по number-crunching в Java.

Это может ухудшить показатели Java кода в разы, так как по умолчанию compacting GC выделяет память последовательно. Перемешав указатели в массиве — уже не получится последовательный обход памяти.
Re[19]: C# - from indians by indians
От: mik1  
Дата: 02.06.15 16:13
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

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


M>>Вас не затруднит дать ссылку на аналогичный код на плюсах ? Это чтобы было с чем сравнивать.

M>>Для чистоты экперимента — без нестандартных зависимостей, чтобы мне, не работавшему с плюсами много веков, не так сложно было собирать и запускать этот код

EP>Пока ты редактировал сообщение, я уже сделал в таком виде Убрать зависимость boost конечно не сложно, но давай уже сделаем это после того как увидим Java версию.


M>>Попутно хотелось бы определить, по каким критериям мы сравниваем.


EP>Простоту работы со struct-like вещами, а конкретнее — скорость выполнения и удобство кода.


EP>P.S. На Java можно писать быстрый код, но если выходить за рамки каких-то примитивнейших случаев (типа сортировки массива int'ов) — то приходится работать против языка, а не вместе с ним — нужно отказываться от GC и даже классов, и нарезать структуры вручную по массивам байт — по сути это уровень даже ниже чем в языке C.


Давай пока что так, требует JMH, которому я доверяю тестировать производительность:

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Thread)
@Fork(1)
@Warmup(iterations = 10)
@Measurement(iterations = 10)
@BenchmarkMode(Mode.AverageTime)
public class ComplexTest2 {

    private static class ComplexFlyweight
    {
        private final double[] ar;

        public ComplexFlyweight(double[] ar) {
            this.ar = ar;
        }

        public double re( int i )
        {
            return ar[ i *2 ];
        }

        public double im( int i )
        {
            return ar[ i * 2 + 1 ];
        }

        public void re( int i, double v )
        {
            ar[i * 2] = v;
        }

        public void im( int i, double v )
        {
            ar[i * 2+1] = v;
        }
    }

    private static final int N = 1 << 24;

    private double[] u_ar = new double[ N * 2 ];
    private double[] v_ar = new double[ N * 2 ];
    private ComplexFlyweight u = new ComplexFlyweight( u_ar );
    private ComplexFlyweight v = new ComplexFlyweight( v_ar );

    @Setup
    public void setup()
    {
        for ( int i = 0; i < v_ar.length; ++i ) {
            u_ar[i] = ThreadLocalRandom.current().nextInt( 32767 ) / 1000. - 1000.;
            v_ar[i] = ThreadLocalRandom.current().nextInt( 32767 ) / 1000. - 1000.;
        }
    }

    @Benchmark
    public double testVectorMult()
    {

        for ( int i = 0; i < u_ar.length / 2; ++i ) {
            v.re(i, u.re(i) * v.re(i) - u.im(i) * v.im(i) );
            v.im(i, u.re(i)*v.im(i) + u.im(i)*v.re(i));
        }
        return u.re( 0 );
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(".*" + ComplexTest2.class.getSimpleName() + ".*")
                .build();

        new Runner(opt).run();
    }
}


rand() пришлось эмулировать (правильно?), для доступа к полям flyweight написал.


Сейчас времени устанавливать плюсовое окружение нет, завтра посмотрю, за сколько твоя версия у меня отрабатывает.
# Warmup: 10 iterations, 1 s each
# Measurement: 10 iterations, 1 s each
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: info.javaperformance.gccheck.ComplexTest2.testVectorMult

# Run progress: 0.00% complete, ETA 00:00:20
# Fork: 1 of 1
# Warmup Iteration   1: 60.429 ms/op
# Warmup Iteration   2: 58.038 ms/op
# Warmup Iteration   3: 58.117 ms/op
# Warmup Iteration   4: 57.762 ms/op
# Warmup Iteration   5: 57.733 ms/op
# Warmup Iteration   6: 57.863 ms/op
# Warmup Iteration   7: 57.885 ms/op
# Warmup Iteration   8: 57.698 ms/op
# Warmup Iteration   9: 57.609 ms/op
# Warmup Iteration  10: 57.925 ms/op
Iteration   1: 57.761 ms/op
Iteration   2: 57.685 ms/op
Iteration   3: 57.779 ms/op
Iteration   4: 57.570 ms/op
Iteration   5: 57.640 ms/op
Iteration   6: 57.743 ms/op
Iteration   7: 57.762 ms/op
Iteration   8: 57.696 ms/op
Iteration   9: 57.668 ms/op
Iteration  10: 57.756 ms/op


Result: 57.706 ±(99.9%) 0.101 ms/op [Average]
  Statistics: (min, avg, max) = (57.570, 57.706, 57.779), stdev = 0.067
  Confidence interval (99.9%): [57.605, 57.807]


# Run complete. Total time: 00:00:25

Benchmark                            Mode  Samples   Score  Score error  Units
i.j.g.ComplexTest2.testVectorMult    avgt       10  57.706        0.101  ms/op

Конкретно здесь классов нужно избегать из-за ненужной нагрузки на GC.
Re[20]: C# - from indians by indians
От: mik1  
Дата: 02.06.15 16:26
Оценка:
Здравствуйте, mik1, Вы писали:

M>Здравствуйте, Evgeny.Panasyuk, Вы писали:


EP>>Пока ты редактировал сообщение, я уже сделал в таком виде Убрать зависимость boost конечно не сложно, но давай уже сделаем это после того как увидим Java версию.


Да, кстати буст хорошо бы убрать из примера (как обещано).

M>>>Попутно хотелось бы определить, по каким критериям мы сравниваем.


EP>>Простоту работы со struct-like вещами, а конкретнее — скорость выполнения и удобство кода.


Сложно? Если разные типы намешаны — возьму direct ByteBuffer.

EP>>P.S. На Java можно писать быстрый код, но если выходить за рамки каких-то примитивнейших случаев (типа сортировки массива int'ов) — то приходится работать против языка, а не вместе с ним — нужно отказываться от GC и даже классов, и нарезать структуры вручную по массивам байт — по сути это уровень даже ниже чем в языке C.


Надо бы графы пообходить... и посмотреть, как там с управлением памятью
Re[20]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 02.06.15 16:53
Оценка:
Здравствуйте, mik1, Вы писали:

M>Давай пока что так, требует JMH, которому я доверяю тестировать производительность:

M>
M>        public double re( int i )
M>        {
M>            return ar[ i *2 ];
M>        }
M>        public double im( int i )
M>        {
M>            return ar[ i * 2 + 1 ];
M>        }
M>    ...
M>    private static final int N = 1 << 24;

M>    private double[] u_ar = new double[ N * 2 ];
M>    private double[] v_ar = new double[ N * 2 ];
M>    private ComplexFlyweight u = new ComplexFlyweight( u_ar );
M>    private ComplexFlyweight v = new ComplexFlyweight( v_ar );

M>    ...
M>    @Benchmark
M>    public double testVectorMult()
M>    {

M>        for ( int i = 0; i < u_ar.length / 2; ++i ) {
M>            v.re(i, u.re(i) * v.re(i) - u.im(i) * v.im(i) );
M>            v.im(i, u.re(i)*v.im(i) + u.im(i)*v.re(i));
M>        }
M>        return u.re( 0 );
M>    }
M>


Здесь используется не класс типа Complex, а класс типа ComplexArray.
Собственно об этом и была речь — простейшая абстракция Complex не совместима с производительностью. То есть нельзя просто отдельно создать класс Complex и положить его в отдельный стандартный массив, в стандартную deque, в стандартную priority_queue и т.п. — их приходится вручную скрещивать.
Причём если взять структуру чуть-чуть посложнее, типа {double, float, int} — то всё, приплыли капитально.

M>Конкретно здесь классов нужно избегать из-за ненужной нагрузки на GC.


В этом примере (перемножение массивов объектов Complex) — тормоза на Java будут даже без учёта GC.
Отредактировано 02.06.2015 17:09 Evgeny.Panasyuk . Предыдущая версия .
Re[21]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 02.06.15 17:40
Оценка:
Здравствуйте, mik1, Вы писали:

EP>>>Пока ты редактировал сообщение, я уже сделал в таком виде Убрать зависимость boost конечно не сложно, но давай уже сделаем это после того как увидим Java версию.

M>Да, кстати буст хорошо бы убрать из примера (как обещано).

LIVE DEMO on Coliru
  Code
#include <algorithm>
#include <iterator>
#include <iostream>
#include <numeric>
#include <cstdlib>
#include <vector>
#include <chrono>
using namespace std;

struct Complex
{
    double re = 0., im = 0.;
};

Complex operator+(Complex x, Complex y)
{
    return {x.re + y.re, x.im + y.im};
}

Complex operator*(Complex x, Complex y)
{
    return {x.re*y.re - x.im*y.im, x.re*y.im + x.im*y.re};
}

Complex random_complex()
{
    return {rand() / 1000. - 1000., rand() / 1000. - 1000.};
}

template<typename F>
void benchmark(F f)
{
    using namespace chrono;
    auto start = high_resolution_clock::now();
    f();
    auto end = high_resolution_clock::now();
    auto elapsed = end - start;
    cout << "Elapsed = " << duration_cast<duration<double>>(elapsed).count() << "s" << endl;
}

int main()
{
    constexpr auto N = 1u << 24;
    vector<Complex> v, u;
    v.reserve(N);
    generate_n(back_inserter(v), N, random_complex);
    u = v;
    random_shuffle(begin(v), end(v));
    random_shuffle(begin(u), end(u));

    benchmark([&]
    {
        transform(begin(v), end(v), begin(u), begin(v), [](auto x, auto y) { return x*y; });
    });

    volatile auto anti_opti = accumulate(begin(v), end(v), Complex{});
    (void)anti_opti;
}


M>>>>Попутно хотелось бы определить, по каким критериям мы сравниваем.

EP>>>Простоту работы со struct-like вещами, а конкретнее — скорость выполнения и удобство кода.
M>Сложно? Если разные типы намешаны — возьму direct ByteBuffer.

Так о том и речь, приходится отказываться от удобных средств и использовать быстрые-неудобные, в то время как такой дилеммы могло бы и не быть.
Re[25]: C# - from indians by indians
От: Aртём Австралия жж
Дата: 02.06.15 23:01
Оценка: -1 :)
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Ок, другой пример — глобальные объекты для многих проектов это "бэд практис", для некоторых же это вполне стандартное решение — типа микроконтроллеров

Вы в курсе, что под микроконтроллеры нету C++?

EP>А где переход на личности? Ты ведь действительно не знаешь что там внутри происходит, разве нет? При этом делаешь какие-то нелепые попытки придраться.

Я уже Вам 3 раза повторил, что удобный доступ к памяти из C++ — для вычислений не значит ничего, ибо Ваш код C++ тормозной по сравнению с специализированными библиотеками. При этом Ваш код неустойчив, а на вопрос "как записать ошибку и тректрейс в лог", Вы предлагаете убивать программу. Т.е. это уже довольно много говорит о том, что 24/7 код Вы не задумывались, как писать.

EP>Даже если и больше по продолжительности, то по качеству — судя по всему нет

99/100 в IKM в 2011г- но без фич C++'11. Мог и подзабыть уже что-то, ибо с 2011г на плюсах не делал проекты.

EP>Что не понятно? Распараллеливание даст больший эффект нежели векторизация.

Почитайте про цену синхронизации. Узнайте много нового .

EP>>>Да даже если в Java-версии с Complex объектами будет векторизация, она всё равно будет медленнее C++ версии без векторизации — из-за плохого паттерна доступа к памяти — сути примера это никак не поменяет.

Aё>>Вы так ничего и не поняли.

EP>Куда уж там.

Попробую объяснить — сделайте N-мерный массив, сделайте обёртку с доступом по смешению через direct ByteBuffer- и будет счастье.

Aё>>А ведь я указывал парой сообщений выше- что Python с NumPy порвёт ваш плюснутый код, как тузик грелку.

EP>По какому критерию?
По скорости и выразительности.

Aё>>Потому что узкие места ускоряются через использование заточенной библиотеки.


EP>Которая далеко не всегда существует.

Не тешьте себя иллюзиями- всё украли до нас, причём ещё во времена Фортрана.

Aё>>А вот в качестве "клея" С++ — далеко не лучший вариант,


EP>Аргументы?

Я привёл Вам аргумент- неустойчивый код, отсутствие логирования стек трейсов, фрагментация кучи. Вам мало? Ну добавить ещё киллер-фичу перегрузка оператора aka выстрелить себе в ногу. В код выглядит выразительным и коротким, но программист на самом деле не знает, как оно под капотом работает. И не понимает, что не знает.

Aё>>>>и размер кода для попадания в кэш CPU почему-то знатоки C++ не упомянули,

EP>>>А зачем его упоминать? Думаешь код перемножения массивов не уместится в intruction cache?
Aё>>Думаю, что реальные задачи сложнее Вашего примера, а шаблоны C++ имеют дурную репутацию разбухания кода.

EP>В реальных задачах там где нужно используется динамический полиморфизм вместо статического, причём обычно где-то наверху. Это на порядки проще чем "работа вопреки языку" (как в тех случаях когда нужна скорость на Java).

Кажется, кто-то ставил Java в вину отсутствие статического полиморфизма- и тут же готов в реальных задачах от него отказаться. Вот и C++ "где-то наверху" не нужен. А "где-то внизу" он тоже не нужен, ибо есть библиотеки на C, где авторы в курсе про векторные расширения, кэш процессора, и т.д..

EP>Даже если допустить что это так — того факта что в Java нет структур, и связанными с этим тормозами или танцами с ручной нарезкой массивов байт на структуры, или факта того что в нагруженных приложениях частенько отказываются от GC — это никак не отменяет.

Не отказываются от GC- а минимизируют освобождение памяти. Обратите внимание, это и программ на C++ касается (фрагментация кучи).
Re[21]: C# - from indians by indians
От: mik1  
Дата: 02.06.15 23:25
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здесь используется не класс типа Complex, а класс типа ComplexArray.

EP>Собственно об этом и была речь — простейшая абстракция Complex не совместима с производительностью. То есть нельзя просто отдельно создать класс Complex и положить его в отдельный стандартный массив, в стандартную deque, в стандартную priority_queue и т.п. — их приходится вручную скрещивать.

А вот тут ты немного обманываешься — ни в деке, ни в очереди ты уже безразрывный блок памяти не получишь, и весь твой выигрыш рискует превратиться в тыкву

EP>Причём если взять структуру чуть-чуть посложнее, типа {double, float, int} — то всё, приплыли капитально.


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

EP>В этом примере (перемножение массивов объектов Complex) — тормоза на Java будут даже без учёта GC.


"Тормоза" тут будут только от 12-16 байтов заголовка объекта в Яве, которые будут "разрывать" последовательность даблов.
Как только ты уйдешь от массивов в плюсах, все станет на свои места. Кроме того, как я уже намекнул, твой пример скромно обходит любые выделения памяти
Отредактировано 03.06.2015 3:14 mik1 . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.