What's new

Very nerdy, low-level question about conditions in KSP ...

Fredeke

Senior Member
Sorry for flooding the forum... But I'm diving deep into scripting today, so I'm having a few questions.

Do we know in which order conditional statements are evaluated in KSP ?
Here's what I mean: if write something like
Code:
if (condition A and condition B)
the interpreter first evaluates one of the conditions (either A or B, depending on the language), and then only evaluates the other if it's relevant to do so. In this example, it would only evaluate the latter if the former is true, because if the former is false, then it knows the whole condition will be false anyway.

Knowing this, we can optimize our code for speed by tweaking the order of such statements. I'd like very much to do that, because sometimes I can hardly avoid complex conditions within loops.

So, does anyone know which side of and/or operators gets evaluated first ?
 
Last edited:
If i had to guess, i'd say the left side would be evaluated first, simply because of the order of the statement... but this is just a guess.

I never considered this too much in relation to how it may impact the speed, though.
Interesting.
 
I'm not sure there's any official info on that. I suppose it makes sense to do left to right, and AND takes precedence over OR as per usual.
 
We should do some speed tests... But I don't want to digress too much from my coding right now.
If I do that later, I'll post my findings here.
 
Last edited:
We should do some speed tests... But I don't want to digress too much from my coding right now.
If I do that later, I'll post my findings here.
I think if you are down this path because you need a speed bump then you've got bigger problems... evaluation order in compiler optimizations really only offer you way way way less than 1% improvement (in my experience)
 
operators precendencein KSP (from hight to low):
(brackets)
Code:
on init
  declare ui_label $print(3, 6)
  declare $x := 1
  declare $y := 2
  if ($x=1 and ($x=$y) or ($x=2 and ($x=$y)) or ($x # $y))
    add_text_line($print,"x#y is true")
  end if
  if (($x=1 and ($x=$y) or ($x=2)) and ($x=$y or ($x # $y)))
    add_text_line($print,"both are false, brackets mean")
  end if
end on
logical and
logical or
math ((*/) +-)
binary (.AND. .OR.)

I can't imagine KSP task needed to optimize condition evaluation...
 
I don't think any speed tests are necessary. if/else and binary operations are such rudimentary things any CPU executes them blazingly fast. You should spend your time elsewhere rather than worrying about these things :)
 
operators precendencein KSP (from hight to low):
(brackets)
Yes but that wasn't the question.

I don't think any speed tests are necessary. if/else and binary operations are such rudimentary things any CPU executes them blazingly fast. You should spend your time elsewhere rather than worrying about these things :)
Yes maybe... But as I said, sometimes they're inside loops ;)

I think if you are down this path because you need a speed bump then you've got bigger problems...
I don't have problems yet. I just don't want to wait for cycle waste to accumulate before worrying, because by then my code will already be a plate of spaghetti.

evaluation order in compiler optimizations really only offer you way way way less than 1% improvement (in my experience)
Well you know, it's 1% here and 1% there... But ok, I admit I was hoping for more.
Then, "in your experience" being the convincing part, I'll stop worrying about it for now.

Ditch the compiler completely and only work in native KS. Who's with me? :D
Anyone?...
You mean the KSE compiler? That's actually another layer I hadn't taken into account! Not sure it affects this matter though... (but you never know - it would require more testing, and at this point I tend to side with @Lindon ;))
 
Last edited:
But as I said, sometimes they're inside loops ;)

Doesn't matter, this is why loops in KSP are limited to around 40-50k iterations if you don't have a finite . And this is literally nothing for today's CPUs.

We're not using Spectrums anymore, there's no need to count CPU cycles. :grin:
 
Doesn't matter, this is why loops in KSP are limited to around 40-50k iterations if you don't have a finite . And this is literally nothing for today's CPUs.

We're not using Spectrums anymore, there's no need to count CPU cycles. :grin:
Well actually I was using IBM System360's but yeah clock cycles - meh...:grin:
 
Doesn't matter, this is why loops in KSP are limited to around 40-50k iterations if you don't have a finite . And this is literally nothing for today's CPUs.

We're not using Spectrums anymore, there's no need to count CPU cycles. :grin:
I may be paranoid but... My thought process was: KS interpretation must happen at a high level, built upon layers of layers of integration, which would multiply actual CPU cycles by an awful factor; so assuming the language is as badly optimized as it is ugly, maybe I should consider coding like I would for the Spectrum...?
 
Last edited:
The concept you're looking for, I think, is "short circuit". You should be able to test it in this way. In pseudocode, as I don't know KSP specifically:

Code:
function test_short_circuit()
  log_to_console("I Was evaluated. KSP does not have short circuit!")
  return true
end

if false and test_short_circuit() do
  print("test done")
end

if Kontakt has short circuiting, test_short_circuit() won't be evaluated. If it doesn't have short circuiting, it will be evaluated.

Usually languages have short circuiting to allow you to do something such as this:
Code:
if length(array) > 0 and array[0] != 0 and 20 / array[0] != 10 do
  print("hello world")
end

The second and third checks would be invalid if the first check fails, as the array has no items inside. The third check would be invalid if the second check failed, because you can't divide by 0.

With short circuiting, you can safely do the second and third checks. Without short circuiting, the above code would not be valid.
 
so assuming the language is as badly optimized as it is ugly

It's exactly the opposite, actually. KSP is extremely optimized for realtime performance within the audio thread.

if Kontakt has short circuiting, test_short_circuit() won't be evaluated. If it doesn't have short circuiting, it will be evaluated.

You cannot even do what you wrote in pseudocode (that first thing) in KSP. You cannot use a function as a variable for evaluation.

The second code snippet is valid in KSP (the first check for array size is not necessary because you cannot declare arrays with size 0 in KSP, though) but the branch won't be executed (nothing is gonna be printed out).
 
Last edited:
The concept you're looking for, I think, is "short circuit". You should be able to test it in this way.
I didn't now the term, thanks.
But I'm afraid @EvilDragon is right. KSP is too rudimentary for your test.

KSP is extremely optimized for realtime performance within the audio thread.
Then I'll stop worrying so much.

Thank you all for the discussion :)
 
Last edited:
I "grew up" at a time when one did count CPU cycles, especially for real time embedded systems. When we started working in C we would compile and examine the generated code to insure we were being as efficient as possible. I no longer remember the details, but branching statements differed wildly. If/Then resulted in one structure, case resulted in another. It was tedious, but necessary.

There is truth to the statement that today's CPUs are so powerful we no longer need to optimize the code. Until we do?

I think it shows great craftsmanship to care about the details.
 
Short circuit evaluation is a well documented computer science concept. It goes left to right after all other precedences are taken care of.

Your highest resolution of timing is microseconds in realtime with KSP timer. You will find that optimizing short circuit conditions will not save you even a single microsecond unless you are running Kontakt on a toaster.

You should still write your conditions to short circuit evaluate because it allows you to prevent invalid checks in consolidated conditions.

For example, let's say I had a variable "selected_idx". I want to check if an array spot at selected_idx is greater than 30.

I would do
"if array[selected_idx] > 30"

However if it were possible that selected_idx could be -1, implying nothing was selected and no action should be taken, this if statement would cause an array access error whenever that happens. To avoid that, I could short circuit the if statement like this

"if selected_idx # -1 and array[selected_idx] > 30"

The if statement will short circuit failing the first component (it IS equal to -1, therefore an AND operation will fail) and not attempt to check the array index at -1, preventing a Kontakt array index error.

I think it shows great craftsmanship to care about the details.

Standards of craftsmanship have evolved. If you were to optimize something to the point it is harder for another person to understand it at a glance, with only a fractional margin of a performance improvement as a trade-off, this would be bad craftsmanship. Maintainability and smooth collaboration are important aspects of craftsmanship that go beyond milking the CPU.

That doesn't apply here because short-circuits make conditions more readable (most important logic happens first) but I'm responding in general to the question of optimizing when your CPU's are powerful.
 
Last edited:
Your highest resolution of timing is microseconds in realtime with KSP timer. You will find that optimizing short circuit conditions will not save you even a single microsecond unless you are running Kontakt on a toaster.
:roflmao:
Ok, point made.

You should still write your conditions to short circuit evaluate because it allows you to prevent invalid checks in consolidated conditions.
Funny I didn't think about that earlier today. I do that all the time in PHP, and yet PHP is much more robust than KSP in regard to invalid checks (or shady statements in general).

There is truth to the statement that today's CPUs are so powerful we no longer need to optimize the code. Until we do?
I think it shows great craftsmanship to care about the details.
A friend of mine agrees with you and illustrates like this: "it's like pollution. One plastic container in the environment is no problem, but billions of them become one. Waste of computer (or network) resources accumulates the same way."
I've always agreed with him ...

If you were to optimize something to the point it is harder for another person to understand it at a glance, with only a fractional margin of a performance improvement as a trade-off, this would be bad craftsmanship. Maintainability and smooth collaboration are important aspects of craftsmanship that go beyond milking CPU cycles.
... and yet @neblix makes a good point.
 
Last edited:
I have created some of the most demanding Kontakt scripts on the market right now, such as Super Audio Cart's modulation matrix. It took a lot of optimization not to break people's older computers with just one instance. None of it happened in small little areas like changing orders of conditions or the number of variables I was using. It was big, structural changes that fixed glaring CPU issues. Stuff like sending thousands of values over PGS every knob turn instead of sending just one at a time using extra keys to provide metadata on what was changed. If I spent hours chasing the small things, it ultimately would have made no difference.

Speaking from experience in general, if you have CPU issues in your Kontakt scripts, it's not the small stuff. There is something much bigger doing it. Stuff like having a LP Filter on hundreds of groups and automating the knob that controls it, or using convolution reverb. Animating GUI stuff in your listener callback (LCB), or anywhere really. This stuff is what chugs.
 
Top Bottom