Go Back   Forums > Community Chatterbox > Tech Corner > Programming
Memberlist Forum Rules Search Today's Posts Mark Forums Read
Search Forums:
Click here to use Advanced Search

Reply
 
Thread Tools Display Modes
Old 24-08-2006, 03:37 PM   #1
Eagg
Forum hobbit

 
Join Date: May 2006
Location: ,
Posts: 29
Default

So since the other thread made me curious about this issue, I wrote a small program in C++ to test the statement: "OOP makes programs slower".

I would have written a more complex one, but being busy in real life, I didn't have enough free time to spend.

If you are a programmer, please try to compile the code with your compiler of choice and let it run at least on the default parameters, better would be if you increase the outerloops for more numerical stability.

I also tried to write the procedural function in C, but since I have absolutely no practical expirience with C, I probably didn't do it very well.
Any C programmers are welcome to critise the code and even better improve it, same goes for the C++ part, of course.
I will not comment on the results of the C program so far, because I really think there are better implementations of that one. The first shock, maybe, will be when you see that I included the windows.h in C, but I simply couldn't find a way to stop time using the time.h in a high enough resolution (windows.h GetTickCount() offers a resolution of 2-3ms).

My prediction was that all the different implementations would give out similar if not same results (duration).
A good modern compiler should and will create almost identical code compiling a procedural and oop implementation of the same idea.
This shows quite well in my results from Visual Studio 2005 (VC++ 8.0) I think.

What suprised me is that the "heavy oop" version even succeeded in outperforming the procedural function somehow, this is a mystery to me.

Also there is a big difference between the compiler versions and I guess even higher difference between different compilers, which we might see if some of you run the program.

Please feel free to critise anything may it be the code, style or idea behind the programs.
If you think this does not prove anything, please tell me also the reason why not.

So here are the results:

System : Athlon64 San Diego @ 2555 MHz , DDR 426 @CL2-2-2-5
Compiler: VC++ 8.0

:::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::.
:: [C++] set: function loops = 10000x10000
:: outer loops = 10
:::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::.
:: finished: 100% time elapsed: 25s time left: 0s
:::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::.

:: procedural stack average: 201ms :: reference stack time
:: procedural heap average: 407ms :: reference heap time

:: oop heavy stack average: 165ms :: 17% faster
:: oop heavy heap average: 361ms :: 11% faster

:: oop medium stack average: 327ms :: 62% slower
:: oop medium heap average: 394ms :: 3% faster

:: oop light stack average: 324ms :: 61% slower
:: oop light heap average: 390ms :: 4% faster
:::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::.
-------------------------------------------------------------------
:::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::.
:: [C] set: function loops = 10000x10000
:: outer loops = 100
:::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::.
:: finished: 100% time elapsed: 41s time left: 0s
:::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::.

:: procedural stack average: 206ms
:: procedural heap average: 209ms
:::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::.


System : Athlon64 San Diego @ 2400 MHz , DDR 400 @CL2.5-3-3-6
Compiler: VC++ 7.0

:::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::.
:: [C++] set: function loops = 10000x10000
:: outer loops = 10
:::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::.
:: finished: 100% time elapsed: 66s time left: 0s
:::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::.

:: procedural stack average: 382ms :: reference stack time
:: procedural heap average: 519ms :: reference heap time

:: oop heavy stack average: 1145ms :: 199% slower
:: oop heavy heap average: 1145ms :: 110% slower

:: oop medium stack average: 1225ms :: 220% slower
:: oop medium heap average: 1389ms :: 167% slower

:: oop light stack average: 460ms :: 20% slower
:: oop light heap average: 463ms :: 10% faster
:::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::.

And here is the source code:

Main.cpp
Code:
/*

Object Oriented Programming vs. Procedural Programming Performance Test (C++ part)

Parameters: program <innerloops>* <outerloops>* <option>*
************innerloops = set function loops to innerloops²
************outerloops = set outerloops
************option**** = h for heap only functions
************************ s for stack only functions
***********************= optional parameters

Asymptotic behavior: O(innerloops²*outerloops) (if option set -> *1/2)


~Noam

*/

#include <iostream>
#include <sstream>
#include <windows.h>
#include "OOPfunc.h"

using namespace std;

//int rx, ry;

//procedural
long ploop(int loop) {
****long end, start = GetTickCount();

****int x = 2;
****int y = 3;

****for (int i = 0; i < loop; i++) {
********for (int j = 0; j < loop; j++) {
************x *= y;
************y += x;
********}
****}****
****//rx = x;
****//ry = y;

****end = GetTickCount();
****return end-start;
}

//procedural heap
long ploop2(int *loop) {
****long end, start = GetTickCount();

****int *x = new int;
*****x = 2;
****int *y = new int;
*****y = 3;

****for (int i = 0; i < *loop; i++) {
********for (int j = 0; j < *loop; j++) {
*************x *= *y;
*************y += *x;
********}
****}
****//if (*x != rx || *y != ry) { cout << "---------------------error:p2"; }
****delete x, y;

****end = GetTickCount();
****return end-start;
}

//oop medium
long ooploop1(int loop) {
****long end, start = GetTickCount();

****OOPfunc o;
****int x = 2;
****int y = 3;

****for (int i = 0; i < loop; i++) {
********for (int j = 0; j < loop; j++) {
************o.mult(x, y);
************o.add(y, x);
********}
****}
****//if (x != rx || y != ry) { cout << "---------------------error:o1"; }

****end = GetTickCount();
****return end-start;
}

//oop medium heap
long ooploop2(int *loop) {
****long end, start = GetTickCount();

****OOPfunc *op = new OOPfunc();
****int *x = new int;
*****x = 2;
****int *y = new int;
*****y = 3;

****for (int i = 0; i < *loop; i++) {
********for (int j = 0; j < *loop; j++) {
************op->mult(*x, *y);
************op->add(*y, *x);
********}
****}
****//if (*x != rx || *y != ry) { cout << "---------------------error:o2"; }
****delete op, x, y;

****end = GetTickCount();
****return end-start;
}

//oop light
long ooploop3(int loop) {
****long end, start = GetTickCount();

****OOPfunc o;
****int x = 2;
****int y = 3;
****
****o.loop(x, y, loop);
****//if (x != rx || y != ry) { cout << "---------------------error:o3"; }

****end = GetTickCount();
****return end-start;
}

//oop light heap
long ooploop4(int *loop) {
****long end, start = GetTickCount();

****OOPfunc *op = new OOPfunc();
****int *x = new int;
*****x = 2;
****int *y = new int;
*****y = 3;
****
****op->loop(*x, *y, loop);
****//if (*x != rx || *y != ry) { cout << "---------------------error:o4"; }
****delete op, x, y;

****end = GetTickCount();
****return end-start;
}

//oop heavy
long ooploop5(int loop) {
****long end, start = GetTickCount();

****OOPfunc x;
****OOPfunc y;

****x.set(2);
****y.set(3);
****
****for (int i = 0; i < loop; i++) {********
********for (int j = 0; j < loop; j++) {
************x.mult(y.value);
************y.add(x.value);
********}
****}
****//if (x.value != rx || y.value != ry) { cout << "---------------------error:o5"; }****

****end = GetTickCount();
****return end-start;
}

//oop heavy heap
long ooploop6(int *loop) {
****long end, start = GetTickCount();

****OOPfunc *xp = new OOPfunc(2);
****OOPfunc *yp = new OOPfunc(3);****
****
****for (int i = 0; i < *loop; i++) {
********for (int j = 0; j < *loop; j++) {
************xp->mult(&yp->value);
************yp->add(&xp->value);
********}
****}
****//if (xp->value != rx || yp->value != ry) { cout << "---------------------error:o6"; }****
****delete xp;
****delete yp;

****end = GetTickCount();
****return end-start;
}

void coutP(int totalF, int loop, int i, int p, long execStart) {
****int percent = 100*(i*totalF+p)/(loop*totalF);
****long elapsed = GetTickCount()-execStart;
****long left;
****if (percent == 0) { left = 0; }
****else { left = elapsed/percent*100-elapsed; }
****cout << ":: finished: " << percent << "%"
******** << "** time elapsed: " << elapsed/1000 << "s"
******** << "** time left: " << left/1000 << "s\t\r";
********
}

string compare(long ref, long x) {
****string result;
****stringstream ss;
****if (ref > x) {
********ss << (int) (100 - 100/(float) ref * (float) x);
********ss >> result;
********result.append("% faster");
****}
****else if (ref < x) {
********ss << (int) (100/(float) ref * (float) x - 100);
********ss >> result;
********result.append("% slower");
****}
****else { result = "equal"; }

****return result;
}

int main(int argc, char *argv[]) {****
****int loop1 = 0;
****int loop2 = 0;
****long execStart = GetTickCount();
****bool heapOnly = false;
****bool stackOnly = false;

****if (argc > 1) {
********stringstream ss;
********ss << argv[1];********
********ss >> loop1;****************
****}****
****if (argc > 2) {
********stringstream ss;********
********ss << argv[2];
********ss >> loop2;********
****}****
****if (argc > 3) {
********string s;
********stringstream ss;********
********ss << argv[3];
********ss >> s;
********if (s == "h") { heapOnly = true; }
********if (s == "s") { stackOnly = true; }************
****}
****if (loop1 == 0) { loop1 = 10000; }
****if (loop2 == 0) { loop2 = 10; }****
****
****cout << ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::." << endl
******** << ":: [C++]****** set: function loops = " << loop1 << "x" << loop1 << endl
******** << "::******************** outer loops = " << loop2 << endl
******** << ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::." << endl;
****
****int totalF = 8;****
****long *dur = new long[totalF];

****for (int i = 0; i < totalF; i++) { dur[i] = 0; }
****if (heapOnly || stackOnly) { totalF /= 2; }

****for (int i = 0; i < loop2; i++) {
********if (heapOnly) {
************coutP(totalF, loop2, i, 0, execStart);
************dur[1] += ploop2(&loop1);************
************coutP(totalF, loop2, i, 1, execStart);
************dur[3] += ooploop2(&loop1);************
************coutP(totalF, loop2, i, 2, execStart);
************dur[5] += ooploop4(&loop1);************
************coutP(totalF, loop2, i, 3, execStart);
************dur[7] += ooploop6(&loop1);
************coutP(totalF, loop2, i, 4, execStart);************
********}
********else if (stackOnly) {
************coutP(totalF, loop2, i, 0, execStart);
************dur[0] += ploop(loop1);
************coutP(totalF, loop2, i, 1, execStart);
************dur[2] += ooploop1(loop1);
************coutP(totalF, loop2, i, 2, execStart);
************dur[4] += ooploop3(loop1);
************coutP(totalF, loop2, i, 3, execStart);
************dur[6] += ooploop5(loop1);
************coutP(totalF, loop2, i, 4, execStart);
********}
********else {
************coutP(totalF, loop2, i, 0, execStart);
************dur[0] += ploop(loop1);
************coutP(totalF, loop2, i, 1, execStart);
************dur[1] += ploop2(&loop1);
************coutP(totalF, loop2, i, 2, execStart);
************dur[2] += ooploop1(loop1);
************coutP(totalF, loop2, i, 3, execStart);
************dur[3] += ooploop2(&loop1);
************coutP(totalF, loop2, i, 4, execStart);
************dur[4] += ooploop3(loop1);
************coutP(totalF, loop2, i, 5, execStart);
************dur[5] += ooploop4(&loop1);
************coutP(totalF, loop2, i, 6, execStart);
************dur[6] += ooploop5(loop1);
************coutP(totalF, loop2, i, 7, execStart);
************dur[7] += ooploop6(&loop1);
************coutP(totalF, loop2, i, 8, execStart);
********}
****}
****
****long refStack = dur[0]/loop2;
****long refHeap = dur[1]/loop2;
****
****cout << endl << ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::." << endl << endl
******** << ":: procedural stack**average: " << refStack << "ms"
******** << " :: reference stack time" << endl
******** << ":: procedural heap** average: " << refHeap << "ms"
******** << " :: reference heap time" << endl << endl
****
******** << ":: oop heavy stack** average: " << dur[6]/loop2 << "ms"
******** << " :: " <<**compare(refStack, dur[6]/loop2) << endl
******** << ":: oop heavy heap****average: " << dur[7]/loop2 << "ms"
******** << " :: " <<**compare(refHeap, dur[7]/loop2) << endl << endl

******** << ":: oop medium stack**average: " << dur[2]/loop2 << "ms"
******** << " :: " <<**compare(refStack, dur[2]/loop2) << endl
******** << ":: oop medium heap** average: " << dur[3]/loop2 << "ms"
******** << " :: " <<**compare(refHeap, dur[3]/loop2) << endl << endl

******** << ":: oop light stack** average: " << dur[4]/loop2 << "ms"
******** << " :: " <<**compare(refStack, dur[4]/loop2) << endl
******** << ":: oop light heap****average: " << dur[5]/loop2 << "ms"
******** << " :: " <<**compare(refHeap, dur[5]/loop2) << endl;
****
****return 0;
}
OOPfunc.h
Code:
class OOPfunc {****
****
public:
****int value;
****bool isSet;

****OOPfunc(int setValue);****
****OOPfunc();****
****void set(int someInt);****
****void mult(int a);
****void add(int a);
****void mult(int *a);
****void add(int *a);
****void mult(int &a, int b);
****void add(int &a, int b);
****void loop(int &a, int &b, int loop);
****void mult(int &a, int *b);
****void add(int &a, int *b);
****void loop(int &a, int &b, int *loop);
};
OOPfunc.cpp
Code:
#include "OOPfunc.h"

OOPfunc::OOPfunc(int setValue) {
****value = setValue;
****isSet = false;
}

OOPfunc::OOPfunc() {
****isSet = false;
}

void OOPfunc::set(int someInt) {
****value = someInt;
****isSet = true;
}

void OOPfunc::mult(int a) {
****value *= a;
}

void OOPfunc::add(int a) {
****value += a;
}

void OOPfunc::mult(int *a) {
****value *= *a;
}

void OOPfunc::add(int *a) {
****value += *a;
}

void OOPfunc::mult(int &a, int b) {
****a *= b;
}

void OOPfunc::add(int &a, int b) {
****a += b;
}

void OOPfunc::loop(int &a, int &b, int loop) {
****for (int i = 0; i < loop; i++) {
********for (int j = 0; j < loop; j++) {
************a *= b;
************b += a;
********}
****}
}

void OOPfunc::mult(int &a, int *b) {
****a *= *b;
}

void OOPfunc::add(int &a, int *b) {
****a += *b;
}

void OOPfunc::loop(int &a, int &b, int *loop) {
****for (int i = 0; i < *loop; i++) {
********for (int j = 0; j < *loop; j++) {
************a *= b;
************b += a;
********}
****}
}
And the beta main.c for C implementation
Code:
/*

Object Oriented Programming vs. Procedural Programming Performance Test (C part)

Parameters: program <innerloops>* <outerloops>*
************innerloops = set function loops to innerloops²
************outerloops = set outerloops************
***********************= optional parameters

Asymptotic behavior: O(innerloops²*outerloops)


~Noam

*/

#include <stdio.h>
#include <windows.h>

long ploop1(int loop) {
****long start = GetTickCount();
****int i, j;
****int x = 2;
****int y = 3;

****for (i = 0; i < loop; i++) {
********for (j = 0; j < loop; j++) {
************x *= y;
************y += x;
********}
****}

****return GetTickCount()-start;
}

long ploop2(int *loop) {
****long start = GetTickCount();
****int i, j;****

****int *xp = malloc(sizeof (int));
****int *yp = malloc(sizeof (int));
****if (xp == NULL || yp == NULL) { exit(EXIT_FAILURE); }
*****xp = 2;
*****yp = 3;

****for (i = 0; i < *loop; i++) {
********for (j = 0; j < *loop; j++) {
*************xp *= *yp;
*************yp += *xp;
********}
****}
****free(xp);
****free(yp);

****return GetTickCount()-start;
}

void printP(int totalF, int loop, int i, int p, long execStart) {
****int percent = 100*(i*totalF+p)/(loop*totalF);
****long elapsed = GetTickCount()-execStart;
****long left;
****if (percent == 0) { left = 0; }
****else { left = elapsed/percent*100-elapsed; }

****printf(":: finished: %d%%", percent);
****printf("** time elapsed: %ds", elapsed/1000);
****printf("** time left: %ds\t\r", left/1000);
}


int main(int argc, char *argv[]) {
****long start;
****int loop1 = 0;
****int loop2 = 0;****
****int i;
****long dur1 = 0;
****long dur2 = 0;

****if (argc > 1) {
********loop1 = atoi(argv[1]);********
****}****
****if (argc > 2) {********
********loop2 = atoi(argv[2]);
****}****
****if (loop1 == 0) { loop1 = 10000; }
****if (loop2 == 0) { loop2 = 10; }****

****printf(":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.\n");
****printf(":: [C]**** set: function loops = %dx%d\n", loop1, loop1);
****printf("::**************** outer loops = %d\n", loop2);
****printf(":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.\n");

****start = GetTickCount();**

****for (i = 0; i < loop2; i++) {
********printP(2, loop2, i, 0, start);
********dur1 += ploop1(loop1);
********printP(2, loop2, i, 1, start);
********dur2 += ploop2(&loop1);
********printP(2, loop2, i, 2, start);
****}

****printf("\n:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.\n\n");
****printf(":: procedural stack average: %dms\n", dur1/loop2);
****printf(":: procedural heap**average: %dms\n", dur2/loop2);

****return 0;
}
PS: Isn't there a way to make the code part in a small scrollable window?
PPS: This are console programs and you should start them out of console, not by double clicking the .exe. If you don't want to do it, you need to add a pause at the end of the code otherwise you won't see the result (the windows will close automatically). I didn't do it by myself because I consider it bad coding practice for a console app.
Eagg is offline                         Send a private message to Eagg
Reply With Quote
Old 24-08-2006, 04:58 PM   #2
GrimFang4
Forum hobbit

 
Join Date: Jun 2006
Location: Strafford, United States
Posts: 31
Send a message via ICQ to GrimFang4
Default

Eagg, I left my code in the other thread. It doesn't matter much what you're doing with OOP or PP, it's that you're working more with functions and pointers in OOP. Functions and pointers will take longer. Only when you use the optimization option of your compiler will the two methods look anything alike in machine code.

To comment on your code without reading much: You shouldn't have the printing statements within your timing range.
__________________
GrimFang4 is offline                         Send a private message to GrimFang4
Reply With Quote
Old 24-08-2006, 05:17 PM   #3
Eagg
Forum hobbit

 
Join Date: May 2006
Location: ,
Posts: 29
Default

Pointers don't necessarily make programs slower, they are there to improve performance and memory footprint when used correctly.

I don't have any output within the time critical sections as you can clearly see, the loop2 loop is only to make the statistics numerically stable and does not count to any functions duration time.

If you mean the output code that is commented out, it was only there to make sure that all the functions actually work correctly and deliver me the same end result (x, y).
Eagg is offline                         Send a private message to Eagg
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump
 


The current time is 12:57 AM (GMT)

 
Powered by vBulletin® Version 3.7.1
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.