Posts RSS Comments RSS 253 Posts and 411 Comments till now

Phase 3 of S.DS.P “CSV Output” (as much as 21 sec faster!)

In the next phase I wanted to actually get some data back and display it. Because I just wanted to test performance I kept the test as close as possible. ADFind has the built in ability to output a csv file so I mimicked his output. I also added two properties to return name and sAMAccountName. For those interested, my next step will be to output objects instead of text (really the whole point.)

My expectation for this test was that ADFind would pull ahead due to the processing of each record, but I was pleasantly surprised when the script was actually faster in all environments except 700k Environment. I will let joe explain why his is slower.

Testing
– I ran each 10x in a Row (as joe Suggested) in its own environement
– ADFind I tested using CMD.exe and used ptime.exe for time measurements.
– Get-DSPObject I used Measure-Command and outputed only TotalSeconds

UPDATED!: I had several people suggest that I should have a consolidated view of the results. So here it is. I took the Average from each test and put into and Excel spreadsheet and then plotted on a chart.

Here is the screenshot (lower is better)
DSP vs ADFind Chart

400k objects in a Prod Quality VM running Win2008 RTM 64bit (local)
Average: ADFind = 90.45
Average: DSP = 68.79
Winner: DSP 21.66 secs faster

Get-DSPObject -prop “name”,”sAMAccountName” -csv
Execution time: 70.455s
Execution time: 69.551s
Execution time: 68.466s
Execution time: 68.085s
Execution time: 68.611s
Execution time: 68.179s
Execution time: 68.837s
Execution time: 68.670s
Execution time: 69.105s
Execution time: 67.994s
adfind -b “your dn here” -f “(objectclass=user)” name samaccountname -csv
Execution time: 100.538 s
Execution time: 109.511 s
Execution time: 92.499 s
Execution time: 96.063 s
Execution time: 91.601 s
Execution time: 80.693 s
Execution time: 81.551 s
Execution time: 81.044 s
Execution time: 90.945 s
Execution time: 80.143 s

400k objects in a Prod Quality VM running Win2008 RTM 64bit (remote)
Average: ADFind = 77.18
Average: DSP = 64.23
Winner: DSP 13 secs faster

Get-DSPObject -prop “name”,”sAMAccountName” -csv
Execution time: 67.065 s
Execution time: 63.871 s
Execution time: 63.330 s
Execution time: 63.027 s
Execution time: 62.630 s
Execution time: 64.692 s
Execution time: 64.451 s
Execution time: 64.450 s
Execution time: 64.594 s
Execution time: 64.219 s
adfind -b “your dn here” -f “(objectclass=user)” name samaccountname -csv
Execution time: 77.280 s
Execution time: 77.616 s
Execution time: 77.304 s
Execution time: 76.899 s
Execution time: 77.426 s
Execution time: 76.773 s
Execution time: 76.699 s
Execution time: 77.445 s
Execution time: 77.463 s
Execution time: 76.912 s

700k objects on a Physical machine Win2k3 x86
Average: ADFind = 101.383
Average: DSP = 109.600
Winner: ADFind 8.21 secs faster

Get-DSPObject -prop “name”,”sAMAccountName” -csv
Execution time: 111.088s
Execution time: 109.962s
Execution time: 110.112s
Execution time: 110.832s
Execution time: 110.167s
Execution time: 109.853s
Execution time: 109.757s
Execution time: 110.387s
Execution time: 109.070s
Execution time: 109.065s
adfind -b “your dn here” -f “(objectclass=user)” name samaccountname -csv
Execution time: 101.571 s
Execution time: 101.313 s
Execution time: 101.386 s
Execution time: 101.593 s
Execution time: 101.539 s
Execution time: 100.917 s
Execution time: 101.020 s
Execution time: 101.286 s
Execution time: 101.544 s
Execution time: 101.667 s

300k Objects on Physical Win2k3 x86 (Remote)
Average: ADFind = 49.90
Average: DSP = 44.44
Winner: DSP 5 secs Faster

Get-DSPObject -prop “name”,”sAMAccountName” -csv
Execution time: 44.782 s
Execution time: 44.316 s
Execution time: 44.473 s
Execution time: 44.322 s
Execution time: 44.380 s
Execution time: 44.440 s
Execution time: 44.394 s
Execution time: 44.544 s
Execution time: 44.428 s
Execution time: 44.247 s
adfind -b “your dn here” -f “(objectclass=user)” name samaccountname -csv
Execution time: 51.983 s
Execution time: 51.937 s
Execution time: 51.810 s
Execution time: 49.142 s
Execution time: 48.913 s
Execution time: 49.073 s
Execution time: 48.765 s
Execution time: 49.125 s
Execution time: 49.110 s
Execution time: 49.105 s

200k Objects on my Server at Home (Win2k8 x64)
Average: ADFind = 35.50
Average: DSP = 31.74
Winner: DSP 4 secs Faster

Get-DSPObject -prop “name”,”sAMAccountName” -csv
Execution time: 31.887 s
Execution time: 31.888 s
Execution time: 31.044 s
Execution time: 30.746 s
Execution time: 31.549 s
Execution time: 31.601 s
Execution time: 31.168 s
Execution time: 31.528 s
Execution time: 31.481 s
Execution time: 31.269 s
adfind -b “your dn here” -f “(objectclass=user)” name samaccountname -csv
Execution time: 37.305 s
Execution time: 34.815 s
Execution time: 34.275 s
Execution time: 34.193 s
Execution time: 39.116 s
Execution time: 34.634 s
Execution time: 39.265 s
Execution time: 33.686 s
Execution time: 33.793 s
Execution time: 33.917 s

Here is the script I used for the DSP Tests

function Get-DSPObject {
    Param(
            $filter = "(objectclass=user)",
            $base = ([ADSI]"").distinguishedName,
            $Server,
            [int]$pageSize = 1000,
            [string[]]$props = @("1.1"),
            [switch]$noHeader,
            [switch]$csv,
            [switch]$count
        )
       
    [VOID][System.Reflection.Assembly]::LoadWithPartialName("System.DirectoryServices.Protocols")
       
    [int]$pageCount = 0
    [int]$objcount = 0
   
    if(!$server){$server = ([ADSI]"").distinguishedName -replace  ",","." -replace "dc=","" }
   
    $connection = New-Object System.DirectoryServices.Protocols.LdapConnection($Server)  
    $subtree = [System.DirectoryServices.Protocols.SearchScope]"Subtree"
   
    $searchRequest = New-Object System.DirectoryServices.Protocols.SearchRequest($base,$filter,$subtree,$props)  
    $pagedRequest = New-Object System.DirectoryServices.Protocols.PageResultRequestControl($pageSize)
    $searchOptions = New-Object System.DirectoryServices.Protocols.SearchOptionsControl([System.DirectoryServices.Protocols.SearchOption]::DomainScope)
    $searchRequest.Controls.add($pagedRequest) | out-null
    $searchRequest.Controls.Add($searchOptions) | out-null
   
    # Output Prep
    if($props -notcontains "1.1")
    {
        $MyProps = @()
        foreach($prop in $props){$MyProps += $prop.ToLower()}
        if($csv)
        {
            if(!$noHeader)
            {
                $header = "distinguishedName"
                foreach($prop in $props){$header += ",$prop"}
                $header
            }
        }
        else
        {
            $MyUserObj = New-Object System.Object
            $MyUserObj | Add-Member -name distinguishedName -MemberType "NoteProperty" -value $null
            foreach($prop in $props){$MyUserObj | Add-Member -name $prop -MemberType "NoteProperty" -value $null}
        }
    }
   
    # Process Pages
    while ($True)
    {
        # Increment the pageCount by 1
        $pageCount++
   
        # Cast the directory response into a SearchResponse object
        $searchResponse = $connection.SendRequest($searchRequest)
   
        # Display the retrieved page number and the number of directory entries in the retrieved page
        # "Page:{0} Contains {1} response entries" -f $pageCount,$searchResponse.entries.count
        $objcount += ($searchResponse.entries).count
       
        # Display the entries within this page
        if(!$count)
        {
            if($props -notcontains "1.1")
            {
                foreach($entry in $searchResponse.Entries)
                {
                    if($csv)
                    {
                        $results = "`"{0}`"" -f $entry.distinguishedName
                        foreach($prop in $MyProps)
                        {
                            $results += ",`"{0}`"" -f ($entry.Attributes[$prop][0])
                        }
                        $results
                    }
                    else
                    {
                        $MyUserObj.distinguishedName = $entry.distinguishedName
                        foreach($prop in $MyProps)
                        {
                            $MyUserObj."$prop" = $null
                            $MyUserObj."$prop" = $entry.Attributes[$prop][0]
                        }
                        $MyUserObj
                    }
                }
            }
            else{$searchResponse.Entries | select distinguishedName}
        }
       
        # if this is true, there are no more pages to request
        if ($searchResponse.Controls[0].Cookie.Length -eq 0){if($count){$objcount};break}
   
        # Set the cookie of the pageRequest equal to the cookie of the pageResponse to request the next
        # page of data in the send request and cast the directory control into a PageResultResponseControl object
        $pagedRequest.Cookie = $searchResponse.Controls[0].Cookie
    }
}

foreach($i in (1..10))
{
    $time = Measure-Command { Get-DSPObject -prop "name","sAMAccountName" -csv }
    "Execution time: {0:n3} s" -f $time.TotalSeconds
}

Trackback this post | Feed on Comments to this post

Leave a Reply

You must be logged in to post a comment.