2013-08-03 7 views
1

Я написал небольшую программу бенчмаркинга, чтобы проверить некоторые способы доступа к данным, хранящимся в векторе. Я использовал tww вложенные для цикла, чтобы встретить A) создать ссылку на объект вектора для каждой итерации первого цикла и использовать эту ссылку во втором для цикла B) создать указатель, сохранить в этом указателе ссылку к объекту вектора для каждой итерации первого цикла и использовать этот указатель в секунду для контура C) доступ непосредственно вектор объекта с [] оператор D) использовать автоматический & в первом циклеДоступ к векторным элементам внутри цикла for, сравнение некоторых способов

Такая пара вложенных циклов была сама вложена в другой цикл вместе с функцией синхронизации. Выполнение теста несколько раз, при этом цикл for, идущий от 0 до 100, получил те же результаты синхронизации для всех этих методов, всегда около 0.150 секунд, с колебанием 0,02%.

Мои вопросы:

1) мой тест правильно?

2) есть ли какая-то оптимизация/другой подход, который я пропустил, что может быть быстрее?

Вот мой код

#include <iostream> 
#include <chrono> 
#include <ratio> 
#include <ctime> 
#include <vector> 
using namespace std; 
using namespace std::chrono; 


struct my_struct{ 

    vector<float> data; 

    my_struct(int N, float x){ 

     for(int i=0;i<N;i++){ 
      data.push_back(cos(x+i)); 
     } 
    } 

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

}; 

int main(){ 
int N=100; 
vector<my_struct> stuff; 
for(int k=0; k<N; ++k){ 
    stuff.push_back(my_struct(100,sin(k))); 
} 

vector<duration<double>> results_t1,results_t2,results_t3,results_t4; 
high_resolution_clock::time_point t1 = high_resolution_clock::now(); 
for(int k=0; k<N; ++k){ 
    int which=0; //this is used to choose what method of access will be used 
    switch(which){ 
     case 0:{ //pointer 
      my_struct * thing=NULL; 
      for(int i=0; i<N;++i){ 
       high_resolution_clock::time_point t2 = high_resolution_clock::now(); 
       for(int j=0; j<N;++j){ 
        thing =&stuff[j]; 
        for(int jj=0; jj<N;++jj) 
         thing->work(); 
       } 
       duration<double> time_span = duration_cast<duration<double>>(t2 - t1); 
       results_t1.push_back(time_span); 
       t1=t2; 
      } 
      break; 
     } 

     case 1:{ //direct access 
      for(int i=0; i<N;++i){ 
       high_resolution_clock::time_point t2 = high_resolution_clock::now(); 
       for(int j=0; j<N;++j){ 
        for(int jj=0; jj<N;++jj) 
         stuff[j].work(); 
       } 
       duration<double> time_span = duration_cast<duration<double>>(t2 - t1); 
       results_t2.push_back(time_span); 
       t1=t2; 
      } 
      break; 
     } 

     case 2:{ //auto reference 
      for(int i=0; i<N;++i){ 
       high_resolution_clock::time_point t2 = high_resolution_clock::now(); 
       for(auto& temp : stuff){ 
        for(int jj=0; jj<N;++jj) 
         temp.work(); 
       } 
       duration<double> time_span = duration_cast<duration<double>>(t2 - t1); 
       results_t3.push_back(time_span); 
       t1=t2; 
      } 
      break; 
     } 
     case 3:{ //reference 
      for(int i=0; i<N;++i){ 
       high_resolution_clock::time_point t2 = high_resolution_clock::now(); 
       for(int j=0; j<N;++j){ 
        my_struct & temp =stuff[j]; 
        for(int jj=0; jj<N;++jj) 
         temp.work(); 
       } 
       duration<double> time_span = duration_cast<duration<double>>(t2 - t1); 
       results_t4.push_back(time_span); 
       t1=t2; 
      } 
      break; 
     } 

    } 
} 
double temp=0; 
for(auto& t : results_t1){ 
temp+=t.count(); 
} 
temp=temp/N; 
std::cout << "pointer " << temp << " seconds."; 
std::cout << std::endl; 

temp=0.0; 
for(auto& t : results_t2){ 
temp+=t.count(); 
} 
temp=temp/N; 
std::cout << "direct " << temp << " seconds."; 
std::cout << std::endl; 

temp=0.0; 
for(auto& t : results_t3){ 
temp+=t.count(); 
} 
temp=temp/N; 
std::cout << "auto reference " << temp << " seconds."; 
std::cout << std::endl; 

    temp=0.0; 
for(auto& t : results_t4){ 
temp+=t.count(); 
} 
temp=temp/N; 
std::cout << "reference " << temp << " seconds."; 
std::cout << std::endl; 

cin.get(); 

return 0; 
} 
+0

Тег для 'оптимизации', также если вам нужны хорошие ответы. –

+0

@UchiaItachi Ваш комментарий, кажется, подразумевает, что только вопросы оптимизации получат хорошие ответы;) – Borgleader

+0

@Borgleader: Если вы хотите получить хорошие ответы * об оптимизации *, пометка с помощью [tag: optimization] действительно кажется очевидной задачей. –

ответ

0

Я бы ожидать аналогичных результатов для каждого из методов. Время не потрачено на циклы, оно будет потрачено на математические функции sin и cos. Оптимизации компилятора, такие как инварианты цикла, будут делать case 1 так же быстро, как и другие циклы, и нет ничего, что можно было бы выбрать между теми, кто относится к производительности.

Для стиля предпочитайте держать его простым, что поможет в ремонте и уменьшит количество ошибок в конечном итоге. Я бы пошел с case 1 прямым доступом на этой основе. Представление временных рядов, чтобы попытаться помочь компилятору, на самом деле не поможет компилятору.

+0

Спасибо, «Представление временных рядов, чтобы помочь компилятору на самом деле не помочь компилятору», это очень хорошая парадигма для запоминания. – darius

Смежные вопросы