Что лучше использовать в высокопроизводительных вычислениях: передавать структуру данных в функцию или набор переменных?

Представьте, что у меня есть структура, содержащая набор переменных, описывающих объект, который в моем случае является сеткой. Мне было интересно, если у меня есть функция, которая использует только подмножество сетки, есть ли какие-либо различия в производительности в двух вариантах функций computational_kernel ниже. Ядра одинаковы, за исключением того, что то, в которое передается структура, должно извлекать itot, jtot и ktot из структуры перед выполнением тяжелых вычислений.

struct Grid
{
    int itot;
    int jtot;
    int ktot;

    int not_used_in_kernel1;
    int not_used_in_kernel2;
    int not_used_in_kernel3;
    int not_used_in_kernel4;
}
Grid grid;

// Code that initializes the grid values...

// Variant 1
computational_kernel(double* array1, double* array2,
                     const int itot, const int jtot, const int ktot);

// Variant 2
computational_kernel(double* array1, double* array2,
                     const Grid& grid);

person Chiel    schedule 20.01.2015    source источник
comment
Вы проводили бенчмаркинг?   -  person Ginden    schedule 20.01.2015
comment
Это очень сильно зависит от компилятора, версии компилятора, флагов оптимизации, модели и архитектуры процессора и, возможно, других вещей.   -  person Some programmer dude    schedule 20.01.2015
comment
Кроме того, технически говоря, вы не передаете структуру во второй версии, вы передаете ссылку на структуру.   -  person Some programmer dude    schedule 20.01.2015
comment
@Ginden Я не проверял это, мне просто было любопытно, имеет ли разыменование сложной структуры затраты, если вы используете только несколько переменных, которые являются частью этой структуры.   -  person Chiel    schedule 20.01.2015


Ответы (3)


Если computational_kernel — это функция, которая выполняет много внутренней работы и вызывается несколько раз, разница между двумя версиями бесконечно мала. Вторая версия имеет только дополнительную стоимость разыменования 3 значений, чем остальные идентичны, и вам, по-видимому, все равно придется выполнять такое разыменование перед вызовом первой версии.

Я бы определенно использовал вторую форму из соображений компактности: если вы определяете объектно-ориентированные структуры данных, используйте их таким образом (лучшая инкапсуляция).

person Emerald Weapon    schedule 20.01.2015
comment
Если при передаче структуры по ссылке нет других затрат по сравнению с передачей целого числа по значению, то я думаю, что нахожу это наиболее разумным ответом. Является ли разыменование структуры таким же дешевым, как копирование целых чисел? - person Chiel; 20.01.2015

Я думаю, что передача структуры лучше для обслуживания кода. если вы добавите новые поля в свою сетку, вам нужно будет только изменить функцию. Но передавая набор переменных, вам придется менять функцию и каждый вызов функции.

person jmonrio    schedule 20.01.2015
comment
Хорошие соображения, хотя и уравновешивают упомянутое вами преимущество, прохождение Grid& делает computational_kernel бесполезным, если у вас нет Grid. - person Tony Delroy; 20.01.2015
comment
@TonyD ... что на самом деле хорошо! Вы минимизируете риск вызова computational_kernel с неправильными входными данными. - person Emerald Weapon; 20.01.2015
comment
@claudv: реализация варианта 2, которая вызывает вариант 1, обеспечит удобство и гарантии ввода, о которых вы упоминаете, хотя и с небольшими затратами времени выполнения, если обе функции не будут встроенными, сохраняя при этом повышенную возможность повторного использования и тестируемость варианта 1. В любом случае, дьявол кроется в деталях... сколько потенциального повторного использования может быть, что еще есть в Grid, например. болезненный для инициализации или дорогостоящий в памяти и может быть пропущен для тестовых случаев и т.д.. - person Tony Delroy; 20.01.2015
comment
@TonyD Итак, вы имеете в виду использование варианта 2 в качестве оболочки для варианта 1 и оставить оба доступны. Конечно! - person Emerald Weapon; 20.01.2015
comment
Я не согласен с этим ответом, потому что, хотя Grid может измениться, мне не нужно передавать этим ядрам дополнительные переменные, кроме той, которую я использую. - person Chiel; 20.01.2015

Я бы сказал, что передача ссылки на структуру, как во втором варианте, вероятно, будет более эффективной с точки зрения производительности. В первом варианте вызывающему абоненту нужно будет поместить 3 переменные int в стек, а во втором варианте все, что ему нужно поместить, — это ссылку (указатель) на структуру и выполнить там действия. Влияние на производительность, конечно, больше, если вам нужно передать более 3 переменных.

person smichak    schedule 20.01.2015
comment
нужно поместить 3 переменные int в стек - не обязательно, некоторые компиляторы/ABI упаковывают много аргументов в регистры, прежде чем вернуться в стек, и в этом случае передача их в регистры никогда не должна быть медленнее, чем передача ссылка на сетку (при условии, что вызываемая функция гарантированно использует 3 поля). При передаче ссылки на сетку вызываемой функции может потребоваться выполнить чтение полей из кэша/памяти, даже если у вызывающего объекта были эти значения в регистрах (при условии, что вызываемая функция не встроена). - person Tony Delroy; 20.01.2015