IMJLA / Export-Permission

Create CSV, HTML, and XML reports of permissions
MIT License
5 stars 1 forks source link

Improve Performance When Selecting First of Multiple Identical Objects? #59

Closed IMJLA closed 10 months ago

IMJLA commented 10 months ago
$array1 = @(1,2)
$array2 = 1
$array3 = $null

Expected Behavior

@($array1)[0] # returns 1
@($array2)[0] # returns 1
@($array3)[0] # returns $null

Current Behavior

$array1 | Select-Object -First 1 # returns 1
$array2 | Select-Object -First 1 # returns 1
$array3 | Select-Object -First 1 # returns $null

Possible Solution

Test performance difference of Select-Object -First 1 vs array wrappers and index references Replace usage of Select-Object -First 1 with array wrappers and index references to improve performance?

IMJLA commented 10 months ago
# Here is the prep code.  We're going to prep some fake test data instead down below
$array1 = @(1,2)
$array2 = 1
$array3 = $null
$array4 = @(1..100000)

$n = 100000

# Here we will list the various methods whose performance we want to test:
$Scriptblocks = @(
    { 
        # Here is the prep code we will use to generate fake test data.100k fake servers, and 10k fake serial numbers to lookup.
        Write-Host "Looping $n times..."
        $null = for ($i = 0; $i -lt $n; $i++) {
            @($array1)[0] # returns 1
            @($array2)[0] # returns 1
            @($array3)[0] # returns $null
            @($array4)[0] # returns 1
        }
        Write-Host "Loop complete"
    },

    {
        # Here is the prep code we will use to generate fake test data.100k fake servers, and 10k fake serial numbers to lookup.
        Write-Host "Looping $n times..."
        $null = for ($i = 0; $i -lt $n; $i++) {
            $array1 | Select-Object -First 1 # returns 1
            $array2 | Select-Object -First 1 # returns 1
            $array3 | Select-Object -First 1 # returns $null
            $array4 | Select-Object -First 1 # returns 1
        }
        Write-Host "Loop complete"
    }
)

# Here is our function to test the performance of each method
Function Test-ScriptBlockPerformance {
    param (
        [Parameter(ValueFromPipeline)]
        [scriptblock[]]$ScriptBlock
    )
    process {
        ForEach ($ThisScript in $ScriptBlock) {
            Write-Host "Starting test of expression {$ThisScript}"
            $Result = Measure-Command -Expression $ThisScript
            [pscustomobject]@{
                Expression = "{$ThisScript}"
                Result = $Result
                Ticks = $Result.Ticks
            }
        }
    }
}

# Here is where we invoke our function to run the performance tests, and sort the results to find a winner (the fastest method)
$Leaderboard = $Scriptblocks | Test-ScriptBlockPerformance | Sort-Object -Property Ticks
$Leaderboard | Format-Table Ticks,Expression -AutoSize
IMJLA commented 10 months ago
     Ticks Expression                                                                                                                                                                                                                                                                                          
     ----- ----------                                                                                                                                                                                                                                                                                          
 391086336 {...                                                                                                                                                                                                                                                                                                
4031613336 { ...              
IMJLA commented 10 months ago

test shows 91.3% performance improvement

IMJLA commented 10 months ago

Implemented in 0.0.193

Involved changes to PsRunspace, PsNtfs, Permission, and Adsi modules