Здравствуйте, Хвост, Вы писали:
Х>надеюсь вы находитесь в трезвом уме и твёрдой памяти и понимаете разницу между "алгоритм был изменён человеком так что исключена его корректная работа" и "в целях оптимизации, код алгоритма не был сгенерирован компилятором"
Разницу между "ложью" и "ошибкой", ты хотел сказать? Ключи оптимизации не взялись из ниоткуда
Впрочем, поскольку "ошибки" исходного поста устранены в тестах criosray, мы имеем
C++ — 77 секунд
С# — 86 секунд
Здравствуйте, midcyber, Вы писали:
M>Здравствуйте, Хвост, Вы писали:
Х>>надеюсь вы находитесь в трезвом уме и твёрдой памяти и понимаете разницу между "алгоритм был изменён человеком так что исключена его корректная работа" и "в целях оптимизации, код алгоритма не был сгенерирован компилятором"
M>Разницу между "ложью" и "ошибкой", ты хотел сказать? Ключи оптимизации не взялись из ниоткуда
M>Впрочем, поскольку "ошибки" исходного поста устранены в тестах criosray, мы имеем M>C++ — 77 секунд M>С# — 86 секунд
M>ЧТД
ето показывает лишь то что MS-компилятор генерит не самый быстрый во вселенной код, кстати скомпилируйте С++ код не с оптимизацией по скорости и с оптимизацией по размеру кода (/O1 у MS-компилятора), результат кого-то удивит.
я думаю что Intel'овский компайлер ничего не выкинул, а честно фигачил 27 секунд бесцельные циклы, а то что он оказался в разы быстрее MS-компилятора — так ето и не удивительно, учитывая что он на порядок дольше компилит.
Здравствуйте, criosray, Вы писали:
C>Здравствуйте, Sorantis, Вы писали:
L>>>Не "превосходство С++", а превоходство интеловского компилятора перед MS-овским jit-ом. L>>>Для корректного сравнения компилируйте C++-код MS-компилятором и сравнивайте.
S>>ну я и говорю. S>>3 секунды под МС компиллер.
Ключевые моменты выделены.
98 секунд на Коре Дуо 2.4
основное время, понятное дело — синус с косинусом.
Aux a;
time_t t1, t2;
time(&t1);
int b = 0;for(int i = 0; i < 100; i++)
{
a.z = 0;
for(a.y = -1.5; a.y < 1.5; a.y += 0.001)
{
for(a.x = -1; a.x < 2; a.x += 0.001)
{
b += a.GetColor();
}
}
}
time(&t2);
cout << "elapsed: " << difftime(t2, t1) << " seconds.; b = " << b << endl;
Здравствуйте, criosray, Вы писали:
C>Здравствуйте, Хвост, Вы писали:
C>>>2) самое значимое — так как алгоритм явно элементарно параллелится, то раскидал его на все доступные (их два у меня) ядра процессора с помощью Parallel.For Х>>а можно узнать результаты теста без Parallel.For? меня терзают смутные сомнения что вы преувеличили лёгкость распараллеливания алгоритма и он у вас просто некорректно работает.
C>Elapsed 00:01:26.8746531
C>86 секунд — то есть примерно на 10-12% медлененнее С++ варианта.
C>На счет Parallel.For Вы правы — работает некорректно. Каюсь, час ночи + спешка — преувеличил легкость распараллеливания.
C>Завтра на свежую голову посмотрю внимательнее как его распараллелить.
Распараллелил. Топорно и наверняка не оптимально, но нет времени на лучшее.
Результат
Elapsed 00:00:45.3581939 sec.
1813065000
Подсчитанно корректно. В полтора раза быстрее С++ варианта без параллелинга, как видим.
Код (как видим я создаю объекты на куче в цикле, что очень не рационально):
...
Parallel.For(0, 100, i =>
{
var a = new Aux();
int b = 0;
for (a.y = -1.5; a.y < 1.5; a.y += 0.001)
{
for (a.x = -1; a.x < 2; a.x += 0.001)
{
b += a.GetColor();
}
}
spinlock.Enter();
x += b;
spinlock.Exit();
});
stopWatch.Stop();
Console.WriteLine("Elapsed {0} sec.", stopWatch.Elapsed);
Console.WriteLine(x);
Здравствуйте, IID, Вы писали:
IID>Я привёл код в компилябельное состояние. Вот C# вариант, а вот C++ вариант. Для компиляции использовалась MSVS2008 со всеми обновлениями.
А почему в плюсовом варианте используется си-шный abs() он же вроде как возвращает int. Или в stdfx.h включён ещё и <cmath>?
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Здравствуйте, criosray, Вы писали:
C>Распараллелил. Топорно и наверняка не оптимально, но нет времени на лучшее. C>Результат C>Elapsed 00:00:45.3581939 sec. C>1813065000 C>Подсчитанно корректно. В полтора раза быстрее С++ варианта без параллелинга, как видим.
ну, продолжим я сегодня выступаю на стороне C++
(cpu: core2 2.4GHz — T7700 два ядра ноутбук 32bit winxp)
изначальный тест показывает 0 секунд на icc (ровно той же версии что и у топикстартера)
(всё собираю из комстроки)
твой вариант с распечаткой результата:
icl -fast test.cpp
Здравствуйте, frogkiller, Вы писали:
F>А почему в плюсовом варианте используется си-шный abs() он же вроде как возвращает int. Или в stdfx.h включён ещё и <cmath>?
Кстати, в указанном варианте со стандартным abs у меня даже и не скомпилялось, ругнулось на неопределённость перегрузки.
ЗЫ. На моей слабенькой машинке с линуксом и gcc замена <cmath> на <math.h> (и соответсвенно abs на fabs) сократило время работы в дебажной версии с 178 сек до 157 сек, т.е на 12%.
При -O2 времена составили, соответсвенно, 111 сек и 112 сек (т.е. с cmath даже быстрее)
При -O3 времена составили, соответсвенно, 111 сек и 111 сек.
Результат везде: 1813065000
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Здравствуйте, Antikrot, Вы писали:
C>>Распараллелил. Топорно и наверняка не оптимально, но нет времени на лучшее. C>>Результат C>>Elapsed 00:00:45.3581939 sec. C>>1813065000 C>>Подсчитанно корректно. В полтора раза быстрее С++ варианта без параллелинга, как видим.
A>ну, продолжим я сегодня выступаю на стороне C++ A>(cpu: core2 2.4GHz — T7700 два ядра ноутбук 32bit winxp)
A>изначальный тест показывает 0 секунд на icc (ровно той же версии что и у топикстартера) A>(всё собираю из комстроки)
A>твой вариант с распечаткой результата: A>icl -fast test.cpp
A>test.exe A>elapsed: 32 seconds. A>1813065000
A>мой вариант с openmp:
Хм, не понял, а каким образом лочится состояние объекта а в Вашем варианте?
A>
A>#pragma omp parallel for reduction(+:x)
A> for(int i = 0; i < 100; i++)
A> {
A> a.z = 0;
A> for(a.y = -1.5; a.y < 1.5; a.y += 0.001)
A> {
A> for(a.x = -1; a.x < 2; a.x += 0.001)
A> {
A> x += a.GetColor();
A> }
A> }
A> }
A>
C>Хм, не понял, а каким образом лочится состояние объекта а в Вашем варианте?
А зачем его лочить? Во внутреннем цикле a.y не изменяется, можно спокойно запускать в нескольких потоках со всеим значением a.y, а потом собрать полученный результат в переменную x.
Интересно было посмотреть, что будет, если суммировать не в переменную на стеке, а в такой же член класса:
a.sum += a.GetColor();
А в сам класс добавить vtable, для запутывания, так сказать Сможет в этом случае компилятор понять, что a.sum так же будет аддитивной?
Курица — это инструмент, с помощью которого одно яйцо производит другие.
не понял, состояние чего? переменной x? или a? x указан в reduction, так что это проблема openmp, уж позвольте опустить объяснение как оно внутри работает.
что касается a, раз ты его втащил в Parallel.For, так я его буду делать private
#pragma omp parallel for reduction(+:x) private(a)
так он будет свой для каждого потока, и ничего лочить не надо.
Здравствуйте, Antikrot, Вы писали:
A>Здравствуйте, criosray, Вы писали:
C>>Хм, не понял, а каким образом лочится состояние объекта а в Вашем варианте?
A>>>
A>не понял, состояние чего? переменной x? или a?
Я не спрашивал про х. Про х я и так вижу, что там аналог Incremental.Add
A>что касается a, раз ты его втащил в Parallel.For, так я его буду делать private A>
A>#pragma omp parallel for reduction(+:x) private(a)
A>
A>так он будет свой для каждого потока, и ничего лочить не надо.
Ок, замечательно. А как в предыдущем тесте у Вас получился корректный результат без private(a)? Потрудитесь объяснить. А заодно приведите замеры с исправленным кодом — где добавлено private(a).
C>>Хм, не понял, а каким образом лочится состояние объекта а в Вашем варианте?
F>А зачем его лочить? Во внутреннем цикле a.y не изменяется, можно спокойно запускать в нескольких потоках со всеим значением a.y, а потом собрать полученный результат в переменную x.
Потому, что параллелится внешний цикл.
Поток 1: вызывает a.GetColor со значениями a.y = -1.5, a.x = -1
Поток 1: Golova() возвращает false
Поток 1: предположим, Spiral() должен был бы вернуть true, но ДО того, как он будет вызван:
Поток 2 перезаписывае a.y и a.x соответствующими инкрементами!
Поток 1: Spiral() возвращает false и объект а теперь в таком состоянии, что только Golova вернула бы true — все проверки возвращают false, GetColor — возвращает 0.
F>Интересно было посмотреть, что будет, если суммировать не в переменную на стеке, а в такой же член класса: F>
a.sum += a.GetColor();
F>А в сам класс добавить vtable, для запутывания, так сказать Сможет в этом случае компилятор понять, что a.sum так же будет аддитивной?
Хороший вопрос...
Здравствуйте, criosray, Вы писали:
F>>Интересно было посмотреть, что будет, если суммировать не в переменную на стеке, а в такой же член класса: F>>
a.sum += a.GetColor();
F>>А в сам класс добавить vtable, для запутывания, так сказать Сможет в этом случае компилятор понять, что a.sum так же будет аддитивной? C>Хороший вопрос...
всё конечно интересно, но компилятор ничего не понимает, ему явно указано что аддитивное. да и указать a.sum в reduction как-то не получается...
лочить же a.sum += a.GetColor() с помощью omp critical сильно всё затормаживает (у меня почти в восемь раз)
C>>>Хм, не понял, а каким образом лочится состояние объекта а в Вашем варианте?
F>>А зачем его лочить? Во внутреннем цикле a.y не изменяется, можно спокойно запускать в нескольких потоках со всеим значением a.y, а потом собрать полученный результат в переменную x.
C>Потому, что параллелится внешний цикл.
C>Поток 1: вызывает a.GetColor со значениями a.y = -1.5, a.x = -1 C>Поток 1: Golova() возвращает false C>Поток 1: предположим, Spiral() должен был бы вернуть true, но ДО того, как он будет вызван: C>Поток 2 перезаписывае a.y и a.x соответствующими инкрементами! C>Поток 1: Spiral() возвращает false и объект а теперь в таком состоянии, что только Golova вернула бы true — все проверки возвращают false, GetColor — возвращает 0.
Это всё понятно. Я к тому, что нужно не лочить, а создавать копию. Более корректным было бы описать методы класса Aux как константные, но тут компилятор сам об этом догадался.
F>>Интересно было посмотреть, что будет, если суммировать не в переменную на стеке, а в такой же член класса: F>>
a.sum += a.GetColor();
F>>А в сам класс добавить vtable, для запутывания, так сказать Сможет в этом случае компилятор понять, что a.sum так же будет аддитивной? C>Хороший вопрос...
Подозреваю, что без помощи в виде явной спецификации константных методов не обойтись. Но проверить ме могу, под рукой только gcc, да и он не самый новый.
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Здравствуйте, frogkiller, Вы писали:
F>ЗЫ. На моей слабенькой машинке с линуксом и gcc замена <cmath> на <math.h> (и соответсвенно abs на fabs) сократило время работы в дебажной версии с 178 сек до 157 сек, т.е на 12%.
Видимо библиотечная функция кривая... ABS в представлении с плавающей точкой это всего лишь безусловный сброс старшего бита, тормозить там (алгоритмически) нечему. Даже целочисленный ABS тормознее (условный NEG), если не реализован в железе.
Здравствуйте, IID, Вы писали:
IID>Здравствуйте, frogkiller, Вы писали:
F>>ЗЫ. На моей слабенькой машинке с линуксом и gcc замена <cmath> на <math.h> (и соответсвенно abs на fabs) сократило время работы в дебажной версии с 178 сек до 157 сек, т.е на 12%.
IID>Видимо библиотечная функция кривая... ABS в представлении с плавающей точкой это всего лишь безусловный сброс старшего бита, тормозить там (алгоритмически) нечему. Даже целочисленный ABS тормознее (условный NEG), если не реализован в железе.
Ну, помимо abs там ещё поменялись, очевидно, и всякие cos/sin
Курица — это инструмент, с помощью которого одно яйцо производит другие.
C> public int GetColor()
C> {
C> if (Spiral())
C> {
C> return 2;
C> }
...skip...
C> return 0;
C> }
C>
А вот это — всегда пожалуйста. Только удивительно что компилятор C# такое не осиливает, если это правда дало какой-то выигрыш.
Попытки упростить вычисления не годятся. Мы ведь можем и поменять пределы изменения пары x,y. И "упрощённый" код станет давать неверные варианты. (В суть закомментированного лень вчитываться, но этот код явно влияет на результат)