Re: NSPoint. The results. Look at that, Georg!
Re: NSPoint. The results. Look at that, Georg!
- Subject: Re: NSPoint. The results. Look at that, Georg!
- From: Nathan Day <email@hidden>
- Date: Tue, 4 Mar 2003 01:05:39 +1030
This is one of Objecive-C's real weaknesses it doesn't handle the idea
of abstract data types well, languages like C++ do this because they
can have statically bound methods and object, a class in C++ with no
virtually methods has the same memory foot print as a struct and it's
methods are no different than functions.
On Monday, March 3, 2003, at 11:53 PM, Pascal Goguey wrote:
Hello!
This is a little bit long, but interesting.
Yesterday, I didn't have that much data for the discusson, but
I made a few experiments that seem to prove either:
- that you are completely wrong or
- that Objective C is extremely inefficient compared to C++.
But if Obj-c was inefficient, everybody would know it, so I guess
you are completely wrong. Here are the reasons:
NB: As I am a beginner in Objective-C, I made all the experiments in
C++
on BeOS.
This experiment is divided in 2 parts: the speed part, and
the memory part.
BeOS has a class BPoint that has 2 public variables x and y (float
numbers).
Beside that, it has about 10 methods among which you have:
- Set(x, y); // Does what it says
- ConstrainToRectangle(BRect R); // Makes sure that the point is
// within the rectangle R and fixes it if not
And you have also copy constructor and so on.
1. The speed experiment:
In order to compare, I made a GPoint which has nothing to do
with my wife's G point, but which is defined as follows:
typedef struct {
float x;
float y;
} GPoint;
What I did:
-----8<----------8<----------8<----------8<-----
#define POINT_COUNT 1000
#define ITER_COUNT 100000
BPoint BPointArray[POINT_COUNT];
GPoint GPointArray[POINT_COUNT];
int i, j;
time_t timebefore, timeafter; // Time variables in microseconds
// Here we go!
timebefore = real_time_clock_usecs(); // Get the current time in
microseconds
for(j = 0 ; j < ITER_COUNT ; ++j) {
for(i = 0 ; i < POINT_COUNT ; ++i) {
BPointArray[i].Set(1.0, 1.0);
}
}
timeafter = real_time_clock_usecs(); // Get the current time in
microseconds
cout << "Time for setting " << POINT_COUNT * ITER_COUNT << " BPoint
set : ";
cout << (float)(timeafter - timebefore) / 1000000.0; // print the time
in seconds
// Now straight to the G point!
timebefore = real_time_clock_usecs(); // Get the current time in
microseconds
for(j = 0 ; j < ITER_COUNT ; ++j) {
for(i = 0 ; i < POINT_COUNT ; ++i) {
GPointArray[i].x = 1.0;
GPointArray[i].y = 1.0;
}
}
timeafter = real_time_clock_usecs(); // Get the current time in
microseconds
cout << "Time for setting " << POINT_COUNT * ITER_COUNT << " GPoint
set : ";
cout << (float)(timeafter - timebefore) / 1000000.0; // print the time
in seconds
-----8<----------8<----------8<----------8<-----
Simple, right?
Guess what? BPoint class is faster!
Time for setting up 100 000 000 BPoints : 0.74 second (I have an old
400 MHz celeron PC).
Time for setting up 100 000 000 GPoints : 1.23 seconds
Now the reason was that it takes time to access GPointArray[i].
Many thanks to Laurent who found the reason.
If I replace the second loop contents by:
GPoint& Here = GPointArray[i];
Here.x = 1.0;
Here.y = 1.0;
Then I have the EXACT SAME results:
Time for setting up 100 000 000 BPoints : 0.7432 second
Time for setting up 100 000 000 GPoints : 0.7432 seconds
NB: to be accurate, there were some fluctuations on the 3rd
decimal (+/-2 ms), that were probably due to the scheduler timing.
Sometimes GPoint saves 1 or 2 ms for 100 millions points,
sometimes BPoint was faster, and 0.7432 on the average of
100 experiments.
CONCLUSION OF THE SPEED EXPERIMENT:
The speed seems to be exactly the same for a structure as for a class
which has a few function in addition to its data.
Important point: before thinking one method is faster (struct vs
class),
one has to test it.
And usually it is a lot better to use existing objects that have been
extensively tested. Doing things yourself is an open door to
performance loss, as shown by the two consecutive accesses
to one element of the same array.
NB: I would like to do the same on MacOS-X, but I don't know how
to get the current time...
2. The memory experiment
This time, it will be short:
I calculated sizeof(GPoint), and I found 8 which is normal for a
structure of 2 floats.
Now the BPoint class size is also 8.
I have also calculated memory sizes for a few NS objects
Here are the results:
sizeof(NSPoint) = 8; No surprise here.
sizeof(NSView = 80; I was surprised, considering all the NSView
functionality
but hey, functions and data are not in the same basket.
sizeof(NSWindow) = 142 (if I recall well)...
CONCLUSION OF THE MEMORY EXPERIMENTS:
In C++, the space of an object is not bigger if it is a class rather
than if it is a structure.
To summarize the results: C++ encapsulation DOES NOT COST ANYTHING IN
TERMS
OF PERFORMANCE AND MEMORY.
As I am a beginner in Obj-C, I am asking obj-c experts the same
question as the
original thread:
Since the performance and memory issues seem to be wrong:
why are some NS objects only structures while others are classes?
--------------------
Now a few comments on your reply:
On Sunday, Mar 2, 2003, at 19:31 Asia/Tokyo, Georg Tuparev wrote:
1. Because it is very bad design practice to surround static data
structures with objects.
Where did you get this "rule" from? I mean, is there a computer science
theory that proves it or is it your taste? And why is it bad design?
I am ready to believe you, but you have to prove why it is
inefficient, why
it takes space in memory and how much, etc... You have to prove it
for Obj-C of course, because I proved it is wrong for C++.
It is like 95% of all text books giving class inheritance examples
like Mammal->Cat->Tiger.
Then the students are let into the real life and start creating
separate classes for each of the
4 500 000 or so species. As absurd as it may sound there are many
frameworks/applications
out there based on this insane design principle. Over 50% of all
Talignet classes and the
Java exception handling are prominent examples ...
2. Because it is slow and inefficient.
Back to the NSPoint example:
How slow would it be? 15% slower? Speed divided by 2? By 10000?
Did you write a small test program before saying it is slow?
Imagine you are writing a protein modeling program with millions of
vectors
(chemical bonds) and billions of points (electron density clouds). If
each vector
and dot is an object, you will need gigabytes of ram just to run the
program.
How many people are writing protein modeling or nuclear
simulation programs on MacOS? As it is a computer with fair media
capabilities, the worst case you can have is a few video streams
at 30 fps each.
I have proved that you can assign values for 100 millions points,
(which must
be in the order of computation of a few frames of video) within
the exact same time and it uses the exact same memory so what are you
using your "Gigabytes of ram" for? Just curious...
Pascal
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.
Nathan Day
http://homepage.mac.com/nathan_day/
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.