Здравствуйте, ZegSoft, Вы писали:
ZS>Пока проблему решил через шаблоны. То есть создаются две копии объектов: float-версия и double-версия. float-версия передается в алгоритмы, которые допускают расчеты с точностью float, а double версия в остальные алгоритмы. Но при таком подходе возникает проблема синхронизации версий. В принципе, алгоритмы взаимонезависимы. Но заранее предугадать, какой алгоритм вызовет пользователь невозможно. Поэтому приходится поддерживать сразу 2 версии объектов, что очень неудобно.
По моему, вполне хорошее решение с шаблонами. Непонятно в чём же именно заключается это «очень неудобно».
ZS>Есть ли какой-то способ или программные конструкции, позволяюшие производить вычисления над double как над float?.
Вообще, как всегда есть частные решения. Например, в x87-fpu есть пара команд fldcw и fstcw, которые позволяют менять точность вычислений прямо во время работы программы. То есть можно просто в нужный момент сказать процессору, чтобы он считал все double с точностью float. Разумеется, это поможет только если тормозят такие инструкции как, например, деление чисел (их время работы сильно зависит от точности), а если тормоза вызваны, скажем, пропускной способностью памяти, то ничего не изменится, ибо fstcw не сделает из восьми байт четыре.
Но такой путь мне кажется всё-таки не очень красивым. Ведь даже на x86 архитектуре всё больше вычислений с плавающей точкой проводится не на x87, а на sse. А с последним такой трюк не работает, так как double и float числа обрабатываются разными семействами инструкций, то есть нужно опять же поддерживать два варианта функций.
Собственно вопрос в следующем. Есть массив объектов, членами которого являются переменные типа double.
Есть алгоритмы, производящие сложные матемитические расчеты над этим объектами. Выичсления довольно ресурсоемкие, поэтому время расчета доходит до нескольких минут.
Эксперименты показали, что если в некоторых иp эти[ алгоритмов заменить double на float, то точность расчета остается на приемлемом уровне, а вот скорость расчета увеличивается примерно на 30%, что в абсолютном измерении составляет от одной до двух минут. То есть разница весьма существенная.
Проблема в том, что такой подход возможен только для части алгоритмов. Для других же алгоритмов менять double на float нельзя, так как точности float не хватает для успешного завершения расчетов (методы расчета не сходятся).
Есть ли какой-то способ или программные конструкции, позволяюшие производить вычисления над double как над float?.
Пока проблему решил через шаблоны. То есть создаются две копии объектов: float-версия и double-версия. float-версия передается в алгоритмы, которые допускают расчеты с точностью float, а double версия в остальные алгоритмы. Но при таком подходе возникает проблема синхронизации версий. В принципе, алгоритмы взаимонезависимы. Но заранее предугадать, какой алгоритм вызовет пользователь невозможно. Поэтому приходится поддерживать сразу 2 версии объектов, что очень неудобно.
Что можете посоветовать? Может быть в boost есть что-нить полезное?
Здравствуйте, watch-maker, Вы писали:
WM>Здравствуйте, ZegSoft, Вы писали:
ZS>>Пока проблему решил через шаблоны. То есть создаются две копии объектов: float-версия и double-версия. float-версия передается в алгоритмы, которые допускают расчеты с точностью float, а double версия в остальные алгоритмы. Но при таком подходе возникает проблема синхронизации версий. В принципе, алгоритмы взаимонезависимы. Но заранее предугадать, какой алгоритм вызовет пользователь невозможно. Поэтому приходится поддерживать сразу 2 версии объектов, что очень неудобно. WM>По моему, вполне хорошее решение с шаблонами. Непонятно в чём же именно заключается это «очень неудобно».
Неудобство в увеличении времени создания массивов таких объектов в два раза. И второе неудобство — это проблема синхронизации данных, хранящихся в каждой версии. Допустим алгоритм работает с float-версией. После завершения работы алгоритма нужно обновить поля double-версии, чтобы была возможность применить алгоритмы, поддерживающие только double версию. Каким образом это реализовывать? Перспектива прописывания ручками присваение полей от двух версий как-то не привлекает.
Здравствуйте, ZegSoft, Вы писали:
ZS>Неудобство в увеличении времени создания массивов таких объектов в два раза. И второе неудобство — это проблема синхронизации данных, хранящихся в каждой версии. Допустим алгоритм работает с float-версией. После завершения работы алгоритма нужно обновить поля double-версии, чтобы была возможность применить алгоритмы, поддерживающие только double версию. Каким образом это реализовывать? Перспектива прописывания ручками присваение полей от двух версий как-то не привлекает.
Например boost::ublas делает такое конвертирование автоматом. И кстати умеет биндится на разные числодробильные библиотеки.
Здравствуйте, Nuzhny, Вы писали:
N>Здравствуйте, ZegSoft, Вы писали:
ZS>>Что можете посоветовать? Может быть в boost есть что-нить полезное?
N>У меня была подобная проблема. Решилась изменением опций компилятора: использовать SSE2.
Здравствуйте, ZegSoft, Вы писали:
N>>У меня была подобная проблема. Решилась изменением опций компилятора: использовать SSE2.
ZS>А чуть подробнее можно?
MSVC: C++ -> Code generation -> Enable enhanced instruction set -> SSE2
Ну и можно: C++ -> Code generation -> Floating point model -> Fast
Здравствуйте, Nuzhny, Вы писали:
N>Здравствуйте, ZegSoft, Вы писали:
N>>>У меня была подобная проблема. Решилась изменением опций компилятора: использовать SSE2.
ZS>>А чуть подробнее можно?
N>MSVC: C++ -> Code generation -> Enable enhanced instruction set -> SSE2 N>Ну и можно: C++ -> Code generation -> Floating point model -> Fast
И на сколько это подняло производительность?? Как я понимаю, в 6-й студии такого нет?(
WM>Но такой путь мне кажется всё-таки не очень красивым. Ведь даже на x86 архитектуре всё больше вычислений с плавающей точкой проводится не на x87, а на sse. А с последним такой трюк не работает, так как double и float числа обрабатываются разными семействами инструкций, то есть нужно опять же поддерживать два варианта функций.
на ССЕ можно ускорить просто в говно.
если двойная точность нужна — то одни и те же инструкции и дабл и флоат могут посчитать. В принципе и ключик в МСВЦ это поможет сделать, а лучше всего ручками прописать.
WM>>Но такой путь мне кажется всё-таки не очень красивым. Ведь даже на x86 архитектуре всё больше вычислений с плавающей точкой проводится не на x87, а на sse. А с последним такой трюк не работает, так как double и float числа обрабатываются разными семействами инструкций, то есть нужно опять же поддерживать два варианта функций. J>на ССЕ можно ускорить просто в говно. J>если двойная точность нужна — то одни и те же инструкции и дабл и флоат могут посчитать. В принципе и ключик в МСВЦ это поможет сделать, а лучше всего ручками прописать.
WM>>Но такой путь мне кажется всё-таки не очень красивым. Ведь даже на x86 архитектуре всё больше вычислений с плавающей точкой проводится не на x87, а на sse. А с последним такой трюк не работает, так как double и float числа обрабатываются разными семействами инструкций, то есть нужно опять же поддерживать два варианта функций. J>на ССЕ можно ускорить просто в говно. J>если двойная точность нужна — то одни и те же инструкции и дабл и флоат могут посчитать. В принципе и ключик в МСВЦ это поможет сделать, а лучше всего ручками прописать.
Попробовал скомпилить с этими ключами — никакого ускорения нет.
Насколько я понимаю, вся проблема в том, что алгоритм делает не тупое "перемалывание массивов данных", а элементы массивов взаимосвязаны. Результаты расчета в элементе j зависят от результатов расчета элемента i. Насколько я понял, SSE — это что-то наподобии конвейеров? В такой постановке они не могут дать эффекта.
Здравствуйте, jakor, Вы писали:
J>если двойная точность нужна — то одни и те же инструкции и дабл и флоат могут посчитать. В принципе и ключик в МСВЦ это поможет сделать, а лучше всего ручками прописать.
Компилятор С++ от MS практически не поддерживает автоматическую векторизацию для SSE. Ощутимого ускорения от включения этого ключа не будет. Надо всё писать ручками.
Здравствуйте, ArtDenis, Вы писали:
AD>Здравствуйте, jakor, Вы писали:
J>>если двойная точность нужна — то одни и те же инструкции и дабл и флоат могут посчитать. В принципе и ключик в МСВЦ это поможет сделать, а лучше всего ручками прописать.
AD>Компилятор С++ от MS практически не поддерживает автоматическую векторизацию для SSE. Ощутимого ускорения от включения этого ключа не будет. Надо всё писать ручками.
Насколько сложные будут модификации кода?? в чем их суть? где об этом можно почитать?
Здравствуйте, ArtDenis, Вы писали:
AD>Здравствуйте, ZegSoft, Вы писали:
ZS>>...SSE — это что-то наподобии конвейеров?
AD>Одна из возможностей SSE — это параллельное выполнение нескольких однотипных операций с числами на одном ядре процессора.
Ну то есть это конвейеры получается?? Изменениея практически такие же, как и при подготовке для CUDA?? Проблема в том, что распараллелить алгоритм проблематично. Элементы массива связаны друг с другом. Результаты вычисления полей одного элемента, зависят от полей другого элемента.
Здравствуйте, ZegSoft, Вы писали:
ZS>Что можете посоветовать? Может быть в boost есть что-нить полезное?
Использовать SSE.
Но вообще вопрос интересный. Дело видимо, в загрузке-сохранении регистров, так как сами вычисления производятся для обоих типов на 80-битных регистрах.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, ZegSoft, Вы писали:
ZS>Ну то есть это конвейеры получается??
Ну смотря что назвать конвейером. По мне так — нет. Конвейер в CPU работает неявно. А для SSE нужно явно указывать операции действий с векторами чисел.
ZS>Изменениея практически такие же, как и при подготовке для CUDA??
Я не разу не использовал CUDA, но думаю что да, типа того
ZS>Проблема в том, что распараллелить алгоритм проблематично. Элементы массива связаны друг с другом. Результаты вычисления полей одного элемента, зависят от полей другого элемента.
Ну значит такой вариант ускорения не пойдёт.
Здравствуйте, ZegSoft, Вы писали:
ZS>Попробовал скомпилить с этими ключами — никакого ускорения нет. ZS>Насколько я понимаю, вся проблема в том, что алгоритм делает не тупое "перемалывание массивов данных", а элементы массивов взаимосвязаны. Результаты расчета в элементе j зависят от результатов расчета элемента i. Насколько я понял, SSE — это что-то наподобии конвейеров? В такой постановке они не могут дать эффекта.
Попробуй развернуть цикл. То есть делать инкремент индекса не на 1, а на 2. Тогда внутренность цикла у тебя немного изменится, компилятор может её более качественно раскидать по регистрам, лучше оптимизировать. Иногда такой приём помогает.
Здравствуйте, ArtDenis, Вы писали:
ZS>>Изменениея практически такие же, как и при подготовке для CUDA?? AD>Я не разу не использовал CUDA, но думаю что да, типа того
Посмотрел что такое CUDA, оказывается это немного другое, чем я ожидал. Так что изменения будут совсем не те.
Здравствуйте, Nuzhny, Вы писали:
N>Здравствуйте, ZegSoft, Вы писали:
ZS>>Попробовал скомпилить с этими ключами — никакого ускорения нет. ZS>>Насколько я понимаю, вся проблема в том, что алгоритм делает не тупое "перемалывание массивов данных", а элементы массивов взаимосвязаны. Результаты расчета в элементе j зависят от результатов расчета элемента i. Насколько я понял, SSE — это что-то наподобии конвейеров? В такой постановке они не могут дать эффекта.
N>Попробуй развернуть цикл. То есть делать инкремент индекса не на 1, а на 2. Тогда внутренность цикла у тебя немного изменится, компилятор может её более качественно раскидать по регистрам, лучше оптимизировать. Иногда такой приём помогает.
То есть теоретически разница между double и float должна быть значительно меньше 30%??
Здравствуйте, ZegSoft, Вы писали:
ZS>То есть теоретически разница между double и float должна быть значительно меньше 30%??
Трудно сказать. Исторически, с разными процессорами эта разница постоянно меняется. А вообще, надо смотреть код и дизассемблер. И ещё: перейди на компилятор посовременнее (6-й студии много-много лет). Разницу точно заметишь.
Здравствуйте, Nuzhny, Вы писали:
N>Здравствуйте, ZegSoft, Вы писали:
ZS>>То есть теоретически разница между double и float должна быть значительно меньше 30%??
N>Трудно сказать. Исторически, с разными процессорами эта разница постоянно меняется. А вообще, надо смотреть код и дизассемблер. И ещё: перейди на компилятор посовременнее (6-й студии много-много лет). Разницу точно заметишь.
Да я знаю, что 6-й компилятор уже сильно устарел. Просто мне проект достался "по-наследству" от предыдущих разработчиков, и перевести его на новую студию не так-то просто. В нем используются старые либы, которые в новой студии не компилятся. Поэтому переход на новую студию требует существенных затрат времени.
Здравствуйте, ZegSoft, Вы писали:
ZS>Здравствуйте, Nuzhny, Вы писали:
N>>Здравствуйте, ZegSoft, Вы писали:
ZS>>>То есть теоретически разница между double и float должна быть значительно меньше 30%??
N>>Трудно сказать. Исторически, с разными процессорами эта разница постоянно меняется. А вообще, надо смотреть код и дизассемблер. И ещё: перейди на компилятор посовременнее (6-й студии много-много лет). Разницу точно заметишь.
ZS>Да я знаю, что 6-й компилятор уже сильно устарел. Просто мне проект достался "по-наследству" от предыдущих разработчиков, и перевести его на новую студию не так-то просто. В нем используются старые либы, которые в новой студии не компилятся. Поэтому переход на новую студию требует существенных затрат времени.
Переведи в ddl только критический код , изолируй числодробилку. Переход на хороший компилятор может дать прирост до 2х -4х раз свободно.