Сравнительный анализ этого класса:
struct Sieve {
std::vector<bool> isPrime;
Sieve (int n = 1) {
isPrime.assign (n+1, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i <= (int)sqrt((double)n); ++i)
if (isPrime[i])
for (int j = i*i; j <= n; j += i)
isPrime[j] = false;
}
};
Я получаю более 3-кратную худшую производительность (процессорное время) с 64-битной бинарной или 32-разрядной версией (выпускной сборкой) при вызове конструктора для большого числа, например.
Sieve s(100000000);
Я тестировал sizeof(bool)
, и для обеих версий это 1
.
Когда я заменяю vector<bool>
на vector<char>
, производительность становится одинаковой для 64-разрядных и 32-разрядных версий. Почему это?
Вот время выполнения для S(100000000)
(режим выпуска, 32-разрядный первый, 64-битный второй)):
vector<bool>
0,97 с 3,12 с
vector<char>
0,99 с 0,99 с
vector<int>
1,57 с 1,59 с
Я также провел тест на чувствительность с VS2010 (вызванный ответом Wouter Huysentruit), который произвел 0,98 с 0,88. Итак, что-то не так с реализацией VS2012.
Я отправил отчет об ошибке в Microsoft Connect
ИЗМЕНИТЬ
Многие ответы ниже содержат комментарии о недостатках использования int
для индексирования. Это может быть правдой, но даже сам Великий Волшебник использует стандартный for (int i = 0; i < v.size(); ++i)
в своих книгах, поэтому такой шаблон не должен нести существенного штрафа за производительность. Кроме того, эта проблема была поднята во время конференции Going Native 2013, и председательствующая группа гуру С++ прокомментировала их ранние рекомендации по использованию size_t
для индексирования и как возвращаемый тип size()
как ошибку. Они сказали: "Мы сожалеем, мы были молоды..."
Название этого вопроса может быть перефразировано до: Более 3-кратного снижения производительности этого кода при обновлении с VS2010 до VS2012.
ИЗМЕНИТЬ
Я сделал грубую попытку найти выравнивание памяти индексов i
и j
и обнаружил, что эта инструментальная версия:
struct Sieve {
vector<bool> isPrime;
Sieve (int n = 1) {
isPrime.assign (n+1, true);
isPrime[0] = isPrime[1] = false;
for (int i = 2; i <= sqrt((double)n); ++i) {
if (i == 17) cout << ((int)&i)%16 << endl;
if (isPrime[i])
for (int j = i*i; j <= n; j += i) {
if (j == 4) cout << ((int)&j)%16 << endl;
isPrime[j] = false;
}
}
}
};
автоматически запускается быстро (только на 10% медленнее, чем 32-разрядная версия). Это и производительность VS2010 затрудняют принятие теории оптимизатора, имеющей неотъемлемые проблемы с индексами int
вместо size_t
.