This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: penalty for member functions?


> > Is there a general runtime penalty for object oriented programing?
> > (May be due to shortage of registers?)
> 
> Without a detailed analysis, it is hard to tell what the problem is.
> Possible causes are:
> 
> - access to the virtual table (for virtual calls)
not in my case

> - the need to pass an implicit argument to each function (this)
> - invocation of implicit functions (such as ctors and dtors)
not in my case

> - optimization problems
> 
so it must be passing the this pointer or optimization.
I did the same tests on a Pentium II and on a SPARCstation-20, but there
the difference between global function and member function is just 10% (Pentium
II) and 16% (Sparc). The original test was made on a Mobile Pentium MMX.

I append the code below.

#include <stdio.h>
#include <sys/resource.h>

// singly linked list, stripped down for test:

struct slink { // base class for singly linked lists
  slink* next;
  inline slink() : next(0) {}
};

template <class L>
class list_base {
  L* tail; // tail is the last element of the list
public:
  inline list_base()     : tail(0) { // constructor, empty list
  }
  inline void append(L* a) {
    if (tail) {
      a->next = tail->next;
      tail    = tail->next = a;
    }
    else tail = a->next = a;
  }
  inline void rotate() {
    if (tail) tail = tail->next;
  }
  inline L* first() const { return tail ? tail->next : (L*) 0; }
  inline L* last()  const { return tail;}
};

template <class T, class L>
class islist : private list_base<L> {
  int elements;
public:
  inline islist() : elements(0) { // constructor
  }
  inline void append(const T* a) {
    list_base<L>::append((T*)a);
    elements++;
  }
  inline T* first() {return (T*) list_base<L>::first();}
  inline T* last()  {return (T*) list_base<L>::last();}
  inline void rotate() { list_base<L>::rotate();}
};

// cpu time measurement
class Timer {
  double last_cpu;	// msec same at last call
public:
  inline Timer () : last_cpu(get_cpu()) {
  };
  inline double get_cpu() { // cpu-time in milliseconds
    rusage usage;
    getrusage(RUSAGE_SELF,&usage);
    return usage.ru_utime.tv_sec*1000.0 + usage.ru_utime.tv_usec/1000.0;
  }
  inline double used_time(const char* msg) {
    // time since last call in seconds
    double now  = get_cpu();
    double diff = (now - last_cpu)*0.001;
    last_cpu = now;
    if (msg) printf("%s %.3f\n",msg,diff);
    return diff;
  }
}; // Timer


class Node : public slink {
public:
  int   pot;
};

class Edge : public slink {
public:
  Node* head;
  Node* tail;
  int cost;
  int flow;
  inline Edge(Node* v, Node* w) : head(w), tail(v) {
  }
  inline int reduced_cost() const {
    return cost - tail->pot + head->pot;
  }
};


int n =  20;       // number of nodes
int m = 100;       // number of edges
int l = 100000000; // number of iterations
  
/******************* flat version *********************/

islist<Node,slink>  nodes;
islist<Edge,slink>  edges;

void init() {
  // make list of nodes:
  for (int i = 0; i < n; i++) {
    nodes.append(new Node);
  }
  // make list of edges:
  for (int i = 0; i < m; i++) {
    edges.append(new Edge(nodes.first(),nodes.last()));
    nodes.rotate();
  }
} // init

Edge* e = 0;
int   c = 0;

void loop() {
  Timer t;
  for (int i = 0; i < l; i++) {
    e = edges.first();
    c = e->reduced_cost();
    edges.rotate();
  }
  t.used_time("flat loop");
}

/*************************** OO version *****************/

class Foo {
public:
  Edge* e;
  int   c;
  islist<Node,slink>  nodes;
  islist<Edge,slink>  edges;
  void init();
  void loop();
};

void Foo::init() {
  // make list of nodes:
  for (int i = 0; i < n; i++) {
    nodes.append(new Node);
  }
  // make list of edges:
  for (int i = 0; i < m; i++) {
    edges.append(new Edge(nodes.first(),nodes.last()));
    nodes.rotate();
  }
}

void Foo::loop() {
  Timer t;
  for (int i = 0; i < l; i++) {
    e = edges.first();
    c = e->reduced_cost();
    edges.rotate();
  }
  t.used_time("Foo::loop");
}

int main () {

  // allocate all the data first
  Foo my_foo;
  my_foo.init();
  init();
  
  // and now the two loops
  loop();
  my_foo.loop();

  return e == 0 || c > 0; // make sure loop is not optimized away
}

-- 
	-lauther

----------------------------------------------------------------------------
Ulrich Lauther          ph: +49 89 636 48834 fx: ... 636 42284
Siemens ZT SE 4         Internet: Ulrich.Lauther@mchp.siemens.de


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]