sed idle time

Hi,

I was trying to find the best way to get the idle time with sed and found that I don’t understand this script:

delay 3
set seconds_text to do shell script "ioreg -c IOHIDSystem | sed -n '/HIDIdleTime/ {;s/[^0-9]*//;h;};$x;$p'"
set idle_seconds to seconds_text / (10 ^ 9)

I don’t understand why the $x and $p executes only when the last line is reached (as it seems). I couldn’t find much documentation on the $ in sed scripts.

Edited: maybe $ means only execute when the last line is in read into the pattern space.

Thanks,
kel

Hello kel.

It is the address of the last line, (anchor) : 1,$ selects each line.

So the sedscript switches the hold buffer and pattern buffer when it reaches the last line, and the prints it. Those commands are paralllel to the search pattern, as range operators for a command.

Hi McUsr,

I see now about the $ being the address of the last line and thus a range.

It was really bothering me not understanding this. You are the light.

Thanks a lot and have a good day,
kel

That’s why it works now with the $g:

delay 3
set seconds_text to do shell script "ioreg -c IOHIDSystem | sed -n '/HIDIdleTime/ {;s/[^0-9]*//;h;};$g;$p'"
set idle_seconds to seconds_text / (10 ^ 9)

Thanks,
kel

Hi.

Just for interest, another way to do the sed process would be as in this script. Here only the line actually output is edited:

delay 3
set seconds_text to do shell script "ioreg -c IOHIDSystem | sed -n '/HIDIdleTime/ h;${g;s/[^0-9]*//p;}'"
set idle_seconds to seconds_text / (10 ^ 9)

Hi Nigel,

That makes sense to just edit the last line instead of editing each line. It seems like it should be faster.

You guys are great!

Thanks a lot for the heads up,
kel

I wonder if it’s best to delete the first part of the paragraph (as I did) or to remember the pattern for the number of nano seconds. It probably doesn’t matter very much with sed’s speed.

Edited: when I try to remember the pattern with (pattern) it takes a lot more typing and thinking.

I threw away the other script, so had to rewrite it. This is what I meant about remembering the idle time pattern and how there was more typing:

delay 3
set seconds_text to do shell script "ioreg -c IOHIDSystem | sed -n '/HIDIdleTime/ h;${g;s/[^0-9]*\\([0-9][0-9]*$\\)/\\1/p;}'"
set idle_seconds to seconds_text / (10 ^ 9)

I timed the two scripts and their differences are negligible.

Thanks for all the help,
kel

Hi,

I think Nigel’s last mod to the script optimized it. :slight_smile:

delay 3
set seconds_text to do shell script "ioreg -c IOHIDSystem | sed -n '/HIDIdleTime/ h;${g;s/[^0-9]*//p;}'"
set idle_seconds to seconds_text / (10 ^ 9)

Now to get it to work with the info from pmset. Getting there!

Thanks a lot,
kel

ps. having fun now instead of reading and reading and reading …

Nevermind, I just remembered that Grymore covered it.

one of the reasons I love AWK is not only it’s speed but also it’s readability:

set idleTimeInSeconds to (do shell script "ioreg -c IOHIDSystem | AWK -F = '/HIDIdleTime/{R=$2} END{print R}'") / (10 ^ 9)

I don’t think this code needs any explanation.

Spoken like a true believer :wink:

:smiley:

A poll would be interesting. But it is a whole lot easier to understand than sed, it is possible to deduce what is going on, at least when you have the output of ioreg table side while reading the snippet.

Nice Awk script. Very readable.

Hi,

Just for fun I ran timed the awk and see scripts. It just so happened that on one run both had the same times! Check this out:

sed:

awk:

The first number is execution time. The other one is delay time. I used my python timer with calibration. On the other tests they flip flopped.

Maybe need to do Nigel’s 1000 iteration test. :slight_smile:

Just for fun.

Edited: should have posted one of the scripts:

run script (do shell script "python -c 'import time; print time.time()'") --dummy
set t1 to run script (do shell script "python -c 'import time; print time.time()'")
set t2 to run script (do shell script "python -c 'import time; print time.time()'")
set time_calib to t2 - t1
delay 3
set t1 to run script (do shell script "python -c 'import time; print time.time()'")
--
set idleTimeInSeconds to (do shell script "ioreg -c IOHIDSystem | AWK -F = '/HIDIdleTime/{R=$2} END{print R}'") / (10 ^ 9)
--
set t2 to run script (do shell script "python -c 'import time; print time.time()'")
{t2 - t1 - time_calib, idleTimeInSeconds}

Edited: I might as well post the sed script:

run script (do shell script "python -c 'import time; print time.time()'") --dummy
set t1 to run script (do shell script "python -c 'import time; print time.time()'")
set t2 to run script (do shell script "python -c 'import time; print time.time()'")
set time_calib to t2 - t1
delay 3
set t1 to run script (do shell script "python -c 'import time; print time.time()'")
--
set idle_seconds to (do shell script "ioreg -c IOHIDSystem | sed -n '/HIDIdleTime/ h;${g;s/[^0-9]*//p;}'") / (10 ^ 9)
--
set t2 to run script (do shell script "python -c 'import time; print time.time()'")
--set idle_seconds to seconds_text / (10 ^ 9)
{t2 - t1 - time_calib, idle_seconds}

Once you’re in the shell it’s fast.

kel

In the 1000 iterations test :smiley: awk won by at least .01 I’m totally convinced that awk is faster (in this).

Now I can try to sleep.

In the sed vs awk (vs perl) you have to be aware that sed is the most fastest one and perl the most versatile. The reason I prefer awk is that it uses a bit of both: it’s readable, more versatile than sed and faster than perl, in fact for most regular expression handling/text processing AWK is only 25% slower than sed which isn’t much. AWK became so popular in the 80’s that people wrote almost complete programs in AWK while Kernighan (and his two co-developers) never intended it to be a complete programming language, you should use C instead. But don’t think that every awk is as good as any, I’m glad that Mac OS X ships with the one-true-awk version which is IMO the best awk version. The other awk version are sort of extended versions with more functions etc… but comes with a cost: less performance. There is an byte coded version of AWK which is 4 - 6 times faster than sed. Unfortunately it’s known to be very sensitive (read:buggy).

The reason I respond to this topic because the “benchmark” has to be very inacurate. First of all, both awk and sed will use of the total cpu needed of the code that’s been executed. To perform an more accurate “becnhmark” we need to get rid of most of the overhead:

  1. first put all the commands in a single shell script
  2. put ioreg results in a single command

I came with something like this:

return do shell script "#!/bin/sh
# time the overhead
dummy1=$(python -c 'import time; print time.time()')
dummy2=$(python -c 'import time; print time.time()')

# bash doesn't support floating point math so we're using awk (could use bc too)
overhead=$(awk '{print $1-$2}' <<< \"$dummy2 $dummy1\")

# now we only want to invoke ioreg command once to avoid more overhead
buffer=$(ioreg -c IOHIDSystem)

# setting the starttime
starttime=$(python -c 'import time; print time.time()')

# repeat the awk command 1000 times
for (( i=1; i<=1000; i++ ))
do
AWK -F = '/HIDIdleTime/{R=$2} END{print R}' <<< \"$buffer\" >/dev/null
done

# we're done; time again
endtime=$(python -c 'import time; print time.time()')

# subtract the time difference so we know the elapsed time but also subtract the overhead
awktime=$(awk '{print $1-$2-$3}' <<< \"$endtime $starttime $overhead\")
echo \"Time elapsed by awk: $awktime\"

# setting the starttime
starttime=$(python -c 'import time; print time.time()')

# repeat the sed command 1000 times
for (( i=1; i<=1000; i++ ))
do
sed -n '/HIDIdleTime/ h;${g;s/[^0-9]*//p;}' <<< \"$buffer\" >/dev/null
done

# we're done; time again
endtime=$(python -c 'import time; print time.time()')

# subtract the time difference so we know the elapsed time but also subtract the overhead
sedtime=$(awk '{print $1-$2-$3}' <<< \"$endtime $starttime $overhead\")
echo \"Time elapsed by sed: $sedtime\"

#just for fun show the difference in percentages
ratio=$(awk '{print ($1/$2-1)*100}' <<< \"$awktime $sedtime\")
echo \"Sed performed the task $ratio% better than awk\""

Keep in mind that still more than half of the code is overhead (communication between bash and commands etc…). I report a time difference ratio back because time in seconds is almost useless without having any information about the machine at all. The most remarkable thing that pops up on my machine after running the code about 20 times (to get a good indication) is not that sed is faster but the ratio differences between each run. On my machine the ratio is mostly 20 - 25% more speed from sed, but once in a while it seems that sed makes a jump in performance and become 50% faster while awk is steady in time each time it ran.

The 20-25% performance difference between sed and awk is confirmed again as I predicted. However the difference in time is almost completely useless because when we time the ioreg command, both awk and sed uses less than 20% of the total cpu time of the two commands. With the overhead of the do shell script command and coercion of variable will put both sed and awk in about 5% of the total cpu needed to complete the command in AppleScript. The 20% in performance difference of awk and sed (including all the surrounding code) is than set back to be around 1%.

conslusion
So in short sed is about 20% faster than awk, as expected and confirmed here. Because of the huge overhead of surrounding commands and AppleScript (including do shell script overhead) the overall winning for sed will be around 1%. So with such a marginally speed difference for this particular command it won’t matter which you should use, use to your most likings sed or awk. I prefer AWK, as I said before, because it’s syntax not that much of speed difference compared to sed (read:fast) and more versatile because of the built in functions. But, hey, that’s just my opinion. If performance is an real issue I prefer to write an command line utility myself, awk and sed can’t beat that.

edit: I’ve ran the script on an older MacBook Pro 8.2, 2.3 GHz Intel Quad Core i7 with 8GB 1333MHz DDR3 Memory using Mac OS X 10.6. I ran the code on my other machine with Mountain Lion which is an MacBook Pro 10.1, 2.6 GHz Intel Quad Core with 16 GB 1600MHz DDR3 Memory. The funny thing I found out that the awk command has the same execution time (would expect faster) but the weird thing is that on the newer machine the sed command is slower in time and the time difference in awk and sed is stable at 5%. I never knew that the performance of sed on newer machine are worse than older machine with older OS.

So I can image that kel1 is having a machine where awk even performs faster than sed. I’m surprised of the unstable performance of sed in the first place but also the unexpected performance difference on different machines. Another reason to like awk even more;)

Hello.

I don’t have Mountain Lion, so I can’t verify this, but at least the latest official version of sed has unicode support, and if that version has made it to the Mountain Lion, then that may be a possible explanation.

But I guess, to really find out, then you’ll have to look at the source code of the two. As far as I know, both should use the same regexp library, so it isn’t there the culprit lies. That regexp library, is 7 times faster than PCRE regexp library that perl uses. I have the 7 times figure, from the promises some guys has made, regarding to using the GPU for parsing regular expressions. I guess they have the timing in order.

That awk program, was very optimal, with regards to speed, don’t expect this result to be valid, for anything than awk programs that are streamlined for speed. Either by written after the same pattern as a sed program, or using associative arrays for accumulating unique lines. :slight_smile: