Dynamic Memory: Resources from some recent Presentations
Over the last few weeks I’ve been travelling around talking about Dynamic Memory in Windows Server 2008 R2 SP1. The sessions were great and as always I got lots of great questions and feedback. One of the most common ones of course is can you share the scripts and the slides. Well of course! I’ll attached the scripts to this post along with the slides as well. They are at the end of this post if you don’t want to read through the rest. Below is the main part of the demo I did and the code used for it. This is probably the first time I’ve put scripts or code directly into a blog post! But before I do that I have to thank Ben Armstrong for his great work on the scripts. They really illustrate Dynamic Memory very well.
Demo Setup
The whole idea of the demo is show how with Dynamic Memory you can increase density on your Hyper-V hosts but still deliver the performance for your workloads. To set this demo up I had to build 16 virtual machines all running Windows 7 with SP1 applied.
Each of these machines are the exact same image and are running a script called VDIlite which simulates a knowledge worker’s daily tasks of opening documents, websites and waiting a random amount of time between each task. Below is what the code looks like.
VDILite.ps1
# Setup Arrays
$documentSourceArray = @()
$processArray = New-Object System.Collections.ArrayList
# Populate source array. Entries have three values - the document, the program to open it with, and the process name for closing the process
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\05-2008ClabbySixReasonsWhyMSwillovertakeVMW.PDF""","""C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe""", "AcroRd32")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\BTS09HyperV.pdf""","""C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe""", "AcroRd32")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Hyper-V_ProductOverview_v1_2.pdf""","""C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe""", "AcroRd32")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\LefthandHyper-VBrief.pdf""","""C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe""", "AcroRd32")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Top Ten Reasons for Hyper-V.pdf""","""C:\Program Files\Adobe\Reader 9.0\Reader\AcroRd32.exe""", "AcroRd32")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\LiveMigrationWhitepaper_Final.docx""","""C:\Program Files\Microsoft Office\Office14\WINWORD.EXE""", "WINWORD")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Windows Server 2008 R2 Hyper-V RC Public FAQ.docx""","""C:\Program Files\Microsoft Office\Office14\WINWORD.EXE""", "WINWORD")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Windows_Server_2008_R2_Reviewers_Guide_RTM.docx""","""C:\Program Files\Microsoft Office\Office14\WINWORD.EXE""", "WINWORD")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Windows_Server_2008_R2_TDM_Whitepaper_RTM.docx""","""C:\Program Files\Microsoft Office\Office14\WINWORD.EXE""", "WINWORD")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\WS08_R2_VHD_Performance_WhitePaper_Final.docx""","""C:\Program Files\Microsoft Office\Office14\WINWORD.EXE""", "WINWORD")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Storage and Hyper-V - The Choices You Can Make and the Things You Need to Know.pptx""","""C:\Program Files\Microsoft Office\Office14\POWERPNT.EXE""", "POWERPNT")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Windows Server 2008 R2 - Hyper-V Part 1.pptx""","""C:\Program Files\Microsoft Office\Office14\POWERPNT.EXE""", "POWERPNT")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Windows Server 2008 R2 - Hyper-V Part 2.pptx""","""C:\Program Files\Microsoft Office\Office14\POWERPNT.EXE""", "POWERPNT")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\WS08 R2 Hyper-V Overview_R2.pptx""","""C:\Program Files\Microsoft Office\Office14\POWERPNT.EXE""", "POWERPNT")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\WS08 R2 Hyper-V Technical Overview_R2.pptx""","""C:\Program Files\Microsoft Office\Office14\POWERPNT.EXE""", "POWERPNT")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Hyper-V RAM Calculator.xls""","""C:\Program Files\Microsoft Office\Office14\EXCEL.EXE""", "EXCEL")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Appendix_A_-_Test_Results_Spreadsheet.xlsx""","""C:\Program Files\Microsoft Office\Office14\EXCEL.EXE""", "EXCEL")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\DPM 2010 Storage Calculator for Hyper-V DRAFT.xlsx""","""C:\Program Files\Microsoft Office\Office14\EXCEL.EXE""", "EXCEL")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Windows Server 2008 Hyper-V Attack Surface Reference.xlsx""","""C:\Program Files\Microsoft Office\Office14\EXCEL.EXE""", "EXCEL")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\WinHEC08_Agenda.xlsx""","""C:\Program Files\Microsoft Office\Office14\EXCEL.EXE""", "EXCEL")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Microsoft Events TechEd USA.mht""","""C:\Program Files\Internet Explorer\iexplore.exe""", "iexplore")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Virtual PC Guy's WebLog - Site Home - MSDN Blogs.mht""","""C:\Program Files\Internet Explorer\iexplore.exe""", "iexplore")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Windows Server 2008 R2 Virtualization with Hyper-V.mht""","""C:\Program Files\Internet Explorer\iexplore.exe""", "iexplore")
$documentSourceArray += ,("""C:\Users\DM-VDI-Demo\Documents\Windows Virtual PC Home Page.mht""","""C:\Program Files\Internet Explorer\iexplore.exe""", "iexplore")
# Loop for all eternity
while (1 -eq 1)
{
# Generate random sleep time between 10 and 90 seconds
$sleepTime = Get-Random -min 10 -max 90
# Generate random boolean value
$test = [boolean](get-random -input 0,1)
# If the boolean is true - or no processes are running - start a new process
if ($test -or ($processArray.count -eq 0))
{
# Choose a random entry from the source array
$entry = $documentSourceArray[(Get-Random -min 0 -max ($documentSourceArray.length - 1))]
# Start the process
$p = [diagnostics.process]::start($entry[1], $entry[0])
# Add the process name to the process array - if it is not already there
if (!$processArray.contains($entry[2]))
{
[void]$processArray.add($entry[2])
}
# Display debug information
write-host "Opening program" $entry[2]
write-host "Opening file" $entry[0]
Write-host
write-host "Numer of open programs:" $processArray.count
write-host "Open programs:"
write-host $processArray
Write-host
}
# Otherwise close a program
else
{
# Choose a random program, or if there is only one choose it and set the sleep counter to 1 second
if ($processArray.count -gt 1) {$index = Get-Random -min 0 -max ($processArray.count - 1)}
else {$index = 0;$sleepTime = 1}
# Display debug information
write-host "Closing program" $processArray[$index]
Write-host
# Close the process. Key things - CloseMainWindow ensures that the process exists politely.
# All the looping makes sure that all instances are fully closed
$p = @(Get-Process -name $processArray[$index])
while ($p = @(Get-Process -name $processArray[$index] -ea 0)) {foreach ($q in $p) {[void]$q.CloseMainWindow()}; sleep 1}
# Remove the process from the array
$processArray.Remove($processArray[$index])
# Display debug information
write-host "Numer of remaining programs:" $processArray.count
write-host "Remaining programs:"
write-host $processArray
Write-host
}
# wait for a random amount of time
write-host "Waiting for" $sleepTime "seconds"
Write-host
sleep $sleepTime
}
The next step is to make sure each machine has the script running in the startup group so it runs at each logon. I also setup each machine to auto logon so I don’t have to type passwords. I use the command “Control.exe usercontrolpasswords2” Below are some screenshots of how this is configured on each machine.
The next step in this demo setup is to create each of the Snapshots for Dynamic memory disabled and Dynamic Memory Enabled. After this part is done the demo flow is fully automate by using the following script. This script runs on the Hyper-V host where the images are running.
DMDemo.ps1
# Self Elevate
$wid=[System.Security.Principal.WindowsIdentity]::GetCurrent()
$prp=new-object System.Security.Principal.WindowsPrincipal($wid)
$adm=[System.Security.Principal.WindowsBuiltInRole]::Administrator
$IsAdmin=$prp.IsInRole($adm)
if ($IsAdmin -eq $false)
{
$psi = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
$psi.Arguments = $myInvocation.MyCommand.Definition;
$psi.Verb = "runas";
[System.Diagnostics.Process]::Start($psi);
exit
}
else
{
$Host.UI.RawUI.WindowTitle = "DM Demo (Elevated)"
$Host.UI.RawUI.BackgroundColor = "DarkBlue"
clear-host
}
# Function for handling WMI jobs / return values
Function ProcessResult($localResult, $successString, $failureString)
{
#Return success if the return value is "0"
if ($localResult.ReturnValue -eq 0)
{write-host $successString}
#If the return value is not "0" or "4096" then the operation failed
ElseIf ($localResult.ReturnValue -ne 4096)
{write-host $failureString " Error value:" $localResult.ReturnValue}
Else
{#Get the job object
$job=[WMI]$localResult.job
#Provide updates if the jobstate is "3" (starting) or "4" (running)
while ($job.JobState -eq 3 -or $job.JobState -eq 4)
{#write-host $job.PercentComplete "% complete"
sleep 1
#Refresh the job object
$job=[WMI]$localResult.job}
#A jobstate of "7" means success
if ($job.JobState -eq 7)
{write-host $successString}
Else
{write-host $failureString
write-host "ErrorCode:" $job.ErrorCode
write-host "ErrorDescription" $job.ErrorDescription}
}
}
# Do a natural bubble sort on a collection of virtual machines
function NaturalBubbleSortVMs ($VMsToSort)
{
$length = $VMsToSort.Length
$hasChanged = $true
while ($hasChanged)
{
$hasChanged = $false
$length--
for ($i = 0; $i -lt $length; $i++)
{
# Regex used to tell numbers apart from characters
$regex = "([0-9]+)"
# Split the VM Element name by numbers (the above regex)
$SplitArray1 = [regex]::split($VMsToSort[$i].ElementName, $regex)
$SplitArray2 = [regex]::split($VMsToSort[$i+1].ElementName, $regex)
# Use compare-object to find the first chunk of the VM name that does not match
$CompareObject1 = compare-object $SplitArray1 $SplitArray2 | ?{$_.SideIndicator -eq "=>"} | select -first 1
$CompareObject2 = compare-object $SplitArray1 $SplitArray2 | ?{$_.SideIndicator -eq "<="} | select -first 1
# $CompareObject1 will be null if both VM names are identical
if ($CompareObject1)
{
# Get the actual split chunk
$CompareItem1 = $CompareObject1.InputObject
$CompareItem2 = $CompareObject2.InputObject
# Check to see if the chunk is a number - if it is, cast it into an integer
if ($CompareItem1 -match $regex) {$CompareItem1 = [int]$CompareItem1}
if ($CompareItem2 -match $regex) {$CompareItem2 = [int]$CompareItem2}
# Now strings will be compared as strings, numbers as numbers
if ($CompareItem2 -gt $CompareItem1)
{
$VMsToSort[$i], $VMsToSort[$i+1] = $VMsToSort[$i+1], $VMsToSort[$i]
$hasChanged = $true
}
}
}
}
}
# Setup parameters for main menu prompt
$message = "What do you want to do?"
$DMDisabled = New-Object System.Management.Automation.Host.ChoiceDescription "Setup DM &Disabled", "Set the system up for the DM disabled demonstration."
$DMEnabled = New-Object System.Management.Automation.Host.ChoiceDescription "Setup DM &Enabled", "Set the system up for the DM enabled demonstration."
$Base = New-Object System.Management.Automation.Host.ChoiceDescription "Return to &Base configuration", "Revert the system to the base configuration."
$quit = New-Object System.Management.Automation.Host.ChoiceDescription "&Quit", "Exit the DM demo script."
$options = [System.Management.Automation.Host.ChoiceDescription[]]($DMDisabled, $DMEnabled, $Base, $quit)
do
{
# Ask the user what they want to do
$promptResult = $host.ui.PromptForChoice($null, $message, $options, 0)
write-host
switch ($promptResult)
{
0
{
$snapshotName = "DM Disabled"
$NoVMsToStart = 7
if ((Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization").memoryreserve -eq $null)
{
New-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization" -name memoryreserve -propertytype DWORD -value 500
restart-service vmms
sleep -s 5
}
elseif ((Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization").memoryreserve -ne 500)
{
Set-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization" -name memoryreserve -value 500
restart-service vmms
sleep -s 5
}
}
1
{
$snapshotName = "DM Enabled"
$NoVMsToStart = 12
if ((Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization").memoryreserve -ne $null)
{
Remove-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization" -name memoryreserve
restart-service vmms
sleep -s 5
}
}
2
{
$snapshotName = "Base"
$NoVMsToStart = 0
if ((Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization").memoryreserve -ne $null)
{
Remove-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization" -name memoryreserve
restart-service vmms
sleep -s 5
}
}
3
{
Exit
}
}
# Get the management service
$VMMS = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService
# Get the virtual machine objects
$VMs = @(gwmi MSVM_ComputerSystem -namespace "root\virtualization" | where {$_.ElementName -match "Windows 7"})
NaturalBubbleSortVMs $VMs
# Stop any virtual machines that are currently running
if ($VMs.length -ne 0)
{
# results will be stored in an array
$resultArray1 = @()
# go through all of the virtual machines
foreach ($VM in $VMs)
{
# enabledstate will be "3" if the VM is already off
if ($VM.EnabledState -ne 3)
{
$resultArray1 += $VM.RequestStateChange(3)
}
}
# go through the result array and process each of the results
if ($resultArray1.length -ne 0)
{
foreach ($result1 in $resultArray1)
{ProcessResult $result1 "Stopped Virtual Machine" "Failed to stop virtual machine"}
}
}
# Apply the desired snapshot on each virtual machine
if ($VMs.length -ne 0)
{
# results will be stored in an array
$resultArray2 = @()
# go through all of the virtual machines
foreach ($VM in $VMs)
{
# Can't use "getrelated" as a snapshot may have multiple associations back to the virtual machine
# e.g. "LastAppliedSnapshot". In this case "getrelated" will return an array. By using a query
# where the association class is specified we are guaranteed to get a single result
$query = "Associators of {$VM} Where AssocClass=Msvm_ElementSettingData"
$VMSnapshot = gwmi -namespace "root\virtualization" -Query $query | where {$_.ElementName -eq $snapshotName}
# Apply the snapshot and store the result in the result array
$resultArray2 += $vmms.ApplyVirtualSystemSnapShotEx($VM,$VMSnapshot)
}
# go through the result array and process each of the results
if ($resultArray2.length -ne 0)
{
foreach ($result2 in $resultArray2)
{ProcessResult $result2 "Applied snapshot" "Failed to apply snapshot"}
}
}
# Start the desired number of virtual machines
if ($VMs.length -gt ($NoVMsToStart-1))
{
# results will be stored in an array
$resultArray3 = @()
# Start the first "i" virtual machines
for ([int]$i=0; $i -le ($NoVMsToStart-1); $i++)
{
$resultArray3 += $VMs.Get($i).RequestStateChange(2)
}
# go through the result array and process each of the results
if ($resultArray3.length -ne 0)
{
foreach ($result3 in $resultArray3)
{ProcessResult $result3 "Started Virtual Machine" "Failed to start virtual machine"}
}
}
}
until ($promptResult -eq 3)
So that’s about it. The way the demo is setup it’s very easy to repeat the whole process and takes a couple of minutes to setup before I have to present so it’s a great re-usable demo. So hopefully this is helpful to you out there. The slides and scripts are below for you to download as needed.
Demo Scripts Scripts
PowerPoint Deck Slides
Jeffa
Technorati Tags: Dynamic Memory,Hyper-V R2
Comments
- Anonymous
May 11, 2011
Thanks. I was present at your demo and it demonstrated the value of dynamic memory to increase the value for money on the comapnay's investment.