Я только что обнаружил, что стоимость косвенного обращения примерно в 3 раза превышает умножение числа с плавающей запятой!
Чего и следовало ожидать? Мой тест неверен?
Задний план
После того, как я прочитал Насколько косвенность указателя влияет на эффективность?, я стал паника по поводу косвенных затрат.
Прохождение косвенного указателя может быть намного медленнее из-за того, как работает современный процессор.
Прежде чем я преждевременно оптимизирую свой реальный код, я хочу убедиться, что он действительно стоит столько, сколько я опасаюсь.
Я делаю некоторые трюки, чтобы найти грубое число (3x), как показано ниже:
Шаг 1
- Test1: без косвенного обращения -> что-то вычислить
- Test2: Косвенность -> что-то вычислить (то же самое)
Я обнаружил, что Test2 занимает больше времени, чем Test1.
Здесь нет ничего удивительного.
Шаг 2
- Test1: без косвенных действий -> вычислить что-то дорогое
- Test2 : Indirection -> вычислить что-то дешевое
Я пытаюсь постепенно изменить свой код в calculate something expensive
, чтобы сделать его более дорогим, чтобы стоимость Test была примерно одинаковой.
Результат
Наконец, я обнаружил, что одна из возможных функций, позволяющих обоим тестам использовать одинаковое количество времени (т.е. безубыточность), это:
- Test1: без косвенного обращения -> возврат
float*float*...
3 раза - Test2: Косвенность -> просто вернуть
float
Вот мой тестовый пример (демонстрация ideone): -
class C{
public: float hello;
public: float hello2s[10];
public: C(){
hello=((double) rand() / (RAND_MAX))*10;
for(int n=0;n<10;n++){
hello2s[n]= ((double) rand() / (RAND_MAX))*10;
}
}
public: float calculateCheap(){
return hello;
}
public: float calculateExpensive(){
float result=1;
result=hello2s[0]*hello2s[1]*hello2s[2]*hello2s[3]*hello2s[4];
return result;
}
};
Вот основное:-
int main(){
const int numTest=10000;
C d[numTest];
C* e[numTest];
for(int n=0;n<numTest;n++){
d[n]=C();
e[n]=new C();
}
float accu=0;
auto t1= std::chrono::system_clock::now();
for(int n=0;n<numTest;n++){
accu+=d[n].calculateExpensive(); //direct call
}
auto t2= std::chrono::system_clock::now();
for(int n=0;n<numTest;n++){
accu+=e[n]->calculateCheap(); //indirect call
}
auto t3= std::chrono::system_clock::now();
std::cout<<"direct call time ="<<(t2-t1).count()<<std::endl;
std::cout<<"indirect call time ="<<(t3-t2).count()<<std::endl;
std::cout<<"print to disable compiler cheat="<<accu<<std::endl;
}
Время прямого звонка и Время непрямого звонка настроены так, чтобы они были аналогичны указанным выше (через редактирование calculateExpensive
).
Заключение
Косвенная стоимость = 3-кратное умножение с плавающей запятой.
На моем рабочем столе (Visual Studio 2015 с -O2) она равна 7-кратному.
Вопрос
Следует ли ожидать, что стоимость косвенного умножения примерно в 3 раза больше, чем умножение с плавающей запятой?
Если нет, то почему мой тест неверен?
(Спасибо enhzflep за предложение улучшения, оно отредактировано.)
public:
. Вы также теряете память с помощью этого оператораnew
. Если вы хотите использовать C++, я предлагаю вам забыть все, что вы знали о Java. - person   schedule 25.05.2017a*b*c*d*e*f*g*h*i*j*k*l*m*n
- person enhzflep   schedule 25.05.2017new C()
100 000 раз. Это создаст 100 000 экземпляров C, разбросанных по всей вашей памяти. Выделение в виде массива (новый C[numTest]), скорее всего, приведет к совершенно другим результатам. Небольшое дополнение: такая инициализацияC d[numTest] = {};
вызовет конструктор для каждого отдельного элемента. - person HeroicKatora   schedule 25.05.2017