Page 1 of 2
					
				Which one is faster
				Posted: Tue Dec 05, 2023 5:55 am
				by jacdelad
				Hello,
just out of curiosity, which one is faster (on ASM backend)?
Code: Select all
Procedure Limit(x.l)
  If x>255
    x=255
  ElseIf x<0
    x=0
  EndIf
  ProcedureReturn x
EndProcedure
or
Code: Select all
Procedure Limit(x.l)
  If x>255
    ProcedureReturn 255
  ElseIf x<0
    ProcedureReturn 0
  Else
    ProcedureReturn x
  EndIf
EndProcedure
or
Code: Select all
Procedure Limit(x.l)
  If x>255
    ProcedureReturn 255
  ElseIf x<0
    ProcedureReturn 0
  EndIf
  ProcedureReturn x
EndProcedure
?
I would guess the first one is the slowest, but how about the second and third? How does the Else affect speed? And I know, the difference (if any) is almost unmeasureable, I'm just asking out of curiosity.
 
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 6:07 am
				by STARGÅTE
				You have to think different. What is the parameter space of Limit()?
You function Limit() is slowest when 
x is between 0 and 255, because then the first and second if is false and you have two additional jumps.
Further, you have to swap x>255 with x<0, when you think that Limit() receives more likely a value below 0 than above 255.
This means, the following function could be faster, when most of the times 
x is between 0 and 255, because you have then just one query and no jump.
Code: Select all
Procedure Limit(x.l)
	If x & (~$FF) = 0
		ProcedureReturn x
	ElseIf x < 0
		ProcedureReturn 0
	Else
		ProcedureReturn 255
	EndIf
EndProcedure
 
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 6:31 am
				by RASHAD
				Hi jacdelad
Maybe 
The speed must be checked  
 
Code: Select all
Procedure Limit(x.l)
  While x < 256 And x >= 0
    ProcedureReturn x
  Wend
EndProcedure
Debug Limit(10)
 
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 6:46 am
				by jacdelad
				Thanks for the answers.
@STARGATE: Yes, I forgot about what scenario might be more likely, values above, below, or withing the range. Let's look at the case, they are within the range, is it faster to use Else or better put the ProcedureReturn outside the If?
@RASHAD: This does not work for values above 255 or below 0. And why use a loop at all?
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 6:47 am
				by AZJIO
				Code: Select all
Procedure RangeCheck(value, min, max)
	If value < min
		value = min
	ElseIf value > max
		value = max
	EndIf
    ProcedureReturn value
EndProcedure
s = ReadPreferenceInteger("num", s)
s = RangeCheck(s, 20, 40)
"Limit4" is the best if the number is inside the range
Code: Select all
DisableDebugger
Procedure Limit1(x.l)
  If x>255
    x=255
  ElseIf x<0
    x=0
  EndIf
  ProcedureReturn x
EndProcedure
Procedure Limit2(x.l)
  If x>255
    ProcedureReturn 255
  ElseIf x<0
    ProcedureReturn 0
  Else
    ProcedureReturn x
  EndIf
EndProcedure
Procedure Limit3(x.l)
  If x>255
    ProcedureReturn 255
  ElseIf x<0
    ProcedureReturn 0
  EndIf
  ProcedureReturn x
EndProcedure
Procedure Limit4(x.l)
	If x & (~$FF) = 0
		ProcedureReturn x
	ElseIf x < 0
		ProcedureReturn 0
	Else
		ProcedureReturn 255
	EndIf
EndProcedure
Procedure Limit5(x.l)
	If x < 0
		ProcedureReturn 0
	ElseIf x > 255
		ProcedureReturn 255
	EndIf
    ProcedureReturn x
EndProcedure
#num = 11
#count = 10000000
StartTime = ElapsedMilliseconds()
For i = 0 To #count 
	Limit1(#num)
Next
xx = ElapsedMilliseconds() - StartTime
StartTime = ElapsedMilliseconds()
For i = 0 To #count 
	Limit2(#num)
Next
yy = ElapsedMilliseconds() - StartTime
StartTime = ElapsedMilliseconds()
For i = 0 To #count 
	Limit3(#num)
Next
zz = ElapsedMilliseconds() - StartTime
StartTime = ElapsedMilliseconds()
For i = 0 To #count 
	Limit4(#num)
Next
aa = ElapsedMilliseconds() - StartTime
StartTime = ElapsedMilliseconds()
For i = 0 To #count 
	Limit5(#num)
Next
bb = ElapsedMilliseconds() - StartTime
EnableDebugger
Debug xx
Debug yy
Debug zz
Debug aa
Debug bb
 
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 8:00 am
				by STARGÅTE
				jacdelad wrote: Tue Dec 05, 2023 6:46 am
Let's look at the case, they are within the range, is it faster to use Else or better put the ProcedureReturn outside the If?
 
There should be no difference, as there is no additional jump command, as long as you use ProcedureReturn in all cases.
To completely avoid jumps you can try to use this ASM code, which would be the fastest variant when using custom limits:
Code: Select all
Procedure.i Clamp(Value.i, Min.i, Max.i)
	! MOV rax, [p.v_Value]
	! CMP rax, [p.v_Min]
	! CMOVL rax, [p.v_Min] ; If Value < Min : Value = Min : EndIf
	! CMP rax, [p.v_Max]
	! CMOVG rax, [p.v_Max] ; If Value > Max : Value = Max : EndIf
	ProcedureReturn
EndProcedure
Debug Clamp(-5, 0, 255)
Debug Clamp(23, 0, 255)
Debug Clamp(300, 0, 255)
 
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 8:10 am
				by idle
				didn't see the posts by stargate clicked without looking 
if you want asm macro you can try this 
Code: Select all
Macro limit(x)  
 !mov     edx, 255
 !mov     eax, [v_x]
 !cmp     eax, edx
 !cmovg   eax, edx 
 !test    eax, eax
 !mov     edx, 0
 !cmovl   eax,edx
 !mov     [v_x],eax
EndMacro 
Define x.l    ;<--- needs to be a long   
x = -5 
limit(x) 
Debug x 
x = 258
limit(x) 
Debug x 
x = 126 
limit(x) 
Debug x 
 
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 8:25 am
				by RASHAD
				For x86 - x64
Code: Select all
Procedure.i LimitValues(Value.i, Min.i, Max.i)
	!mov eax,dword[p.v_Value]
	!xor edx,edx 
	!cmp eax,dword[p.v_Min]
	!cmovl eax,edx 
	!mov edx,dword[p.v_Max] 
	!cmp eax,edx 
	!cmovg eax,edx 
	ProcedureReturn
EndProcedure
Debug LimitValues(-5, 0, 255)
Debug LimitValues(23, 0, 255)
Debug LimitValues(300, 0, 255)
 
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 8:44 am
				by pjay
				For sure use macros to remove the Procedure call overhead with the ASM compiler.  They basically do what the C compiler should do (inline the functions).
I use standard If/Endif for simplicitys sake, as variable type & x86/x64 asm handling then become irrelevant.
Code: Select all
Macro Clamp01M(x) : If x < 0 : x = 0 : ElseIf x > 1 : x = 1 : EndIf : EndMacro
Macro Clamp255M(x) : If x < 0 : x = 0 : ElseIf x > 255 : x = 255 : EndIf : EndMacro
Macro ClampIM(in, min, max) : If in < min : in = min : ElseIf in > max : in = max : EndIf : EndMacro
Macro ClampIOM(out, in, min, max) : If in < min : out = min : ElseIf in > max : out = max : Else : out = in : EndIf : EndMacro
 
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 8:50 am
				by wilbert
				Code: Select all
Procedure Limit(x.l)
  ; limit between 0 and 255
  !movd xmm0, [p.v_x]
  !packssdw xmm0, xmm0
  !packuswb xmm0, xmm0
  !movd eax, xmm0
  ProcedureReturn
EndProcedure
Debug Limit(-10)
Debug Limit(1000)
Debug Limit(100)
 
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 9:26 am
				by jacdelad
				I really appreciate the approaches, but it was STARGATE who answered my question. I was really just asking for what is faster, the Else or not the Else.
Anyway, thanks to everyone who put some brain in here!
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 9:35 am
				by AZJIO
				pjay wrote: Tue Dec 05, 2023 8:44 am
For sure use macros to remove the Procedure call overhead with the ASM compiler.
 
The macro increases the code size. The size of the executable file increases and, as I understand it, in memory when executing code, when moving from label to label, the movement will be greater. If you use an empty function (for testing) and call it a million times, the overhead of running it will be negligible. Therefore, you should not complicate the code where speed is not required, but reduces the readability of the code or increases the size of the executable file.
 
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 10:08 am
				by jacdelad
				How should this task be done with a macro???
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 11:53 am
				by pf shadoko
				Hi there,
out of curiosity i wanted to compare with the c backend
try with and without debugger
can someone explain?
some modifications in the code to make sure it was really doing the calculations
important: I multiplied by 100 #count
Code: Select all
DisableDebugger
Procedure Limit1(x.l)
  If x>255
    x=255
  ElseIf x<0
    x=0
  EndIf
  ProcedureReturn x
EndProcedure
Procedure Limit2(x.l)
  If x>255
    ProcedureReturn 255
  ElseIf x<0
    ProcedureReturn 0
  Else
    ProcedureReturn x
  EndIf
EndProcedure
Procedure Limit3(x.l)
  If x>255
    ProcedureReturn 255
  ElseIf x<0
    ProcedureReturn 0
  EndIf
  ProcedureReturn x
EndProcedure
Procedure Limit4(x.l)
	If x & (~$FF) = 0
		ProcedureReturn x
	ElseIf x < 0
		ProcedureReturn 0
	Else
		ProcedureReturn 255
	EndIf
EndProcedure
Procedure Limit5(x.l)
	If x < 0
		ProcedureReturn 0
	ElseIf x > 255
		ProcedureReturn 255
	EndIf
    ProcedureReturn x
EndProcedure
#num = 11
#count = 1000000000
StartTime = ElapsedMilliseconds()
For i = 0 To #count 
	a+Limit1(#num)
Next
xx = ElapsedMilliseconds() - StartTime
StartTime = ElapsedMilliseconds()
For i = 0 To #count 
	a+Limit2(#num)
Next
yy = ElapsedMilliseconds() - StartTime
StartTime = ElapsedMilliseconds()
For i = 0 To #count 
	a+Limit3(#num)
Next
zz = ElapsedMilliseconds() - StartTime
StartTime = ElapsedMilliseconds()
For i = 0 To #count 
	a+Limit4(#num)
Next
aa = ElapsedMilliseconds() - StartTime
StartTime = ElapsedMilliseconds()
For i = 0 To #count 
	a+Limit5(#num)
Next
bb = ElapsedMilliseconds() - StartTime
EnableDebugger
MessageRequester("somme : "+a,""+xx+#LF$+yy+#LF$+zz+#LF$+aa+#LF$+bb)
Debug xx
Debug yy
Debug zz
Debug aa
Debug bb
 
			 
			
					
				Re: Which one is faster
				Posted: Tue Dec 05, 2023 12:09 pm
				by pjay
				You're passing the functions an unchanging value, so the compiler is optimizing it away (when the optimizer is enabled that is).