Может ли простое разыменование многомерного массива быть медленным? - PullRequest
0 голосов
/ 14 ноября 2018

Я изо всех сил пытаюсь понять вывод, который я получаю от gprof .

У меня есть простой класс-оболочка для двумерного массива, который должен быть непрерывным в памяти.

Его конструктор и метод, который я использую для доступа к значениям:

Array2d::Array2d(int size, double initialValue)
: mSize(size) {
    data = new double *[size];
    data[0] = new double[size * size];

    for (int i = 1; i < size; ++i) {
        data[i] = data[0] + i * size;
    }

    for (int i = 0; i < size; ++i) {
        for (int j = 0; j < size; ++j) {
            data[i][j] = initialValue;
        }
    }
}


double &Array2d::operator()(int i, int j) {
    return data[i][j];
}

В числовом коде, над которым я работаю, это один вывод, полученный из gprof:

  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ms/call  ms/call  name    
 49.33     34.80    34.80 43507867293     0.00     0.00  Array2d::operator()(int, int)
 18.05     47.53    12.73                             jacobi(Array2d&, Array2d&, int, int, double, double, double, int)

Я удивлен, увидев, что почти 50% времени работы тратится на доступ к значениям из массива.

Этот класс Array2d заменил использование std::vector<double>, что было намного быстрее.

Что я здесь не понимаю?

1 Ответ

0 голосов
/ 14 ноября 2018

Я удивлен, увидев, что почти 50% времени уходит доступ к значениям из массива.

Мы не можем много говорить об этом, не увидев ваш код. Можно легко написать код с более высоким процентом одного вызова. Рассмотрим

int main() { 
    while(true){ 
        foo(); 
    }
}

Профилировщик скажет вам, что около 100% времени выполнения тратится в foo. Означает ли это, что foo медленно? Нет, мы не знаем.

Проценты, которые вы получаете от профилировщика, скорее подсказывают вам, где находятся горячие точки в вашем коде. Если вы знаете, что 50% времени тратится на один вызов конкретной функции, то вы знаете, что это хороший способ улучшить производительность. Если вы оптимизируете этот вызов одной функции, вы сможете добиться ускорения до x2 (см. закон Амдалса ).

С другой стороны, функция, которая использует только 0,1% от общего времени выполнения, может быть выполнена в 1000 раз быстрее без значительного влияния на общее время выполнения.

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

...