Здравствуйте, BulatZiganshin, Вы писали:
_>>Хотя в начале было бы ещё интересно посмотреть на результат icc для этого кода, вдруг он достаточно умный... BZ>только непонятно что ты дальше с этим делать будешь? перейдёшь на этот компилятор? ручная векторизация по крайней мере означает что дальше у тебя всё будет работать независимо от компиляторов и их ключей
Для начала можно просто скопировать выданный им код, а не придумывать свой)
Здравствуйте, BulatZiganshin, Вы писали:
BZ>таким образом, нам удалось доказать что бессмертный человек сможет соптимизировать программу лучше чем любой компилятор.
Нам удалось доказать, что никто не пишет на ассемблере не из-за того, что это не позволяет получить более быстрый код, а из-за того, что выигрыш, который от этого можно получить не соизмерим с теми затратами сил которые на это нужно потратить. При этом оптимизация кода на асме не является чем-то сверходинарным, в отличии от умения очень хорошо играть в шахматы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
_>>Ну и если считать коллекции C# с его сплошным ООП ближе ФП, чем STL, то даже не знаю что ещё сказать... ))) VD>Причем тут коллекции? Речь идет о лямбдах и linq-е. STL с его двунаправленными итераторами на этом фоне выглядит недоразумение.
ФП — это не лямбды, а просто наличие в языке функций первого класса. И такое было даже ещё в древнем C.
Linq — это IEnumerable, т.е. самое что ни на есть классическое ООП. Да, там добавили несколько дополнительных функций на этом интерфейсе, реализующих классическую ФП функциональность (типа map/reduce/filter, только обозвав в SQL стиле), но они такие уже давным давно были во многих языка, включая и менстримные. Причём в гораздо более классическом стиле (без всяких интерфейсов и т.п.).
Здравствуйте, alex_public, Вы писали:
_>Для начала можно просто скопировать выданный им код, а не придумывать свой)
вот уж проблема. сложение, сдвиг, сравнение и блендинг. если тебе непонятно это описание на русском, то ты не поймёшь его и на любом другом языке
кстати, а этот код вообще корректен? мне показалось что там rgb и тогда старшие биты одних каналов перемешиваются с младшими битами других. к примеру (0x0100+0x0000)/2 = 0x0080
Здравствуйте, alex_public, Вы писали:
_>ФП — это не лямбды, а просто наличие в языке функций первого класса. И такое было даже ещё в древнем C.
Нет, не просто. Иначе С-и будет тоже ФП.
_>Linq — это IEnumerable, т.е. самое что ни на есть классическое ООП.
Ну, это какая-то философская демогогия. Мне это не интересно. Linq, точнее изменения внесенные в версию Шарпа, которая поддерживает Linq — это встраивание в язык фич функционального программирования. IEnumerable не более чем абстракция списков доступная в языке (причем появившаяся за долго до Linq-а).
_>Да, там добавили несколько дополнительных функций на этом интерфейсе, реализующих классическую ФП функциональность (типа map/reduce/filter, только обозвав в SQL стиле), но они такие уже давным давно были во многих языка, включая и менстримные. Причём в гораздо более классическом стиле (без всяких интерфейсов и т.п.).
Многие языки нас не колыша. В C/C++/C# их не было. И главная добавленная фича — это лямбды с выводом типов и замыканиями. Без них map/fold/filter или Select/Aggrigate/Where был бы таким же унылым как аналоги из STL.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>полноценных функций там не было, поскольку их нельзя было конструировать на лету. полноценные функции — это как раз таки лямбды, а не голые указатели
Ага. И не просто лямбды, а с замыканиями и выводом типа. Казалось бы разница эфемерна, но разница в результате более чем очевидна.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
BZ>ой. вот тебе для пример такой вопрос — есть char a[16] и b[16], нужно найти номер первого различающегося байта. какой ты предложишь подход?
хз, поксорить и посчитать clz не используя бранчи? вообще я не занимался низкоуровневой оптимизацией уже лет восемь, но вроде с того времени ничего не изменилось — если что-то векторизуется и нет branch missprediction то обычно всё упрётся в пропускную способность памяти
Здравствуйте, BulatZiganshin, Вы писали:
_>>ФП — это не лямбды, а просто наличие в языке функций первого класса. И такое было даже ещё в древнем C. BZ>полноценных функций там не было, поскольку их нельзя было конструировать на лету. полноценные функции — это как раз таки лямбды, а не голые указатели
Ок, если цепляться к такой ерунде... Какой-нибудь древний std::pointer_to_unary_function — это первоклассная сущность или нет? )
Здравствуйте, alex_public, Вы писали:
_>О, если у тебя есть доступ к icc, то можешь сравнить на нём разницу между вариант со включенной векторизацией и выключенной на таком http://rsdn.ru/forum/flame.comp/6072279
(count=500, width=1920, height=1080) тесте? А то у меня gcc выдаёт на haswell xeon ускорение всего где-то в 3 раза, что как-то не очень для AVX2...
сейчас у меня нет доступа к icc, но если мне будет очень скучно я поставлю триал на выходных. вообще я занимался похожими вещами ( софтверные фильтры растра ) и обычно всё упиралось в медленную память
Здравствуйте, VladD2, Вы писали:
VD>Нам удалось доказать, что никто не пишет на ассемблере не из-за того, что это не позволяет получить более быстрый код, а из-за того, что выигрыш, который от этого можно получить не соизмерим с теми затратами сил которые на это нужно потратить. При этом оптимизация кода на асме не является чем-то сверходинарным, в отличии от умения очень хорошо играть в шахматы.
нет, Влад, не так. Если ты возьмёшь и просто "будешь писать на асме" у тебя мало того что код не будет быстрым, он у тебя будет медленней чем на C++, и только если ты начнёшь _оптимизировать_ код на асме, т.е. думать о векторизации, кешах, предсказании ветвлений, эффективном декодировании операций, то да, ты сможешь написать быстрый код. А вот например если ты берёшь С++ вместо java, или, тем более, скриптов, то тебе не нужно _оптимизировать_, у тебя сразу получается более эффективный исполняемый код.
Здравствуйте, BulatZiganshin, Вы писали: _>>Для начала можно просто скопировать выданный им код, а не придумывать свой) BZ>вот уж проблема. сложение, сдвиг, сравнение и блендинг. если тебе непонятно это описание на русском, то ты не поймёшь его и на любом другом языке
Вот как раз такой тупой код в лоб gcc и генерирует:
И именно он работает заметно медленнее теоретического максимума для данного процессора. BZ>кстати, а этот код вообще корректен? мне показалось что там rgb и тогда старшие биты одних каналов перемешиваются с младшими битами других. к примеру (0x0100+0x0000)/2 = 0x0080
Это не сглаживание картинки (видно же уже по количеству применений) — это разновидность клеточного автомата. )
Здравствуйте, VladD2, Вы писали:
_>>Linq — это IEnumerable, т.е. самое что ни на есть классическое ООП. VD>Ну, это какая-то философская демогогия. Мне это не интересно. Linq, точнее изменения внесенные в версию Шарпа, которая поддерживает Linq — это встраивание в язык фич функционального программирования. IEnumerable не более чем абстракция списков доступная в языке (причем появившаяся за долго до Linq-а).
Значит встраивание фич функционального программирования? ) Ну т.е. значит хотя бы такая базовая ФП вещь как частичное применение функций (хотя бы аналог древнейших std::bind1st и т.п.) были тогда введены в библиотеку C#?) Ну чтобы играться с каррированием и прочими ФП извращениями... )
_>>Да, там добавили несколько дополнительных функций на этом интерфейсе, реализующих классическую ФП функциональность (типа map/reduce/filter, только обозвав в SQL стиле), но они такие уже давным давно были во многих языка, включая и менстримные. Причём в гораздо более классическом стиле (без всяких интерфейсов и т.п.). VD>Многие языки нас не колыша. В C/C++/C# их не было. И главная добавленная фича — это лямбды с выводом типов и замыканиями. Без них map/fold/filter или Select/Aggrigate/Where был бы таким же унылым как аналоги из STL.
Правильно, нас интересуют только мейнстрим языки. Питон мы вроде бы признали таковым? ) Видел как там выглядит map/filter/reduce? )
Ну и даже если их аналог из STL кажется тебе унылым, то ты же всё равно сам признаёшь, что это аналог...
Здравствуйте, VladD2, Вы писали: VD>Здравствуйте, Mazay, Вы писали: M>>Я же сказал — я перепутал. VD>Ну, а претензию то ты свою обратно берешь? Или отсутствие аргументов наездов не отменяет?
Тестов нет на шутауте, зато я привёл тесты по ссылке ниже. Так что наезд в силе. M>>Это называется "особенности" реализации алгоритма. По сути неэффективная реализация. Их там сохраняют потому что иногда после модификации неэффективной реализации она может стать самой быстрой. VD>Включи же логику, наконец! Раз особенности реализации так сильно влияют на результат, значит алгоритмы не эквивалентны и сравнивать компиляторы на них некорректно.
Ничего подобного. Алгоритм и его реализация на конкретном языке — это разные вещи, разный уровень абстракции. Каждый алгоритм может быть реализован на любом Тьюринг-полном языке, но по разному. С функциями, без функций, с глобальными переменными, без оных, передавая параметры по ссылке или копируя их, выравнивая или переупорядочивая данные в структуре, выставляя барьеры. Все эти тонкости свои для каждого языка свои, но итоговая задача — заставить компилятор сгенерить наилучший машинный код. Если язык не позволяет этого сделать, то он плох. VD>Ты же программист. Ты же должен уметь логически мыслить. Или раз тебе не выгодно, то можно плевать на логику?
Ты же профессионал — не переходи на личности. VD>>>Подтверждение чего? Опровержение чего? Вроде там результаты D на уровне С-шных. M>>Ну вот такой взгляд разработчиков языка на результаты тестов и множит на ноль все его перспективы в HPC. VD>Какой, такой? Что ты несешь? По твоей ссылке D показывает результат близкий к C-шным. В одном из тестов он даже выше С-ишных. В других отстает на десятую секунды. Какое это на фиг оставление? Какой-нибудь VC++ отстанет намного больше. M>>D по всем тестам медленнее C. VD>Не правда. В matmul:m он быстрее. В остальных если и медленнее, то на сущие копейки.
У нас интернет разный? Вот же.
Верхние три результата на Си от 1.8 до 2.3 секунд. На Ди — от 2.4 до 3.3 (кстати, 2.4 — LLVM).
M>>Даже на наивном умножении матриц. Это как надо накосячить в компиляторе, чтобы получить просадку на такой элементарной вещи? VD>Ты высосал проблему из пальца и подгоняешь факты под свои утверждения. Там тупо разные библиотеки используются, а может и разные версии того же GCC.
Какие библиотеки? Там наивное умножение на трёх циклах. VD>Разница при этом в пределах статистических погрешностей, но ты натягиваешь сову на глобус и делаешь феерические завлечения.
Статистическая погрешность бывает в обе стороны, а если отклонение всегда в одну сторону — это уже закономерность. M>>Там машинный код должен быть один-в-один. Если у них бэкэнд от GCC, то что же там надо было навертеть в IR? Вот у clang++ правильный подход. Если им присылают код, который на gcc компилируется в более быстрый, то они заводят багу. VD>Кончай нести пургу. Иди открой исходники и посмотри на них. Посмотри как написана С-шная версия^: VD>
VD>[d] VD>import std.stdio, std.string;
VD>void main(string[] args) { VD> int N = 5000000; VD> char[] buf; VD> int[char[]] h; VD> int max = 1, n = 0; VD> if (args.length >= 2) N = atoi(args[1]); VD> while (readln(stdin, buf)) { VD> int current = ++h[buf]; VD> max = (current > max)? current : max; VD> if (++n == N) { VD> writef(h.length); writef("\t"); writefln(max); VD> } VD> } VD> writef(h.length); writef("\t"); writefln(max); VD>} VD>[/d]
VD>Там есть и нормальная С++-ная версия, но по понятным причинам ее в списке результатов не: VD>
Скрытый текст
VD>
VD>#include <utility>
VD>#include <iostream>
VD>#include <unordered_map>
VD>using namespace std;
VD>int main(int argc, char *argv[])
VD>{
VD> unordered_map<string, int> h;
VD> string s;
VD> int max = 1;
VD> while (getline(cin, s).good()) {
VD> unordered_map<string, int>::iterator p = h.find(s);
VD> if (p == h.end()) h[s] = 1;
VD> else {
VD> ++p->second;
VD> if (max < p->second) max = p->second;
VD> }
VD> }
VD> cout<<h.size()<<'\t'<<max<<'\n';
VD> return 0;
VD>}
VD>
Это по-твоему умножение матриц? Кажется ты пропустил кусок рассуждений, где ты перешёл от matmul к dict. VD>Там разные хэш-таблицы используются и совершенно разный уровень битовыжимания. В D — это прекрасно читаемый код использующий встроенные хэш-таблицы, а на С-и — куча мелких оптимизаций и рукапашная работа с памятью.
Ну так здесь же сравнивается производительность, а не читабельность. Внутренние циклы оптимизируют без всякой оглядки на читаемость. VD>Хочешь сравнить компиляторы? Напиши одинаковую реализацию хэш-таблицы. В конце концов D-и без проблем позволяет те же малоки дергать.
Согласен. Для сравнения языков (или компиляторов) хэш должен быть одинаковым. Там собственно написано
Note that "sudoku" and "matmul" evaluate the performance of the language itself. "Patmch" and "dict" below effectively evaluate the performance of libraries.
Потому я и написал про matmul. Зачем ты на dict перепрыгнул? Вот код для matmul:
Си:
Скрытый текст
// Writen by Attractive Chaos; distributed under the MIT license#include <stdlib.h>
#include <stdio.h>
double **mm_init(int n)
{
double **m;
int i;
m = (double**)malloc(n * sizeof(void*));
for (i = 0; i < n; ++i)
m[i] = calloc(n, sizeof(double));
return m;
}
void mm_destroy(int n, double **m)
{
int i;
for (i = 0; i < n; ++i) free(m[i]);
free(m);
}
double **mm_gen(int n)
{
double **m, tmp = 1. / n / n;
int i, j;
m = mm_init(n);
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
m[i][j] = tmp * (i - j) * (i + j);
return m;
}
// better cache performance by transposing the second matrixdouble **mm_mul(int n, double *const *a, double *const *b)
{
int i, j, k;
double **m, **c;
m = mm_init(n); c = mm_init(n);
for (i = 0; i < n; ++i) // transposefor (j = 0; j < n; ++j)
c[i][j] = b[j][i];
for (i = 0; i < n; ++i) {
double *p = a[i], *q = m[i];
for (j = 0; j < n; ++j) {
double t = 0.0, *r = c[j];
for (k = 0; k < n; ++k)
t += p[k] * r[k];
q[j] = t;
}
}
mm_destroy(n, c);
return m;
}
int main(int argc, char *argv[])
{
int n = 100;
double **a, **b, **m;
if (argc > 1) n = atoi(argv[1]);
n = (n/2) * 2;
a = mm_gen(n); b = mm_gen(n);
m = mm_mul(n, a, b);
fprintf(stderr, "%lf\n", m[n/2][n/2]);
mm_destroy(n, a); mm_destroy(n, b); mm_destroy(n, m);
return 0;
}
Ди:
Скрытый текст
// Originally written by Attractive Chaos; distributed under the MIT license (D V.2 code)
// D1 code for LDC:
// http://www.dsource.org/projects/ldc
// Compile with: ldc -O3 -release -inline matmul.d
import tango.stdc.stdio, tango.stdc.stdlib;
double[][] matGen(in int n) {
double tmp = 1.0 / n / n;
auto a = new double[][](n, n);
foreach (int i, row; a)
foreach (int j, ref x; row)
x = tmp * (i - j) * (i + j);
return a;
}
double[][] matMul(in double[][] a, in double[][] b) {
int m = a.length,
n = a[0].length,
p = b[0].length;
// transposeauto c = new double[][](p, n);
foreach (i, brow; b)
foreach (j, bx; brow)
c[j][i] = bx;
auto x = new double[][](m, p);
foreach (i, arow; a)
foreach (j, crow; c) {
// x[i][j] = std.numeric.dotProduct(arow, crow); // right way D2double s = 0.0;
foreach (k, arowk; arow)
s += arowk * crow[k];
x[i][j] = s;
}
return x;
}
void main(in char[][] args) {
int n = 100;
if (args.length >= 2)
n = atoi((args[1] ~ '\0').ptr) / 2 * 2;
auto a = matGen(n);
auto b = matGen(n);
auto x = matMul(a, b);
printf("%f\n", x[n / 2][n / 2]);
}
Тут всё даже без интринсиков. Почему Ди здесь проваливается? VD>>>Если результаты одного языка отличаются, то где гарантии, что дело не в том как написан тест, а именно в компиляторе? M>>Я в этом посте выше написал про "особенности" реализации. VD>Ты сам себе противоричешь. В одной строке ты утверждаешь, что алгоритмы эквивалентны, а в другом говоришь о каких-то там особенностях реализации. Чтобы сравнивать кодогенерацию нужно иметь эквивалентный код. Понимаешь? Инструкция в инструкцию.
Инструкция в инструкцию — невозможно для разных языков. Приходится выбирать наилучшую реализацию для каждого языка. VD>Ежу понятно, что если у тебя в алгоритме используется хэш-таблица, то результат его работы, во многом, будет зависеть от качества ее реализации и от качества хэш-функции.
С хэш-таблицей всё понятно. Наивное умножение матриц тебя чем не устраивает? M>>Никогда нельзя быть уверенным, что ты что-то не упустил, но если ты хочешь показать, что какой-то язык/компилятор крут — ты всегда можешь сравнить код и машинный код с самой быстрой реализацией (на другом языке) и поправить свой код. Если это сделать не удаётся — это баг. VD>
Здравствуйте, VladD2, Вы писали:
_>>Ну и если считать коллекции C# с его сплошным ООП ближе ФП, чем STL, то даже не знаю что ещё сказать... ))) VD>Причем тут коллекции? Речь идет о лямбдах
Лямбды/замыкания не являются определяющей характеристикой ФП. Есть ФЯ без лямбд — Unlambda, а также есть старый язык с замыканиями — Smalltalk — который совершенно не ФЯ.
Здравствуйте, VladD2, Вы писали:
I>>Вот чОрт, всегда виноваты эти мейнстримные программисты. Никак не могут парадокс блаба преодолеть, вместо этого, бездельники, гоняются за экономическим профитом.
VD>Они только думают, что гоняются. На самом деле они нагревают вселенную своим непроизводительным трудом.
Напомнишь, на каких языках написаны инструменты джетбрейнс ? Как то так выходит, мейнстримные программисты зарабатывают столько, что хватает даже на команду нитры, котлина и десяток таких же.
Здравствуйте, antropolog, Вы писали:
BZ>>ой. вот тебе для пример такой вопрос — есть char a[16] и b[16], нужно найти номер первого различающегося байта. какой ты предложишь подход? A>хз, поксорить и посчитать clz не используя бранчи?
тепло. но уже начиная с mmx есть pcmpeqb и pmovmskb. надо ли объяснять почему компиляторы эти способы не используют?