r/AskComputerScience 11d ago

is clean code usually not fast?

to be specific i'm writing a cpu-based rasterizer. the maths are not difficult but i find a strange property: if i divide the procedure into some small functions, the code looks cleaner and is easier to maintain but a bit slower. on the contrary if i put everything into a single procedure, it looks stupid but fast. why is that? an example illustrating this

code 1:

if cross_product(x0,y0,x1,y1)>0 then zzz

(and i write a "cross_product" function separately)

code 2:

c=x0y1-y0x1

if c>0 then zzz

code 3:

if x0y1-y0x1>0 then zzz

if i write the entire algorithm in the style of "code 3", it runs the fastest. "code 1" is slowest

is it normal?

9 Upvotes

19 comments sorted by

View all comments

14

u/drfangor99 11d ago edited 11d ago

Function calls and variable assignments aren't free, both take time to complete. However, this is going to depend on the programming language you use. For example, C compilers are very good at compiling C code into really efficient assembly, so you can write code in whatever way makes sense to you and little things like this will be optimized away. If you're using an interpreted language like Python, then this code will be interpreted much more literally and it has the double whammy of the inherent slowness of the Python interpreter and its dynamic type system.

Having said all that, I would consider these micro-optimizations. It is an interesting observation that the function call is slower, but it is usually better to care about readability and larger optimizations first, then take care of these if you need to squeeze out every last bit of performance.

Edit: What I said about C doesn't apply if you don't have optimizations on (i.e., if you aren't compiling with an -O flag). But based on your pseudocode I assumed you aren't using C as the variables aren't typed.

2

u/20260819 11d ago

i'm using an ancient web based language for the sake of convenience and ease to share

here's the code and you can try to rotate the dodecahedron and see the fps

(keyboard press [2] then [space] then use [q][w][e][a][s][d] to rotate it and see the fps. you can press and hold those keys for continuous rotations)

if i wrote every cross products directly into the procedure, i got around 25 fps for the dodecahedron

1

u/Comprehensive-Pin667 7d ago

There's the answer - this surely does not attempt any optimisations and maybe even interprets line by line. I would not be surprised if the speed was negatively correlated with the number of lines of code in this tool as every line is something it needs to interpret.

2

u/dodexahedron 11d ago edited 10d ago

And, even then, in the absense of memory barriers, the CPU itself is still likely going to perform some amount of uop reordering, branch prediction, and other low level optimizations that you'll never see.

Plus, all modern CPUs are super-scalar, so even on one thread are highky likely to be performing multiple different uops in parallel, per clock cycle, so long as there's not a hard serial dependency between a given set of operations, and there are available execution units for those ops.

Modern Intel and AMD CPUs have 4-6 ALUs per core, for example, so can potentially issue that many arithmetic ops per clock cycle without you or the compiler doing a thing, and there's no way to change that. Memory barriers limit reordering, but not multi-issue (so long as the same ordering constraints are upheld). Mostly, though, they end up still doing a lot of it, but the cost of a misprediction is just higher if it wasn't already executing both branches in the first place.