Wednesday, August 26, 2020

Digest for comp.lang.c++@googlegroups.com - 25 updates in 3 topics

Frederick Gotham <cauldwell.thomas@gmail.com>: Aug 26 11:24AM -0700

I work 37.5 hours a week, so that's around about 8 hours a day (I leave early on Friday's).
 
Today's Wednesday, and I've just finished my 3rd day in a row trying to get 'cmake' to cross-compile on an x64 host for an aarch64 target (both Linux).
 
Are the makers of 'cmake' mistakenly claiming that it can cross-compile? I've read their manual in the chapter about 'toolchains', but after about 22 hours at my desk scrolling through various posts on open-source forums, Github issues, and 'Stack Overflow', I still haven't got a successful aarch64 build.
 
It looks like I will have to do the following with every package that is built with 'cmake':
 
(1) Run 'cmake' natively on x64 to get it to create GNU Makefiles intended for the x64 versions of gcc, g++.
(2) Process these GNU Makefiles at the command line with something like 'make SHELL="sh -x" -n' in order to get all the compiler commands
(3) Gather all the compiler commands together into a script and call it "make.sh", and prepend "aarch64-linux-gnu-" to every command.
(4) Add these "make.sh" files to my overall build in the place of "CMakeLists.txt" and "cmake-configure".
 
Having spent 22 hours fiddling and tinkering around with Makefiles, I see now that they are of no use in distributed source code. Makefiles are convenient when you're _developing_ code because you don't have to recompile your entire codebase every time you make a small change, however it is only a hinderence to other people to supply your source code to them with a Makefile. You should give them a very simple compilation script -- not a horrendously complicated Makefile that creates another Makefile.
 
After this week I will never have the respect I once had for 'build systems'. For smaller projects I think I'll go back to simple compilation scripts like this:
 
#!/bin/sh
${CROSSCOMPILE}gcc -c alpha.c
${CROSSCOMPILE}gcc -c beta.c
${CROSSCOMPILE}gcc -c gamma.c
${CROSSCOMPILE}gcc -o prog alpha.o beta.o gamma.o
 
If someone wants to cross-compile then they can do:
 
CROSSCOMPILE=aarch64-linux- ./make.sh
 
I think 'cmake' might be able to cross-compile between Linux and MS-Windows if the two architectures are the same
, but after 22 hours I can't make an aarch64 Linux build from an x64 Linux host.
Cholo Lennon <chololennon@hotmail.com>: Aug 26 05:11PM -0300

On 26/8/20 15:24, Frederick Gotham wrote:
 
> CROSSCOMPILE=aarch64-linux- ./make.sh
 
> I think 'cmake' might be able to cross-compile between Linux and MS-Windows if the two architectures are the same
> , but after 22 hours I can't make an aarch64 Linux build from an x64 Linux host.
 
But it's not clear what your problem is: "...I still haven't got a
successful aarch64 build..." is not a good description of the issue. Are
you asking for help or is your post just a rant? :-)
 
 
--
Cholo Lennon
Bs.As.
ARG
Frederick Gotham <cauldwell.thomas@gmail.com>: Aug 26 01:51PM -0700

On Wednesday, August 26, 2020 at 9:11:18 PM UTC+1, Cholo Lennon wrote:
 
> But it's not clear what your problem is: "...I still haven't got a
> successful aarch64 build..." is not a good description of the issue. Are
> you asking for help or is your post just a rant? :-)
 
 
 
If I invite you into my house and say, "There's tea in the tin and milk in the fridge", are you going to stand there staring at me until I formally ask you, "Good sir would you like a cup of tea?".
 
Please re-read my original post and fathom what I might want.
Juha Nieminen <nospam@thanks.invalid>: Aug 26 06:19AM

>> OOP is out of fashion...
 
> OOP still has its place. Especially in business applications in lang-
> uages like C#, and even BASIC variants and Visual FoxPro.
 
I can't even imagine how a GUI library could be implemented without OOP...
 
Maybe one could do it in some other way that kind of mimics what OOP provides
to such a library but without using OOP per se. Although it's still hard to
imagine how you would do that. (Perhaps some kind of templated code that
generates code for every single possible type of GUI element? Although it's
still hard to come up with an implemenentation that's "not OOP" given that
you ostensibly need data containers that can manage objects of different
types, and to perform the same operations to all the objects even though
they are of different types...)
 
Perhaps the most prominent industry where OOP is falling out of fashion is
the game engine one. OOP seemed like the natural approach, for pretty much
the same reason as with GUI libraries. However, OOP just kills low-level
performance because it interacts poorly with cache coherence, memory
locality, the CPU's pipeline, and the compiler's ability to autovectorize
the code. (Changing the codebase of a game engine from an object-oriented
design to a data-oriented design can increase efficiency by even an order
of magnitude, for the mere reason that the latter behaves much better with
respect to the CPU's cache and pipelines, as well as helping the compiler
to better optimize the code eg. with autovectorization.)
Bonita Montero <Bonita.Montero@gmail.com>: Aug 26 08:25AM +0200

> performance because it interacts poorly with cache coherence, memory
> locality, the CPU's pipeline, and the compiler's ability to autovectorize
> the code. ...
 
That's stupid stuff.
David Brown <david.brown@hesbynett.no>: Aug 26 10:31AM +0200

On 26/08/2020 08:25, Bonita Montero wrote:
>> locality, the CPU's pipeline, and the compiler's ability to autovectorize
>> the code. ...
 
> That's stupid stuff.
 
No, he is correct.
 
But it is not just OOP that makes the difference here - it is structured
data in the first place. OOP just makes it even worse performance-wise
(while making it neater in the source code).
 
You might logically have a structure for a bullet in a game that holds x
and y coordinates, age, type, size, colour, speeds, explosiveness, and a
dozen other attributes. With OOP, some of these will be inherited from
a more generic "flying thing" object, and other types will inherit from
the bullet - everything is neat, maintainable, expandable in the code.
Let's guess 100 bytes of data for a "bullet" object.
 
But when you want to do a time-step, you do "pos_x += speed_x *
time_step" for every object in your list. Let's say you have 10,000
objects in your list (games can easily have vast numbers of objects at a
time). For each object, you will need to pull in at least one, but
sometimes two, 64-byte cache lines - varying as the alignment changes
throughout the array. And for each updated position variable, you have
a 64-bit dirty cache line that needs to be written out again. 640 KB of
memory - thrashing your L1 cache and making a solid dent in your L2
cache. Almost all of the cache space used, and memory bandwidth, is
wasted. And of course there can be no vectorisation.
 
In game programming, you prefer to have an array of pos_x, an array of
speed_x, and so on - the object's data is all split up. Now you are
running through two arrays, of 40 KB each (for 4-byte float data) - an
order of magnitude more efficient. Every byte read is a byte used, as
is every byte written. Vectorisation will let you handle perhaps 8
objects every clock cycle. It is a completely different world in
performance terms.
 
For almost any programming where run-time speed is important, it comes
down to caches.
Bonita Montero <Bonita.Montero@gmail.com>: Aug 26 10:35AM +0200

> No, he is correct.
 
No, that's wrong. If you have structures and associated functionis
or methods bound to ne namespace of the structures doesn't make a
difference.
 
> memory - thrashing your L1 cache and making a solid dent in your L2
> cache. Almost all of the cache space used, and memory bandwidth, is
> wasted. And of course there can be no vectorisation.
 
LOL, what studpid dreaming.
boltar@nuttyella.co.uk: Aug 26 09:19AM

On Wed, 26 Aug 2020 10:31:23 +0200
>In game programming, you prefer to have an array of pos_x, an array of
>speed_x, and so on - the object's data is all split up. Now you are
 
I find it hard to believe that in any significant game that may have a
codebase of millions of lines of code and thousands of different game object
types, that they revert to BASIC style programming with object values being
stored in arrays indexed by some object id. Perhaps it does speed things up
but the spaghetti code and potential design problems and bugs it would create
would far outweigh the gains IMO.
Paavo Helde <eesnimi@osa.pri.ee>: Aug 26 01:46PM +0300

> stored in arrays indexed by some object id. Perhaps it does speed things up
> but the spaghetti code and potential design problems and bugs it would create
> would far outweigh the gains IMO.
 
"object values being stored in arrays indexed by some object id" is a
common data structure in programming; it's called "table". From what I
have heard there are some big name vendors earning great bucks on them.
 
A table can be represented either row-wise and column-wise in memory. If
one frequently needs to perform operations on whole columns, then
storing columns compactly in memory means huge performance wins.
boltar@nuttyella.co.uk: Aug 26 10:51AM

On Wed, 26 Aug 2020 13:46:13 +0300
 
>"object values being stored in arrays indexed by some object id" is a
>common data structure in programming; it's called "table". From what I
>have heard there are some big name vendors earning great bucks on them.
 
I'm not talking about tables/maps/hashes since if you use a complex object
like that you might as well just use objects directly as there's a lot going
on underneath. I suspect what he was talking about is C style arrays indexed
by sequentially created integer object id that identifies an object.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Aug 26 11:06AM

["Followup-To:" header set to comp.lang.c++.]
 
> stored in arrays indexed by some object id. Perhaps it does speed things up
> but the spaghetti code and potential design problems and bugs it would create
> would far outweigh the gains IMO.
 
Surely it would affect only parts of the code, and surely you can
build reasonable abstractions on top of it, in C++ anyway.
 
(Maybe OOP in the sense "lots of inheritance everywhere" would be hard
to get, though. If anyone wants that.)
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Paavo Helde <eesnimi@osa.pri.ee>: Aug 26 02:36PM +0300

26.08.2020 14:06 Jorgen Grahn kirjutas:
> build reasonable abstractions on top of it, in C++ anyway.
 
> (Maybe OOP in the sense "lots of inheritance everywhere" would be hard
> to get, though. If anyone wants that.)
 
OOP with lots of inheritance might imply dynamic allocation in common
usage scenarios, and dynamic allocation might be slow, for several reasons.
 
But it all depends on how OOP is used. E.g, in image processing, if a
pixel is an OOP object allocated dynamically then there is no hope for
any decent performance. OTOH, if an image containing millions of pixels
is an OOP object and allocated dynamically, there is no problem.
David Brown <david.brown@hesbynett.no>: Aug 26 02:13PM +0200

On 26/08/2020 13:06, Jorgen Grahn wrote:
>> would far outweigh the gains IMO.
 
> Surely it would affect only parts of the code, and surely you can
> build reasonable abstractions on top of it, in C++ anyway.
 
Of course (to both points).
 
Some references:
 
<https://gameprogrammingpatterns.com/data-locality.html>
 
<https://jacksondunstan.com/articles/3860>
 
 
 
 
 
David Brown <david.brown@hesbynett.no>: Aug 26 02:52PM +0200

> stored in arrays indexed by some object id. Perhaps it does speed things up
> but the spaghetti code and potential design problems and bugs it would create
> would far outweigh the gains IMO.
 
No one suggested spaghetti code or "BASIC style" programming. You would
use C++ to get nice code - wrapping access to private static arrays (or
more likely, arrays of SIMD vectors) in abstractions that give you neat
source code that compiles to optimised SIMD object code with run-time
adaption to different processors.
 
C++ has the tools you need to write this kind of code in a (relatively)
clear and maintainable way, with a separation of the abstract interface
used in code and the highly optimised implementation code. Using an
obvious OOP hierarchy with data held in classes will not cut it.
 
And the speed gains can easily be an order of magnitude - it /is/ worth
doing. In the opinion of real games developers.
boltar@nuttyella.co.uk: Aug 26 03:27PM

On Wed, 26 Aug 2020 14:52:46 +0200
>more likely, arrays of SIMD vectors) in abstractions that give you neat
>source code that compiles to optimised SIMD object code with run-time
>adaption to different processors.
 
Don't you simply get overhead with the abstracted calls instead?
 
>clear and maintainable way, with a separation of the abstract interface
>used in code and the highly optimised implementation code. Using an
>obvious OOP hierarchy with data held in classes will not cut it.
 
Just sounds like old style bottom up programming with some lipstick on top.
If you can't use much in the way of OOP you might as well just use C.
 
>And the speed gains can easily be an order of magnitude - it /is/ worth
>doing. In the opinion of real games developers.
 
I'll take your word for it.
David Brown <david.brown@hesbynett.no>: Aug 26 05:44PM +0200

>> source code that compiles to optimised SIMD object code with run-time
>> adaption to different processors.
 
> Don't you simply get overhead with the abstracted calls instead?
 
No. Your abstractions are not calls, just wrappers so that code using
the data doesn't have to be concerned about the details of the
implementation of the data storage. (It might /look/ like function
calls, templates, references, etc., but done properly, it will all
disappear in inlining and optimisation.)
 
Also, your really critical code probably accesses the data using the
low-level vector information.
 
>> obvious OOP hierarchy with data held in classes will not cut it.
 
> Just sounds like old style bottom up programming with some lipstick on top.
> If you can't use much in the way of OOP you might as well just use C.
 
No. C++ supports OOP - but doing OOP is certainly not the only reason
to choose C++ over C.
 
>> And the speed gains can easily be an order of magnitude - it /is/ worth
>> doing. In the opinion of real games developers.
 
> I'll take your word for it.
 
Marvellous!
 
You can also look at these (due to the follow-ups, I posted these in the
C++ group but not the comp.arch group in a previous post).
 
 
<https://gameprogrammingpatterns.com/data-locality.html>
 
<https://jacksondunstan.com/articles/3860>
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Aug 26 05:50PM +0100

On Wed, 26 Aug 2020 06:19:50 +0000 (UTC)
 
> > OOP still has its place. Especially in business applications in lang-
> > uages like C#, and even BASIC variants and Visual FoxPro.
 
> I can't even imagine how a GUI library could be implemented without OOP...
 
That depends on whether by 'OOP' you mean OOP implemented by C++'s
notion of inheritance sub-typing. Every serious language has to
have some means of properly structuring code, and the ability to build
code up from the bottom step by step.
 
Rust has structs and traits. The MLs have module signatures, module
inclusions and functors, and some of them also implement sub-type
polymorphism via polymorphic variants. And of course C does not have
inheritance as such (although it can be emulated).
Lynn McGuire <lynnmcguire5@gmail.com>: Aug 26 12:46PM -0500

On 8/26/2020 1:19 AM, Juha Nieminen wrote:
> of magnitude, for the mere reason that the latter behaves much better with
> respect to the CPU's cache and pipelines, as well as helping the compiler
> to better optimize the code eg. with autovectorization.)
 
Seen a GUI library implemented before in C. Lots and lots of void *.
 
Lynn
Juha Nieminen <nospam@thanks.invalid>: Aug 26 06:01PM


> No, that's wrong. If you have structures and associated functionis
> or methods bound to ne namespace of the structures doesn't make a
> difference.
 
I don't think you have any idea what either of us is talking about.
 
Do you even know how CPU caches work?
Juha Nieminen <nospam@thanks.invalid>: Aug 26 06:14PM

> (Maybe OOP in the sense "lots of inheritance everywhere" would be hard
> to get, though. If anyone wants that.)
 
Inheritance and dynamic binding (ie. virtual functions) are not the
only performance-killers.
 
One of the most fundamental core building blocks of OOP, and its
precursor, modular programming, ie. the fact that you gather all
the data related to one object into the same place, the same
data structure, is one of the major performance killers in modern
CPUs. This even if you manage objects by value putting them in arrays.
(While putting them by-value into arrays does help quite some, it's
still not optimal.)
 
Quite often, especially in games, you only read and/or write a
particular or a couple of particular member variables of each object
(like for example the coordinate variables of the object), and you
do this for a huge bunch of objects (in modern games we may be talking
about thousands, maybe even tens or thousands of objects, on each
frame, at least 60 times per second, in modern PCs even more, like
up to 144 times per second and even higher.)
 
Even if your objects are in an array, what happens is that you will
be jumping in this array in big steps, because each object will have
a big bunch of other ancillary member variables in between the ones
you are interested in. This kills cache locality. The most optimal
way would be to traverse all the consecutive bytes of an array,
because this minimizes the amount of cache misses. However, OOP
kills this because now you will be jumping in big steps.
 
And that's assuming your objects are in an array in the first place.
If you just dynamically allocated every object individually, it will
be much worse. Now they will be all over the place, at random
locations in memory.
 
The other reason why OOP is a performance killer is that function
calls inhibit compiler optimizations. And we are not necessarily
even talking about virtual function calls. Just regular function
calls (assuming the functions aren't inlined).
 
A function call in itself isn't very inefficient at runtime because
of branch prediction. The CPU will start reading instructions from
the location of the jump, so there's very little penalty. Depending
on the function call the stack might not even be involved (if all
the parameters can be passed in CPU registers.)
 
However, what may well kill performance is that a function call
(that can't be inlined) will completely inhibit the compiler's
ability to optimize the code, eg. if you are calling the function
in a loop (which is often the case when you are updating a bunch
of objects).
 
If the code directly sees the data in an array and performs no
function calls, the compiler may well be able to auto-vectorize
the operations you are doing to the data.
Juha Nieminen <nospam@thanks.invalid>: Aug 26 06:19PM

> stored in arrays indexed by some object id. Perhaps it does speed things up
> but the spaghetti code and potential design problems and bugs it would create
> would far outweigh the gains IMO.
 
You may find it hard to believe, but that's what all the major game
engines have been doing for the past few years: Moving away from OOP
and towards data-oriented design.
 
The whole idea of "data-oriented design" is to make your code as
efficient as possible at the low level (ie. in terms of the CPU cache,
the CPU pipeline and the compiler autovectorization) without your code
becoming spaghettified. It's definitely not as easy and nice as OOP,
but it's not impossible either. And it may result in *significant*
improvements in terms of speed.
 
Given that video games are becoming bigger and bigger, and more and
more complex by the year, and given that not everything can be offloaded
to the GPU, and given that display framerates are also increasing by
the year (displays are already surpassing 144 Hz refresh rates), being
able to process data as efficiently as possible with the CPU can be
a huge advantage.
Juha Nieminen <nospam@thanks.invalid>: Aug 26 06:23PM

> Seen a GUI library implemented before in C. Lots and lots of void *.
 
It's still OOP even if it has to be "manually simulated".
I'm more talking about program design rather than whether the
language has direct support for OOP.
 
A GUI typically needs some kind of base code that handles all
screen elements (so that it can eg. draw them and do all other
kinds of stuff to them). Since not all elements are equal, the
base code needs to still be able to handle all of them, no matter
how different they may be. Be it a button, a checkbox, an image,
a text label, a textfield, a window, a menu, a menu element...
the base code still needs to be able to eg. know its dimensions
and positions (and a myriad of other common characteristics)
and to be able to draw them somehow. It also needs to know which
elements are inside which other elements, and so on.
 
I can't even imagine how this coule be achieved with anything
other than OOP (even if the OOP has to be "simulated" in a
language that doesn't have explicit support).
Ben Bacarisse <ben.usenet@bsb.me.uk>: Aug 26 07:36PM +0100

> CPUs. This even if you manage objects by value putting them in arrays.
> (While putting them by-value into arrays does help quite some, it's
> still not optimal.)
 
A minor point of little practical value is that the collecting together
is only in the source code. One could imagine a OO language that could
arrange for vectors of object to have certain properties arranged in
contiguous storage. It would probably be complex to manage, but it
might be possible.
 
> If you just dynamically allocated every object individually, it will
> be much worse. Now they will be all over the place, at random
> locations in memory.
 
Right. But this is in part bad design. I blame the rather simplistic
view of OO that gets pushed by online tutorials and so on. There is no
reason to consider position to be an intrinsic property of an object.
Object locations could be stored contiguously in an instance of a
LocationArray class and linked (vie pointers or indexes) or otherwise
associated with the object or objects that have those locations.
 
--
Ben.
Cholo Lennon <chololennon@hotmail.com>: Aug 25 09:50PM -0300

On 8/25/20 12:46 AM, Richard wrote:
>> was awful, but the size stayed around 40 Kb.
 
> You may want to look at the compile-time regex library:
> <https://github.com/hanickadot/compile-time-regular-expressions>
 
Nice library, thanks :-) I'll be testing it.
 
--
Cholo Lennon
Bs.As.
ARG
boltar@nuttyella.co.uk: Aug 26 07:53AM

On Tue, 25 Aug 2020 09:29:49 -0700 (PDT)
 
>> https://en.wikipedia.org/wiki/Star_Wars_(1983_video_game)
 
>Yes, the math hasn't changed but the performance. Few lines on 320 x 200
>pixels and 16 colors screen 6 frames per second. You now get 100
 
It was vector graphics, not raster. And I assume you mean 60 fps.
 
>times more lines on 6 x 6 times bigger screen that are 8 times more
>colorful at 10 times faster rate. So 100 * 6 * 6 * 8 * 10 ... 288 000
>times more processing needed. But as in everything there are GPUs that
 
Do you really think the graphics in his example were 288K times better?
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: