· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.ZEN —› Производительность STL

Посл.отвђт Сообщенiе


Дата: Апр 2, 2004 22:09:10

Истинным ассемблерщикам (на каком бы языке они не писали) всегда любопытна производительность того или иного клочка кода. Речь в данном топике пойдет об STL. Примеры взяты из "Thinking in C++" Bruce Ekkel.
Сравнивался hash_map с map. Сравнивал на Windows и Solaris. Компилировал Visual Studio .NET 2003 и g++. Врубил всю оптимизацию, до которой только смог додуматься и дотянуться.

Код:
//: C20:MapVsHashMap.cpp
// The hash_map header is not part of the 
// Standard C++ STL. It is an extension that 
// is only available as part of the SGI STL:
#include <hash_map> 
#include <iostream>
#include <map>
#include <ctime>
using namespace std;

int main(){
  hash_map<int, int> hm;
  map<int, int> m;
  clock_t ticks = clock();
  for(int i = 0; i < 100; i++)
    for(int j = 0; j < 1000; j++)
      m.insert(make_pair(j,j));
  cout << "map insertions: " 
    << clock() - ticks << endl;
  ticks = clock();
  for(int i = 0; i < 100; i++)
    for(int j = 0; j < 1000; j++)
      hm.insert(make_pair(j,j));
  cout << "hash_map insertions: " 
    << clock() - ticks << endl;
  ticks = clock();
  for(int i = 0; i < 100; i++)
    for(int j = 0; j < 1000; j++)
      m[j];
  cout << "map::operator[] lookups: " 
    << clock() - ticks << endl;
  ticks = clock();
  for(int i = 0; i < 100; i++)
    for(int j = 0; j < 1000; j++)
      hm[j];
  cout << "hash_map::operator[] lookups: "
    << clock() - ticks << endl;
  ticks = clock();
  for(int i = 0; i < 100; i++)
    for(int j = 0; j < 1000; j++)
      m.find(j);
  cout << "map::find() lookups: "
    << clock() - ticks << endl;
  ticks = clock();
  for(int i = 0; i < 100; i++)
    for(int j = 0; j < 1000; j++)
      hm.find(j);
  cout << "hash_map::find() lookups: " 
    << clock() - ticks << endl;
} ///:~ 


Результат на Solaris (SPARC v9):

map insertions: 170000
hash_map insertions: 80000
map::operator[] lookups: 130000
hash_map::operator[] lookups: 50000
map::find() lookups: 120000
hash_map::find() lookups: 40000

Результат на Windows (P4):

map insertions: 15
hash_map insertions: 0
map::operator[] lookups: 16
hash_map::operator[] lookups: 0
map::find() lookups: 0
hash_map::find() lookups: 0

Результат в миллисекундах. Хи-хи, на солярные результаты сравнительно с виндой особо внимания не обращайте. У нас особые солярные машины 8-)
А вообще, кто теперь скажет, что hash_map медленнее?

Код по сравнению других STL-контейнеров:
//: C07:SequencePerformance.cpp
// Comparing the performance of the basic
// sequence containers for various operations
//{L} ../TestSuite/Test
#include <vector>
#include <queue>
#include <list>
#include <iostream>
#include <string>
#include <typeinfo>
#include <ctime>
#include <cstdlib>
using namespace std;

class FixedSize {
int x[20];
// Automatic generation of default constructor,
// copy-constructor and operator=
} fs;

template<class Cont>
struct InsertBack {
void operator()(Cont& c, long count) {
for(long i = 0; i < count; i++)
      c.push_back(fs);
  }
char* testName() { return "InsertBack"; }
};

template<class Cont>
struct InsertFront {
void operator()(Cont& c, long count) {
long cnt = count * 10;
for(long i = 0; i < cnt; i++)
      c.push_front(fs);
  }  
char* testName() { return "InsertFront"; }
};

template<class Cont>
struct InsertMiddle {
void operator()(Cont& c, long count) {
typename Cont::iterator it;
long cnt = count / 10;
for(long i = 0; i < cnt; i++) {
// Must get the iterator every time to keep
// from causing an access violation with
// vector. Increment it to put it in the
// middle of the container:
      it = c.begin();
      it++;
      c.insert(it, fs);
    }
  }
char* testName() { return "InsertMiddle"; }
};

template<class Cont>
struct RandomAccess { // Not for list
void operator()(Cont& c, long count) {
int sz = c.size();
long cnt = count * 100;
for(long i = 0; i < cnt; i++)
      c[rand() % sz];
  }
char* testName() { return "RandomAccess"; }
};

template<class Cont>
struct Traversal {
void operator()(Cont& c, long count) {
long cnt = count / 100;
for(long i = 0; i < cnt; i++) {
typename Cont::iterator it = c.begin(),
        end = c.end();
while(it != end) it++;
    }
  }
char* testName() { return "Traversal"; }
};

template<class Cont>
struct Swap {
void operator()(Cont& c, long count) {
int middle = c.size() / 2;
typename Cont::iterator it = c.begin(), 
      mid = c.begin();
    it++; // Put it in the middle
for(int x = 0; x < middle + 1; x++)
      mid++;
long cnt = count * 10;
for(long i = 0; i < cnt; i++)
      swap(*it, *mid);
  }
char* testName() { return "Swap"; }
};

template<class Cont>
struct RemoveMiddle {
void operator()(Cont& c, long count) {
long cnt = count / 10;
if(cnt > c.size()) {
      cout << "RemoveMiddle: not enough elements"
        << endl;
return;
    }
for(long i = 0; i < cnt; i++) {
typename Cont::iterator it = c.begin();
      it++;
      c.erase(it);
    }
  }
char* testName() { return "RemoveMiddle"; }
};

template<class Cont>
struct RemoveBack {
void operator()(Cont& c, long count) {
long cnt = count * 10;
if(cnt > c.size()) {
      cout << "RemoveBack: not enough elements"
        << endl;
return;
    }
for(long i = 0; i < cnt; i++)
      c.pop_back();
  }
char* testName() { return "RemoveBack"; }
};

template<class Op, class Container>
void measureTime(Op f, Container& c, long count){
  string id(typeid(f).name());
bool Deque = id.find("deque") != string::npos;
bool List = id.find("list") != string::npos;
bool Vector = id.find("vector") !=string::npos;
  string cont = Deque ? "deque" : List ? "list" 
    : Vector? "vector" : "unknown";
  cout << f.testName() << " for " << cont << ": ";
// Standard C library CPU ticks:
  clock_t ticks = clock();
  f(c, count); // Run the test
  ticks = clock() - ticks;
  cout << ticks << endl;
}

typedef deque<FixedSize> DF;
typedef list<FixedSize> LF;
typedef vector<FixedSize> VF;

int main(int argc, char* argv[]) {
  srand(time(0));
long count = 1000;
if(argc >= 2) count = atoi(argv[1]);
  DF deq;
  LF lst;
  VF vec, vecres;
  vecres.reserve(count); // Preallocate storage
  measureTime(InsertBack<VF>(), vec, count);
  measureTime(InsertBack<VF>(), vecres, count);
  measureTime(InsertBack<DF>(), deq, count);
  measureTime(InsertBack<LF>(), lst, count);
// Can't push_front() with a vector:
//! measureTime(InsertFront<VF>(), vec, count);
  measureTime(InsertFront<DF>(), deq, count);
  measureTime(InsertFront<LF>(), lst, count);
  measureTime(InsertMiddle<VF>(), vec, count);
  measureTime(InsertMiddle<DF>(), deq, count);
  measureTime(InsertMiddle<LF>(), lst, count);
  measureTime(RandomAccess<VF>(), vec, count);
  measureTime(RandomAccess<DF>(), deq, count);
// Can't operator[] with a list:
//! measureTime(RandomAccess<LF>(), lst, count);
  measureTime(Traversal<VF>(), vec, count);
  measureTime(Traversal<DF>(), deq, count);
  measureTime(Traversal<LF>(), lst, count);
  measureTime(Swap<VF>(), vec, count);
  measureTime(Swap<DF>(), deq, count);
  measureTime(Swap<LF>(), lst, count);
  measureTime(RemoveMiddle<VF>(), vec, count);
  measureTime(RemoveMiddle<DF>(), deq, count);
  measureTime(RemoveMiddle<LF>(), lst, count);
  vec.resize(vec.size() * 10); // Make it bigger
  measureTime(RemoveBack<VF>(), vec, count);
  measureTime(RemoveBack<DF>(), deq, count);
  measureTime(RemoveBack<LF>(), lst, count);
} ///:~


Результат под Windows (P4):

InsertBack for vector: 0
InsertBack for vector: 0
InsertBack for deque: 0
InsertBack for list: 0
InsertFront for deque: 0
InsertFront for list: 15
InsertMiddle for vector: 0
InsertMiddle for deque: 0
InsertMiddle for list: 0
RandomAccess for vector: 0
RandomAccess for deque: 0
Traversal for vector: 0
Traversal for deque: 0
Traversal for list: 0
Swap for vector: 0
Swap for deque: 0
Swap for list: 0
RemoveMiddle for vector: 15
RemoveMiddle for deque: 0
RemoveMiddle for list: 0
RemoveBack for vector: 0
RemoveBack for deque: 0
RemoveBack for list: 0


Дата: Апр 2, 2004 22:16:11 · Поправил: volodya

Пардон, в последнем случае чувствительности счетчика оказалось маловато. Увеличил размер.
Имеем:

InsertBack for vector: 15
InsertBack for vector: 0
InsertBack for deque: 0
InsertBack for list: 0
InsertFront for deque: 47
InsertFront for list: 47
InsertMiddle for vector: 1094
InsertMiddle for deque: 0
InsertMiddle for list: 0
RandomAccess for vector: 15
RandomAccess for deque: 32
Traversal for vector: 0
Traversal for deque: 15
Traversal for list: 610
Swap for vector: 15
Swap for deque: 0
Swap for list: 16
RemoveMiddle for vector: 1140
RemoveMiddle for deque: 0
RemoveMiddle for list: 0
RemoveBack for vector: 0
RemoveBack for deque: 0
RemoveBack for list: 31


Дата: Апр 5, 2004 16:37:14

....я почти был в этом уверен, эх, лучше перечитаю Криса Касперски


Дата: Апр 5, 2004 18:27:15

У Криса я замечаю тенденцию писать то, в чем он иногда не слишком хорошо разбирается. Хотя все так делают, но он это делает с вышки, как в том анекдоте...


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.045