NOP+nested code.

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
Liviu
Expert
Posts: 470
Joined: 13 Jan 2012 21:24

Re: NOP+nested code.

#16 Post by Liviu » 17 Mar 2014 01:15

einstein1969 wrote:I have done some tests
Not entirely sure what your tests are meant to measure. If it's just about the raw performance of different NOPs then the if/echo/break alone will introduce noise unrelated to the actual NOP being measured.

einstein1969 wrote:i have removed the comment but the problem remain: :(
Haven't followed your code or use-case in detail, but as a general note... Checking centi-seconds for equality like 'if "!time:~9,2!"=="99"' is inherently fragile. There is no guarantee whatsoever that a 'for' loop will execute in less that 10ms. Of course, that's usually the case, but if you run the batch while a high-priority task executes, or if someone else runs it in a terminal console on an undersized/overloaded server, the difference in %time% between consecutive iterations can potentially be arbitrarily large.

Liviu

einstein1969
Expert
Posts: 941
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: NOP+nested code.

#17 Post by einstein1969 » 17 Mar 2014 11:04

Thanks Liviu for your comments. You make me think

is that I have mixed functional and performance tests together. But I think they're indicative though not precise.
How do you see the command title suffers from a problem when using code with pipe.
The rem: it takes more time perhaps for the thing that you have discovered with the process monitor. Your tests are much more comprehensive and complete. Thank you.

However, before I read your comment I had already carried out tests under load. Even if I move on systems that are not non-server.

Unfortunately I do not have a multi-cpu/core and I can not test it thoroughly.

Yesterday I was able to run the code and I've tried what happens on my windows seven Monocore.

My project is a HEARTBEAT with minimum use of CPU / LATENCY using PING.

I am aware that another problem is the set /p with CR LF but for the moment it seems to work.

Code: Select all

(

start "" /B /realtime cmd /V:ON /Q /C"cmd /V:ON /Q /Cfor /l %%k in (0) do for %%l in (99 00) do (if "^^^^!time:~9,2^^^^!"=="%%l" (exit)) & start "" /B /realtime ping ::1 -n 135"
ping ::1 -n 4 >nul
start "" /B /realtime cmd /V:ON /Q /C"cmd /V:ON /Q /Cfor /l %%k in (0) do for %%l in (49 50) do (if "^^^^!time:~9,2^^^^!"=="%%l" (exit)) & start "" /B /realtime ping ::1 -n 135"
ping ::1 -n 4 >nul
start "" /B /realtime cmd /V:ON /Q /C"cmd /V:ON /Q /Cfor /l %%k in (0) do for %%l in (24 25) do (if "^^^^!time:~9,2^^^^!"=="%%l" (exit)) & start "" /B /realtime ping ::1 -n 135"
ping ::1 -n 4 >nul
start "" /B /realtime cmd /V:ON /Q /C"cmd /V:ON /Q /Cfor /l %%k in (0) do for %%l in (74 75) do (if "^^^^!time:~9,2^^^^!"=="%%l" (exit)) & start "" /B /realtime ping ::1 -n 135"

) | start "" /B /realtime find "<" | start "" /B /realtime cmd /v:on /c"for /l %%k in (1,1,1000) do @(set/p "l=" & echo tick: !time! )"


I have been studying a system of resynchronization light load.
The frequency is 4 ticks per second and requires a resynchronization with high usage of cpu.
With greater frequency the cpu usage time for resynchronization should be less and also the error is smaller.
Ping produces minimum 500ms, with this system I can get down to 50 ms or less (at no load system, for the moment).

ref: Watchdog_timer

einstein1969

einstein1969
Expert
Posts: 941
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: NOP+nested code.

#18 Post by einstein1969 » 17 Mar 2014 11:51

a question:

this code do filesystem access?

Code: Select all

for %%l in (99 00) do ...


einstein1969

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

Re: NOP+nested code.

#19 Post by Ed Dyreen » 17 Mar 2014 14:43

einstein1969 wrote:a question:

this code do filesystem access?

Code: Select all

for %%l in (99 00) do ...


einstein1969
What Liviu has observed is a disk access, I assume this happens when a command is not recognized, then the system reasons it must be external and start looking for it in the current directory and then in the path if it is set. An external command is an executable file that ends in exe or com. For.exe does not exist on disk so it must be internal. Sysinternals provides the tool Liviu used for free. The REM: command is eventually recognized but behaves differently now.

einstein1969
Expert
Posts: 941
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: NOP+nested code.

#20 Post by einstein1969 » 17 Mar 2014 15:15

Ed Dyreen wrote:
einstein1969 wrote:a question:

this code do filesystem access?

Code: Select all

for %%l in (99 00) do ...


einstein1969
What Liviu has observed is a disk access, I assume this happens when a command is not recognized, then the system reasons it must be external and start looking for it in the current directory and then in the path if it is set. An external command is an executable file that ends in exe or com. For.exe does not exist on disk so it must be internal. Sysinternals provides the tool Liviu used for free. The REM: command is eventually recognized but behaves differently now.


Hi Ed,

thanks for your support. I know sysinternal utility but I not have know of low level function/aspect of windows. Time ago i have see this Windows Sysinternals Primer but not learn to much. It's very advanced for me.

I have resolved the previus problem with nested code eliminating the surround quote for the nested cmd /c. But i think that is a workaround.
I don't know why this work :oops:

I have see your code and for there i start. Thanks again Ed.

If you know how resolve using the quote (") than give me!

I have seen the "inject delay once" in the macro you posted previusly and it seems to me something magical :shock: . Maybe because I have no experience in this direction.

In the help of FOR command the for %var in (group) , the group is descrived how a group of files. For what was done was wondering if access to the filesystem.

If so would slow down the execution of the code.

einstein1969

Liviu
Expert
Posts: 470
Joined: 13 Jan 2012 21:24

Re: NOP+nested code.

#21 Post by Liviu » 17 Mar 2014 18:59

einstein1969 wrote:How do you see the command title suffers from a problem when using code with pipe.
I didn't really follow that through. Anyway, I don't think title is a plausible candidate for a NOP, so it's not of much practical interest.

Unrelated, but I don't think 'break' is a good NOP candidate, either. The help mentions "If Command Extensions are enabled, and running on the Windows platform, then the BREAK command will enter a hard coded breakpoint if being debugged by a debugger". Granted, that's not likely to happen to most users, but it still makes it less than a true NOP.

einstein1969 wrote:this code do filesystem access? [...] In the help of FOR command the for %var in (group) , the group is descrived how a group of files. For what was done was wondering if access to the filesystem.
The FOR/L won't make any file access attempts - except if you attempt to use file modifiers on the variable such as %%~fX, but that'd be downright pointless. Even a plain FOR loop won't access files unless the names contain ?* wildcards, or - again - you use file modifiers on the variable.

Ed Dyreen wrote:What Liviu has observed is a disk access, I assume this happens when a command is not recognized, then the system reasons it must be external and start looking for it in the current directory and then in the path if it is set.
My assumption is that it's triggered by extension and path-like characters :\/. in cases the command doesn't literally match the internal name. For example, 'echo' wil always run the internal command regardless of what's on disk, and without ever checking the filesystem. But 'echo.' with a trailing '.' dot will fail if there is a file named 'echo' in the current directory, otherwise it will ignore the '.' and fallback to the builtin 'echo'. Likewise for 'echo\abc.bat' if a subdirectory '.\echo' exists and contains a file '.\echo\abc.bat'. It's a bit less obvious, but the same applies to 'echo:abc.bat' if a file '.\echo' exists with an ADS (alternate data stream) named 'abc.bat' - cmd will recognize the ADS, but fail to actually run it, possibly due to security concerns.

Liviu

penpen
Expert
Posts: 1992
Joined: 23 Jun 2013 06:15
Location: Germany

Re: NOP+nested code.

#22 Post by penpen » 21 Apr 2014 05:44

I think i have found another candidate for NOP: "rem^ "
This time it is without any QueryOpen access (at least under win xp home 32 bit).

Code: Select all

if 0==0 (rem^ ) else echo 0
if 0==1 (rem^ ) else echo 1

penpen

Squashman
Expert
Posts: 4470
Joined: 23 Dec 2011 13:59

Re: NOP+nested code.

#23 Post by Squashman » 21 Apr 2014 07:05

penpen wrote:I think i have found another candidate for NOP: "rem^ "
This time it is without any QueryOpen access (at least under win xp home 32 bit).

Code: Select all

if 0==0 (rem^ ) else echo 0
if 0==1 (rem^ ) else echo 1

penpen

I have been trying to follow this thread but am wondering what real world example you would use for that code? Or are you just trying to provide an example of when code is not executed. Because I guess I don't see any real world example to use an IF ELSE like that. I guess I would just write it like this instead.

Code: Select all

if 0==0 || echo 0
if 0==1 || echo 1

Or just use an IF NOT instead.

penpen
Expert
Posts: 1992
Joined: 23 Jun 2013 06:15
Location: Germany

Re: NOP+nested code.

#24 Post by penpen » 21 Apr 2014 08:02

Einstein1969 (OP) uses "break" as a NOP command in a single line (cmd /C "... if ...==... (break) else ... "), and
he wanted to get some alternatives - i assume to choose the fastest.

The default "rem" make the batch file to ignore the rest of the line.
My examples just should show, that "rem:" and "rem^ " behaves different, and
it is possible to use the rest of the line as batch code:
Especially it could be used to be built into his "if condition (NOP) else ..." case,
so the "if else statement" works no matter if the condition is computed to true, or false.

penpen

jfl
Posts: 226
Joined: 26 Oct 2012 06:40
Location: Saint Hilaire du Touvet, France
Contact:

Re: NOP+nested code.

#25 Post by jfl » 18 Jan 2024 07:13

I searched for a discussion about a good NOP command, and only found this old one.

While investigating why my %WHILE(% macro was slower that my %REPEAT% macro, I began to suspect that the culprit was a (set -=) instruction, that was used as a NOP.
After finding this discussion, I timed that particular NOP, then the alternatives listed above in this discussion, then a few more that I thought about.
I timed them by running them 10⁵ or 10⁶ times in a for /l loop.
Results:

Code: Select all

(set -=)         89µs
(set -=-)        88µs
break            81µs
(rem.)          121µs
(rem:)          115µs
(rem^ )          82µs
(echo>nul)      181µs
(if 1==0 break)   1.7µs
(if 1==0 cd)      1.7µs
(if 1==0 .)       1.7µs
Conclusion: Unless anybody finds a major issue with it, now on I'll use the following NOP macro:

Code: Select all

set "NOP=(if 1==0 .)"
And (spoiler) this resolves the performance issue in my %WHILE(% macro :)

jeb
Expert
Posts: 1042
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: NOP+nested code.

#26 Post by jeb » 19 Jan 2024 06:57

I build a test script to measure the time and check if the constructs would work with FOR-meta-variable expansions.
"rem=" or "rem," are still the winner, but even "if %%? == 0" and 'FOR /F %%? in ("%%~?") DO ' are still fast enough

Neither "echo>nul" nor "rem^ " can't be used as switchable NOP. Because after the FOR-meta-var expansion they can't be parsed anymore.

These are the results:

Code: Select all

Test  1:  69.9us  total-time=    6990ms "set -="
Test  2:  70.5us  total-time=    7050ms "set -=-"
Test  3:  81.3us  total-time=    8130ms "break="
Test  4:  92.1us  total-time=    9210ms "rem."
Test  5:  92.7us  total-time=    9270ms "rem:"
Test  6:   1.6us  total-time=     160ms "rem="
Test  7:   1.8us  total-time=     180ms "rem,"
Test  8:   2.5us  total-time=     250ms "if %0==0 "
Test  9:   4.8us  total-time=     480ms "for /F %1 in ("%~1") do "
Der Befehl "echo>nul" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
Test 10: 145.6us  total-time=   14560ms "echo>nul "
Der Befehl "rem^" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
Test 11:  24.4us  total-time=    2440ms "rem^ "

Code: Select all

@echo off
setlocal
set count=100000

set testNo=0

call :test "set -="
call :test "set -=-"
call :test "break="
call :test "rem."
call :test "rem:"
call :test "rem="
call :test "rem,"
call :test "if %%%%0==0 " noCap
call :test "for /F %%%%1 in (""%%%%~1"") do " noCap
call :test "echo>nul "
call :test "rem^ "
exit /b

:test
set /a testNo+=1
setlocal EnableDelayedExpansion
set "NopCmd=%~1"
set "NopCmd=!NopCmd:^^=^!"
set "NopCmd=!NopCmd:""="!"
set "start_ts=%time%"
if "%~2" == "" call :checkCapability

for /F "tokens=1-2" %%0 in ("1 ") do (
  for /L %%n in (1 1 %count%) DO (
    %NopCmd%date
  )
)

setlocal EnableDelayedExpansion
set "end_ts=!time!"
call :bl.DateTime.timeDiff total_dur "!start_ts!" "!end_ts!"
set /a per_run_us=total_dur*10000/count
set "_total_dur=      !total_dur!"
set "_per_run_us=     !per_run_us:~0,-1!.!per_run_us:~-1!"
set "_testNo=  !testNo!"
echo Test !_testNo:~-2!: !_per_run_us:~-5!us  total-time=!_total_dur:~-8!ms "!NopCmd!"
endlocal
endlocal

exit /b

:checkCapability
set nop_work=true
set "execCommand=set nop_work=false"
FOR /F "delims=" %%? in ("!NopCmd!") DO (
  %%?%execCommand%
)
if "!nop_work!" NEQ "true" echo NOP doesn't work
exit /b

::###############################
::### WARNING, enclose the time in quotes ", because it can contain comma seperators
:bl.DateTime.timeDiff <resultVar> <start_time> <end_time>
(
  SETLOCAL EnableDelayedExpansion
  if "%~4" NEQ "" (
    echo ERROR in :bl.DateTime.timeDiff too much parameter
   exit /b 4
  )
  call :bl.DateTime.timeToMs ms_start "%~2"
  call :bl.DateTime.timeToMs ms_end "%~3"
)
set /a diff_ms=ms_end - ms_start
(
  ENDLOCAL
  set %~1=%diff_ms%
  goto :eof
)
::End of function

::###############################
:bl.DateTime.timeToMs <resultVar> <time>
::### WARNING, enclose the time in quotes ", because it can contain comma seperators
::### WARNING it does not convert time in am/pm format, because it's regressive
SETLOCAL
FOR /F "tokens=1,2,3,4 delims=:,.^ " %%a IN ("%~2") DO (
  set /a ms=^(^(^(30%%a%%100^)*60+7%%b^)*60+3%%c-42300^)*1000+^(1%%d0 %% 1000^)
)
(
  ENDLOCAL
  set %~1=%ms%
  goto :eof
)
::End of function

Post Reply