xvr 12 4 февраля, 2019 Опубликовано 4 февраля, 2019 · Жалоба 1 hour ago, Kabdim said: А с другой стороны интеловый фортран компилятор позволяет приблизится по эффективности к программе на С. Наоборот - это С приближается к Фортрану (как не странно). Дело в том, что в модели вызовов функций в Фортране есть один замечательный момент. Постулируется, что все параметры независимы, т.е. оптимизатор имеет право считать, что никакие переданные массивы никогда не пересекаются. В С все массивы передаются указателями, и оптимизатор обязан считать наоборот - что любые параметры/указатели могут пересечься. А так как вся математика крутится вокруг массивов, то это сразу отрубает добрую половину возможных оптимизаций (причём в очень критичном месте). Компиляторы сейчас достаточно умные, что бы понять где и что пересекается, а где нет, но всё равно отследить до конца они не в состоянии (не зря в С появилось ключевое слово restrict) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iiv 27 4 февраля, 2019 Опубликовано 4 февраля, 2019 · Жалоба Спасибо всем за интересные советы и обсуждения! Так все-таки вдруг кто знает, скажите, пожалуйста, есть ли возможность отказаться от строчки double (*X)[M] = static_cast<double (*)[M]>((void*)_X); в каждой лямбде, описав ее один раз на функцию и желательно по стандарту и без использования std::vector ? Спасибо! ИИВ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 5 февраля, 2019 Опубликовано 5 февраля, 2019 · Жалоба 15 часов назад, xvr сказал: Наоборот - это С приближается к Фортрану (как не странно). .. Постулируется, что все параметры независимы ... (не зря в С появилось ключевое слово restrict) Вы уж определитесь только приближается или есть restrict, которым нужно пользоваться/использовать правильно написанные библиотеки. Но в целом конечно да, фортран для ученых требует меньших чем для cpp ментальных усилий при приличном результате. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 5 февраля, 2019 Опубликовано 5 февраля, 2019 · Жалоба 19 hours ago, iiv said: Func3 - и только тут с копией в каждой единице функции удается все скомпилировать. Я потыкал Ваш код на godbolt.org - только gcc и умеет его компилировать. Все остальные ругаются на трюки с приведением типов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 5 февраля, 2019 Опубликовано 5 февраля, 2019 · Жалоба 1 hour ago, Kabdim said: Вы уж определитесь только приближается или есть restrict, которым нужно пользоваться/использовать правильно написанные библиотеки. Во первых restrict появился сравнительно недавно (сравнительно с возрастом Фортрана) Во вторых им почти не пользуются :( Ну и если им пользоваться (и/или использовать правильные библиотеки), то разницы в качестве оптимизации не будет :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 5 февраля, 2019 Опубликовано 5 февраля, 2019 · Жалоба 8 часов назад, xvr сказал: Во первых restrict появился сравнительно недавно (сравнительно с возрастом Фортрана) Во вторых им почти не пользуются :( Ну и если им пользоваться (и/или использовать правильные библиотеки), то разницы в качестве оптимизации не будет :) Он больше не на качество оптимизации влияет, а скорее на правильность результата после применения оптимизации. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 75 5 февраля, 2019 Опубликовано 5 февраля, 2019 · Жалоба On 2/4/2019 at 4:30 PM, iiv said: Спасибо! Лет десять у нас была такая идея :) там ключевая проблема в том, что компилер начинает сходить с ума, раскрывая все инлайны и код становится огромным и не влазит в кеш инструкций, соответсвенно тут же падает производительность. ну тогда могу предложить ещё более замечательные костыли: вставить код внутренней функции один раз как есть, а вызовы этой функции заменить на метки и goto, и прыгать туда сюда, jmp, call, какая разница :), ну переменную ещё одну завести придётся, счётчик вызовов и switch в конце функции добавить, чтобы возвращаться из этой "локальной" функции туда откуда вызывали. ну и локальные переменные под аргументы и возвращаемое значение. void Func(int N, int M, double X[N][M]){ int i, j; int Test_call_cnt = 0; goto Test_end; :Test { int i, j; for(i=0; i<N; i++) for(j=0; j<M; j++) X[i][j]=(double)(i*1000+j); Test_call_cnt += 1; switch (Test_call_cnt){ case 1 : goto Test_call_1; case 2 : goto Test_call_2; case 3 : goto Test_call_3; } } :Test_end goto Test; :Test_call_1 for(i=0; i<N; i++) { double s=0; for(j=0; j<M; j++) s+=X[i][j]*X[i][j]; s=(s>0.)?1./sqrt(s):0.; for(j=0; j<M; j++) X[i][j]*=s; } goto Test; :Test_call_2 return; } а ещё в макросы всю эту красоту обернуть :) чтобы не так страшно было. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 6 февраля, 2019 Опубликовано 6 февраля, 2019 · Жалоба В 04.02.2019 в 18:30, iiv сказал: Но оно точно потянет перетестирование всей оптимизации кеша и мультитредингов (вложенные функции ужасно удобны в ручном мультитрединге). Если включить full LTO, с точки зрения компилятора ничего поменяться не должно кроме удобства для программиста. Разбивать на маленькие исходники вполне можно научится скриптом. Честно говоря не вижу в этой задаче человекогоды. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 6 февраля, 2019 Опубликовано 6 февраля, 2019 · Жалоба 40 minutes ago, Kabdim said: не вижу в этой задаче человекогоды Ну, скажем, код __pv вполне может стоить человекожизни. Потому что искать случайную опечатку в этой красоте - убицца просто. Имхо - оставить всё как есть или медленно и печально переносить на std::vector или какой-нибудь самодельный vector2d. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iiv 27 6 февраля, 2019 Опубликовано 6 февраля, 2019 · Жалоба 9 minutes ago, esaulenka said: Ну, скажем, код __pv вполне может стоить человекожизни. Потому что искать случайную опечатку в этой красоте - убицца просто. Имхо - оставить всё как есть или медленно и печально переносить на std::vector или какой-нибудь самодельный vector2d. Спасибо большое всем за интересные советы! Действительно, на многих не поддерживается даже то, что у меня в func3. На удивление последний интел это стал поддерживать, я принял это за чистую монету и поэтому кинулся в этом направлении. Похоже да, если и переползать на С++, то пользовать что-то самодельное похожее на std::vector. PS: тут же еще все поддерживать надо. Софт-то не на месте стоит, а постоянно модифицируется. Ошибка в концепции - действительно приведет к потерям порядка человекожизни. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 6 февраля, 2019 Опубликовано 6 февраля, 2019 · Жалоба 17 минут назад, esaulenka сказал: Ну, скажем, код __pv вполне может стоить человекожизни. Но ведь я говорил не про код __pv... Там цитата про обсуждение разделения кода на файлы. У __pv ключевая фраза про оборачивание страшного кода в макросы сама по себе достаточно знаковая. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 75 6 февраля, 2019 Опубликовано 6 февраля, 2019 · Жалоба 40 minutes ago, esaulenka said: Ну, скажем, код __pv вполне может стоить человекожизни. Потому что искать случайную опечатку в этой красоте - убицца просто. я старался. но с другой стороны вся эта красота будет генерироваться автоматически скриптами, и её можно в макросы убрать. и в результате наверное можно добиться чего-нибудь вроде void Func(){ DECLARE_LOCAL_FUNC (Test){ ... } ... CALL(Test); ... } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 6 февраля, 2019 Опубликовано 6 февраля, 2019 · Жалоба 15 hours ago, Arlleex said: Он больше не на качество оптимизации влияет, а скорее на правильность результата после применения оптимизации. Нет, именно на качество. Если после оптимизации результат не правильный, то оптимизатор не вправе эту оптимизацию применять. А restrict развязывает оптимизатору руки, и он может применить более агрессивные оптимизации. PS. Я не утверждаю, что оптимизатор никогда не создаёт неправильного кода - ошибки у всех бывают, в том числе и у писателей компиляторов :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 6 февраля, 2019 Опубликовано 6 февраля, 2019 · Жалоба В 04.02.2019 в 18:45, iiv сказал: Добрый день, Попробовал в лоб сделать на ламбдах, получилось так: void Func3(int N, int M, double *_X) { double (*X)[M] = static_cast<double (*)[M]>((void*)_X); auto Test = [&] () -> void { int i, j; double (*X)[M] = static_cast<double (*)[M]>((void*)_X); for(i=0; i<N; i++) for(j=0; j<M; j++) X[i][j]=(double)(i*1000+j); // теперь он все видит, но приходится писать double (*X)[M] ... в каждой лямбде и копировать указатель из _Х }; .. } Если проблема только в том, что надо чем-то заменить массивы переменной длины, то можно вместо проблемного static_cast соорудить какой-нибудь класс, типа FlexibleArray2d, и вместо кастования создавать экземпляр этого класса. Его и использовать в лямбде (потыкать на wandbox-е): // одномерный массив переменной размерности template<typename T> struct FlexibleArray { FlexibleArray(size_t xDim, T* rawData) : x(xDim), data(rawData) {} T& operator[](size_t xPos) { return data[xPos]; } private: const size_t x; T* data; }; // двумерный массив переменной размерности template<typename T> struct FlexibleArray2d { FlexibleArray2d(size_t xDim, size_t yDim, T* rawData) : x(xDim) , y(yDim) , data(rawData) {} FlexibleArray<T> operator[](size_t yPos) { return FlexibleArray<T>(x, &data[yPos * x]); } private: const size_t x; const size_t y; T* data; }; // использование void Func3(int N, int M, double *_X) { // вместо static_cast-а делаем вот как: FlexibleArray2d<double> X(N, M, _X); // и далее по тексту auto Test = [&] () -> void { int i, j; for(i=0; i<N; i++) for(j=0; j<M; j++) X[i][j]=(i*1000+j); }; int i, j; Test(); for(i=0; i<N; i++) { double s=0; for(j=0; j<M; j++) s+=X[i][j]*X[i][j]; s=(s>0.)?1./sqrt(s):0.; for(j=0; j<M; j++) X[i][j]*=s; } return; } В качестве бонуса можно добавить проверки на выход за пределы диапазонов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 27 6 февраля, 2019 Опубликовано 6 февраля, 2019 · Жалоба 17 hours ago, _pv said: ну тогда могу предложить ещё более замечательные костыли: вставить код внутренней функции один раз как есть, а вызовы этой функции заменить на метки и goto, и прыгать туда сюда, jmp, call, какая разница :), ну переменную ещё одну завести придётся, счётчик вызовов и switch в конце функции добавить, чтобы возвращаться из этой "локальной" функции туда откуда вызывали. ну и локальные переменные под аргументы и возвращаемое значение. . . . . а ещё в макросы всю эту красоту обернуть :) чтобы не так страшно было. Это получится, насколько понял, Protothreads http://dunkels.com/adam/pt/ ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться