Странная проблема с производительностью - PullRequest
2 голосов
/ 30 октября 2009

У меня есть контейнер, похожий на этот.

template <typename Nat, typename Elt>
class NatMap {
 public:
  Elt& operator[] (Nat nat) { 
    return tab [nat.GetRaw()];
  }
 private:
  Elt tab [Nat::kBound];
};

Я хотел отменить требование для Elt иметь конструктор по умолчанию:

template <typename Nat, typename Elt>
class NatMap {
 public:
  Elt& operator[] (Nat nat) { 
    return ((Elt*)tab) [nat.GetRaw()];
  }
 private:
  char tab [Nat::kBound * sizeof(Elt)];
};

Я использую g ++ - 4.3, и этот код работает на 25% медленнее в моем приложении, чем предыдущее. К сожалению, замедление не проявляется в синтетическом тесте. Я предполагаю, что это что-то вроде оптимизации компилятора, псевдонимов, выравнивания или подобных вещей.

Что я должен сделать, чтобы вернуть свое выступление? (без необходимости использования конструктора по умолчанию)

Обновление:

Только что я попробовал новый g ++ - 4.4, и он дал мне следующее предупреждение для последнего кода:

dereferencing pointer '<anonymous>' does break strict-aliasing rules

Ответы [ 2 ]

1 голос
/ 03 ноября 2009

Возможно, у вас проблемы с выравниванием. Если Elt имеет некоторый размер, отличный от собственного типа выравнивания, то выделение его с помощью размещения в массиве символов может потребовать большого количества выровненных чтений, которые вы не увидите, когда компилятор выровняет его для вас. Или вы можете столкнуться с проблемой, называемой хранилищем загрузки-загрузки, которая проявляется в некоторых процессорах, когда они записывают значение в память, а затем сразу же читают его обратно; в этих процессорах это может быть остановка, пока идет конвейер.

Или это может быть что-то совершенно другое, генерация патологического кода GCC.

К сожалению, трассировки стека не помогают отследить ни одну из этих проблем, поскольку они просто выглядят как операция загрузки (lw, lb и т. Д.), Которая занимает сорок циклов вместо одного. Задержка в микрокоде внутри процессора, а не в коде x86, который вы написали. Но, глядя на сборку с параметром командной строки -S, вы можете выяснить, что на самом деле генерирует компилятор, и как он отличается между вашими двумя реализациями. Возможно, в одной из версий возникла какая-то плохая операция.

0 голосов
/ 30 октября 2009

Небольшое предложение: вместо того, чтобы пытаться делать обоснованные предположения, например, если оптимизации компилятора отличаются, вы можете либо пошагово выполнить это, либо узнать с помощью этого неортодоксального метода .

...