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



## Fredeke (May 30, 2019)

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

```
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 ?


----------



## P.N. (May 30, 2019)

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.


----------



## EvilDragon (May 30, 2019)

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.


----------



## Fredeke (May 30, 2019)

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.


----------



## P.N. (May 30, 2019)

Fredeke said:


> We should do some speed tests...



You mean like... a race? Seems fun. :D


----------



## Lindon (May 30, 2019)

Fredeke said:


> 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)


----------



## Levitanus (May 30, 2019)

operators precendencein KSP (from hight to low):
(brackets)

```
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...


----------



## EvilDragon (May 30, 2019)

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


----------



## P.N. (May 30, 2019)

Here's an idea:

Ditch the compiler completely and only work in native KS. Who's with me? :D
Anyone?...


----------



## Fredeke (May 30, 2019)

Levitanus said:


> operators precendencein KSP (from hight to low):
> (brackets)


Yes but that wasn't the question.



EvilDragon said:


> 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 



Lindon said:


> 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.



Lindon said:


> 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.



P.N. said:


> 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 )


----------



## EvilDragon (May 30, 2019)

Fredeke said:


> 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.


----------



## Lindon (May 30, 2019)

EvilDragon said:


> 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.


Well actually I was using IBM System360's but yeah clock cycles - meh...


----------



## Fredeke (May 30, 2019)

EvilDragon said:


> 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.


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...?


----------



## EugenioBruno (May 30, 2019)

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:


```
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:

```
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.


----------



## EvilDragon (May 30, 2019)

Fredeke said:


> 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.



EugenioBruno said:


> 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).


----------



## Fredeke (May 30, 2019)

EugenioBruno said:


> 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.



EvilDragon said:


> KSP is extremely optimized for realtime performance within the audio thread.


Then I'll stop worrying so much.

Thank you all for the discussion


----------



## wst3 (May 30, 2019)

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.


----------



## neblix (May 30, 2019)

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.



wst3 said:


> 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.


----------



## Fredeke (May 30, 2019)

neblix said:


> 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.



Ok, point made.



neblix said:


> 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).



wst3 said:


> 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 ...



neblix said:


> 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.


----------



## neblix (May 30, 2019)

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.


----------



## Fredeke (May 30, 2019)

neblix said:


> 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.


Thanks for sharing the experience. It's precious info.


----------



## Mike Greene (May 30, 2019)

You may already know this (or maybe someone mentioned it and I missed it), but you can test this pretty easily using the $KSP_TIMER variable, which tells you the clock position in microseconds. You'd do something like this:


```
$Start_Time := $KSP_TIMER
$i := 1
while ($i < 25000)
   if (complicated conditional ::: version 1)
      inc($i)
   end if
end while
$Total_Time := $KSP_TIMER - $Start_Time
message ("Version 1 took " & $Total_Time & " microseconds")
```

Then do the same thing for your alternate conditional ordering.

Note that you don't want to have anything other than simply incrementing the counter inside the while loop, since you don't want excess fluff to pad your time results.


----------



## EvilDragon (May 30, 2019)

And, since we now have floats, you can actually divide that KSP timer with those 25000 iterations to get a more accurate number (sorta).


----------

