0

I made 2 benchmarks, one for my oop class

class oop {

    public float[] position = new float[2];
    public float[] scale = new float[2];
    public float[] rotation = new float[2];
    public string name;
    public int weight;

    public void setPosition() {
        position[0] = 1.5f;
        position[1] = 3f;
    }

    public void setScale() {
        scale[0] = 1.5f;
        scale[1] = 3f;
    }

    public void setRotation() {
        rotation[0] = 1.5f;
        rotation[1] = 3f;
    }

    public void setName() {
        name = "Gregor";
    }

    public void setWeight() {
        weight = 150;
    }

}

and one for my entity class

class entity {

    // Entity properties
    public position position;
    public rotation rotation;
    public scale scale;
    public name name;
    public weight weight;

}

each property in the entity is a struct.

I tried to benchmark them:

for (long i = 0; i < times; i++) {
    oop test = new oop();

    test.setPosition();
    test.setRotation();
    test.setScale();
    test.setName();
    test.setWeight();
}
for (long i = 0; i < times; i++) {
    entity e = new entity();
    e.position.x = 1.5f;
    e.position.y = 3f;

    e.rotation.x = 1.5f;
    e.rotation.y = 3f;

    e.scale.x = 1.5f;
    e.scale.y = 3f;

    e.name.n = "Gregor";

    e.weight.w = 150;
}

my results:

OOP 0ms (1)
DoD 0ms (1)

OOP 0ms (10)
DoD 0ms (10)

OOP 0ms (100)
DoD 0ms (100)

OOP 0ms (1000)
DoD 0ms (1000)

OOP 4ms (10000)
DoD 0ms (10000)

OOP 9ms (100000)
DoD 5ms (100000)

OOP 78ms (1000000)
DoD 42ms (1000000)

OOP 786ms (10000000)
DoD 539ms (10000000)

OOP 6455ms (100000000)
DoD 4107ms (100000000)

My question is: Why is this possible? In my dod class i have the same amount of values as in my oop class, and i set the same values for everything. The float arrays are slower than the structs? I wanted to make an a Data Oriented Design, but its not great like that, but the result is a lot better than my oop class

6
  • Did you do a release build and run the test from the command line? Commented Jul 4, 2020 at 21:32
  • No, i run it from visual studio only Commented Jul 4, 2020 at 22:18
  • When running from visual studio some opermizations may be disabled. Likewise for debug builds. Commented Jul 4, 2020 at 22:39
  • @TechWiki- Your entity code doesn't compile. I assume you meant to use the same types as the oop example? Commented Jul 5, 2020 at 0:51
  • @TechWiki - No, I can see the x and y properties. Can you please post a minimal reproducible example so that we can run the benchmarks ourselves? Commented Jul 5, 2020 at 0:56

2 Answers 2

1

Difference is due to the memory management of both.

Structs are value types, which means they are stored inline inside their containing data type.

Here you can find a very good article on this.

https://medium.com/csharp-architects/whats-faster-in-c-a-struct-or-a-class-99e4761a7b76

Sign up to request clarification or add additional context in comments.

2 Comments

@AlexeiLevenkov it seems that position, rotation ... are structs =) At least I have assumed so =)
@vivek nuna yes, position, rotation and scale holds 2 floats, name holds 1 string and weight 1 integer
0

What you called OOP here is not OOP but raw data in a class (arrays). And what you called DOD is OOP here with data encapsulated and abstracted.

So, in what you called OOP you have getters and setters, hence lots of procs calls in your loop. And in what you called DOD you have not these procs calls but direct memory access by pointers (references if you prefer). Hence the speed... because using true OOP (in your DOD) you gain speed over the OOP's weight. Despite what I will said below, sometimes good OOP design can be faster than non-OOP design for some parts, because, I suppose, you have no setters/getters.

In conclusion to your question: your test is flawed by your design. Because in what you called OOP, that is false OOP, you have getters and setters to arrays (lots of big CPU procs calls ticks). And in what you called DOD, that is true OOP, you have no procs calls, I suppose, but direct access to instance members that are simple value types (CPU access to memory is fast here).

Generally, OOP is always slower than raw data access... because of CPU procedures calls on getters and setters when available, and always because of chained references access at least.

An A.B.C.D access requires at least 4 memory pointers that are 4 times slower (or up to 4 procs calls that are very slower, I don't remember timings on a i486, one call or jump is x2 to x4 or x8 slower than a MOV or an ADD), at least, approximately, than only one reference access to a raw int or an array plus an offset, for example.

Another example is that arrays are always faster than generic lists.

On the whole, OOP is always slower than non OOP: OOP is the science of using memory pointers to organize data and code to do abstraction and encapsulation... this science requires more CPU resources than structured programming that is useless to do even simple OOP simulation. And OOP abuses procs calls...

But without OOP, we can't do such great things we do since many years: OOP frees up programming technolgies and foreshadows inconceivable things no matters what we think about it.

To understand that, not only to know that, we need to know how the CPU works.

There is a book on that by Bjarne Stroustrup about the C++ genesis: "The Design and Evolution of C++", and all references manuals by Intel since the beginning.

You should learn how the processor works and what assembly language is. So, you can see what are proc calls, memory access, timings and CPU ticks/clocks for mov, add, sub, call, ret, jz, jne, jmp... instructions and so on.

https://www.tutorialspoint.com/assembly_programming/index.htm

https://www.wiley.com/en-us/Professional+Assembly+Language-p-9780764579011

Old simple great Intel manual:

http://bitsavers.trailing-edge.com/components/intel/80486/i486_Processor_Programmers_Reference_Manual_1990.pdf

Intel modern manuals:

https://software.intel.com/content/www/us/en/develop/articles/intel-sdm.html

You can also use ILSpy or Reflector to see IL code generated by Visual Studio and see how things are done.

https://learn.microsoft.com/dotnet/api/system.reflection.emit.opcodes

It is because nowadays we have good CPU that we can do OOP on .NET or Java or other, and the better will come soon... with or without quantum.

You can search on Google for tutorials and books about these things, using terms like "code optimization", ".net intermediate language (or IL)", "processor timings (or ticks or clocks)", "assembly mnemonics (or opcodes)", "assembly language", "processor architecture"... as well as "programing theory".

7 Comments

What is "procs calls ticks"?
I really don't understand what you're saying here: "OOP frees up programming technolgies and foreshadows inconceivable things no matters what we think about it."????
1 - The number of CPU clocks or ticks that is needed to execute a call or a jump to an address (procedure call in assembly language). For example a MOV (assign) or a JZ (if) takes 1 to 10 clocks but a CALL takes 4 to 50 if I remember... | 2 - I said that because, less today, some coders dislike OOP (the previous generation), but without OOP, our world would not have been what it is and will become.
You've gone a level of abstraction too deep, in my opinion. And you're making some astonishing incorrect statements: "OOP is always slower than non OOP".
Yes OOP is slower, because of virtual tables, of abstraction, of encapsulation and of abuse of proc calls and references chaining... It's a fact. Sometimes we can do some things faster with a good design, but on the average, OOP est slow. OOP gain notoriety with recents CPU since 10 to 20 years.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.