Showing posts with label measure. Show all posts
Showing posts with label measure. Show all posts

Thursday, May 29, 2008

Select and then Sort

 

When you use both select-object and sort-object in a pipeline, what's the proper order? Let's check how fast they execute.
Each speed test is built from two similar commands with a different sort/select piping order and each test is executed 10 times. The total execution time is measured in Milliseconds.

 

- Updated: 06/11/2008 (see comment below by Lee Holmes) -

 

Test #1

PS > (measure-Command { 1..10 | foreach { gsv | sort name | select name,status }}).TotalMilliseconds

444.5451


PS > (measure-Command { 1..10 | foreach { gsv | select name,status | sort name}}).TotalMilliseconds

384.7565


Result: Second command is 15% faster.

 

Test #2  

# this command is the third example of select-object command from the help files.

PS > (measure-command { 1..10 | foreach { gps | sort ws | select -last 5 }}).TotalMilliseconds

346.0652


PS > (measure-command { 1..10 | foreach { gps | select -last 5 | sort WS }}).TotalMilliseconds

100.4444
    
Result
: Second command is 3.44 times faster.

# this command is the sixth example of sort-object command from the CTP help files. I changed the extension to ps1.

PS > (measure-Command { 1..10 | foreach { dir *.ps1 | sort @{Expression={$_.LastWriteTime-$_.CreationTime}; Ascending=$
false} | select LastWriteTime, CreationTime}}).TotalMilliseconds
640.9769
PS > (measure-Command { 1..10 | foreach { dir *.ps1 | select LastWriteTime, CreationTime | sort @{Expression={$_.LastWr
iteTime-$_.CreationTime}; Ascending=$false}}}).TotalMilliseconds



592.3512

 Result: Second command is 8.2% faster

 

Test #3  

PS > (measure-Command { 1..10 | foreach { dir | sort -unique | select name}}).TotalMilliseconds

6405.653


PS > (measure-Command { 1..10 | foreach { dir | select name | sort -unique}}).TotalMilliseconds

750.8251


Result: Second command is 753% faster!

 

The reason why 'select then sort' is faster to execute is because there are much less properties for sort-object to work on. When you select certain properties from a collection, select-object creates a new object with just the specified properties of the incoming object thus resulting in a smaller object to process.

One thing is for sure: In most cases, select objects before sorting them, and ALWAYS make sure they produce the SAME output!.

Thursday, February 1, 2007

Measure'm all

One of my scripting mottos is to always aspire to script with less steps and at the same time in the fastest way. Basically, you can get from point A to point B in various ways, but in the end, you need to decide which path to choose and how efficient it is.

Back in the VBScript days (seems like a very a long time ago), measuring the time that took your scripts/commands to execute was involved in writing a custom procedure, capturing the date/time before and after the action, and using DATEDIFF function to calculate the difference. Using PS> You can still use the "old" method.

This sample assigns the starting time to $s, executes the main command ($t), and then uses the New-TimeSpan cmdlet to calculate the time difference.

 

$s=(get-date)
$t=Get-ChildItem "C:\Documents and Settings" -filter *.txt -recurse
New-TimeSpan -start $s

Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 453
Ticks : 4531250
TotalDays : 5.24450231481481E-06
TotalHours : 0.000125868055555556
TotalMinutes : 0.00755208333333333
TotalSeconds : 0.453125
TotalMilliseconds : 453.125

 

Now, there's no need to write the whole procedure.
There's a built-in cmdlet called Measure-Command specially created for this kind of task, only it is much simpler and shorter:

Measure-Command {Get-ChildItem "C:\Documents and Settings" -filter *.txt -recurse}

Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 452
Ticks : 4525956
TotalDays : 5.238375E-06
TotalHours : 0.000125721
TotalMinutes : 0.00754326
TotalSeconds : 0.4525956
TotalMilliseconds : 452.5956

 

You can even measure a few lines of code:

Measure-Command {Get-ChildItem "C:\Documents and Settings" -filter *.txt -recurse ;Get-Process; Get-Service }

If you need to test a more complex command structure, consider saving the commands into a .ps1 file and then execute it via Measure-Command:

Measure-Command {& c:\measurec.ps1}

Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 433
Ticks : 4331861
TotalDays : 5.01372800925926E-06
TotalHours : 0.000120329472222222
TotalMinutes : 0.00721976833333333
TotalSeconds : 0.4331861
TotalMilliseconds : 433.1861

That way you can test various scripts/commands that execute procedures using different scripting methods and decide, based on the results, which one to implement. Here is a little teaser. Can you tell which for-loop is faster?

Counting from 1 to 1000?
for($i=0;$i -le 1000;$i++) {$d+=($i*1000)/2}

-or- from 1000 to 1?

for($i=1000;$i -ge 0;$i--) {$d+=($i*1000)/2}

 

Now you can measure it up, for-loops vs. while-loops and so on :-)

 

$hay