Skip to content

Commit

Permalink
Merge pull request #534 from michbern-ms/Main
Browse files Browse the repository at this point in the history
Add support to Query-JobLimits.ps1 for querying CPU rate controls
  • Loading branch information
michbern-ms authored Sep 27, 2024
2 parents c521791 + 52cc47d commit cf9f92d
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 6 deletions.
118 changes: 112 additions & 6 deletions helpful_tools/Query-JobLimits/Query-JobLimits.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
############################################################
# Script to query the job limits inside a process-isolated container
############################################################

<#
.NOTES
Copyright (c) Microsoft Corporation. All rights reserved.
Expand All @@ -19,8 +20,11 @@
.DESCRIPTION
Queries the job limits from inside a process-isolated container
.PARAMETER Verbose
If passed, dump verbose output
.PARAMETER LimitType
Determines the type of limit to query. The following values are supported:
- JobMemoryLimit: Returns the job memory limit in bytes
- PeakJobMemoryUsed: Returns the peak job memory used in bytes
- CpuRateControl: Returns the CPU rate control, if enabled, which is generally a cycle count out of a total of 10000
.EXAMPLE
.\Query-JobLimits.ps1
Expand All @@ -30,7 +34,7 @@
[CmdletBinding(DefaultParameterSetName="Standard")]
param(
[Parameter(Mandatory=$True)]
[ValidateSet("JobMemoryLimit", "PeakJobMemoryUsed")]
[ValidateSet("JobMemoryLimit", "PeakJobMemoryUsed", "CpuRateControl")]
[string]$LimitType
)

Expand All @@ -55,6 +59,11 @@ Add-Type @"
JobObjectBasicAndIoAccountingInformation,
JobObjectExtendedLimitInformation,
JobObjectJobSetInformation,
JobObjectGroupInformation,
JobObjectNotificationLimitInformation,
JobObjectLimitViolationInformation,
JobObjectGroupInformationEx,
JobObjectCpuRateControlInformation,
MaxJobObjectInfoClass,
}
Expand All @@ -80,6 +89,14 @@ Add-Type @"
public const UInt32 JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000;
public const UInt32 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000;
//
// CPU Rate Control Flags
//
public const UInt32 JOB_OBJECT_CPU_RATE_CONTROL_ENABLE = 0x00000001;
public const UInt32 JOB_OBJECT_CPU_RATE_CONTROL_WEIGHT_BASED = 0x00000002;
public const UInt32 JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP = 0x00000004;
public const UInt32 JOB_OBJECT_CPU_RATE_CONTROL_NOTIFY = 0x00000008;
[StructLayout(LayoutKind.Sequential)]
public struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
Expand Down Expand Up @@ -116,6 +133,13 @@ Add-Type @"
public UIntPtr PeakJobMemoryUsed;
}
[StructLayout(LayoutKind.Sequential)]
public struct JOBOBJECT_CPU_RATE_CONTROL_INFORMATION
{
public UInt32 ControlFlags;
public UInt32 Data;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, EntryPoint = "QueryInformationJobObject", SetLastError = true)]
public static extern bool QueryInformationJobObject(
IntPtr handleJob,
Expand All @@ -137,7 +161,7 @@ Add-Type @"
{
// Marshal.AllocHGlobal will throw on failure, so we do not need to
// check for allocation failure.
ptrData = Marshal.AllocHGlobal( inSize );
ptrData = Marshal.AllocHGlobal( inSize );
UInt32 outSize = 0;
// Query the job object for its extended limits
Expand Down Expand Up @@ -168,21 +192,103 @@ Add-Type @"
}
}
}
// Query the CPU rate control info for the running job
// If this is run outside of an executing job, or if the CPU rates are not set,
// the script will return zero.
public static JOBOBJECT_CPU_RATE_CONTROL_INFORMATION QueryCPURateControlInformation()
{
// Allocate an JOBOBJECT_CPU_RATE_CONTROL_INFORMATION
int inSize = Marshal.SizeOf(typeof(Api.JOBOBJECT_CPU_RATE_CONTROL_INFORMATION));
IntPtr ptrData = IntPtr.Zero;
try
{
// Marshal.AllocHGlobal will throw on failure, so we do not need to
// check for allocation failure.
ptrData = Marshal.AllocHGlobal( inSize );
UInt32 outSize = 0;
// Query the job object for its extended limits
bool result = Api.QueryInformationJobObject(IntPtr.Zero,
Api.JOBOBJECTINFOCLASS.JobObjectCpuRateControlInformation,
ptrData,
(UInt32)inSize,
ref outSize);
if (result)
{
// Marshal the result data into a .NET structure
Api.JOBOBJECT_CPU_RATE_CONTROL_INFORMATION jobinfo =
(Api.JOBOBJECT_CPU_RATE_CONTROL_INFORMATION)Marshal.PtrToStructure(ptrData, typeof(Api.JOBOBJECT_CPU_RATE_CONTROL_INFORMATION));
// Return the extended limit information to the caller
return jobinfo;
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
if (ptrData != IntPtr.Zero)
{
Marshal.FreeHGlobal( ptrData );
}
}
}
public static UInt32 GetCpuLimit()
{
JOBOBJECT_CPU_RATE_CONTROL_INFORMATION cpuRateControl = QueryCPURateControlInformation();
// Is CPU rate control enabled?
if ((cpuRateControl.ControlFlags & JOB_OBJECT_CPU_RATE_CONTROL_ENABLE) == 0)
{
Console.WriteLine("# CPU rate control is not enabled.");
return 0;
}
// Is CPU rate control weight-based?
if ((cpuRateControl.ControlFlags & JOB_OBJECT_CPU_RATE_CONTROL_WEIGHT_BASED) != 0)
{
Console.WriteLine("# CPU rate control is weight-based.");
return cpuRateControl.Data;
}
// Is CPU rate control hard cap?
if ((cpuRateControl.ControlFlags & JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP) != 0)
{
Console.WriteLine("# CPU rate control is hard cap.");
return cpuRateControl.Data;
}
// Otherwise, default to zero.
return 0;
}
}
"@

$result = [Api]::QueryExtendedLimitInformation()

switch ($LimitType) {
# Returns the job memory limit in bytes
"JobMemoryLimit" {
$result = [Api]::QueryExtendedLimitInformation()
$result.JobMemoryLimit
}

# Returns the peak job memory used in bytes
"PeakJobMemoryUsed" {
$result = [Api]::QueryExtendedLimitInformation()
$result.PeakJobMemoryUsed
}

# Returns the CPU rate control, if enabled,
# which is generally a cycle count out of a total of 10000
"CpuRateControl" {
$result = [Api]::GetCpuLimit()
$result
}

Default {
Write-Error "Limit type unknown: $LimitType"
}
Expand Down
56 changes: 56 additions & 0 deletions helpful_tools/Query-JobLimits/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
## Query-JobLimits.ps1

#### NAME
Query-JobLimits.ps1

#### SYNOPSIS
Queries the job limits from inside a process-isolated container

#### SYNTAX
Query-JobLimits.ps1 [-LimitType <String>] [<CommonParameters>]


#### DESCRIPTION
Queries the job limits from inside a process-isolated container

Once the container platform has set a CPU or Memory limit, this utility
can be used to query those limits and potentially pass them to processes
or workloads inside the container.

#### PARAMETERS
-LimitType [<String>]
The limit type to query from within the container
Required? True
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false

Determines the type of limit to query. The following values are supported:
- JobMemoryLimit: Returns the job memory limit in bytes
- PeakJobMemoryUsed: Returns the peak job memory used in bytes
- CpuRateControl: Returns the CPU rate control, if enabled, which is generally a cycle count out of a total of
10000

#### NOTES
Copyright (c) Microsoft Corporation. All rights reserved.
Use of this sample source code is subject to the terms of the Microsoft
license agreement under which you licensed this sample source code. If
you did not accept the terms of the license agreement, you are not
authorized to use this sample source code. For the terms of the license,
please see the license agreement between you and Microsoft or, if applicable,
see the LICENSE.RTF on your install media or the root of your tools installation.
THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.

#### Examples

PS C:\>.\Query-JobLimits.ps1 -LimitType JobMemoryLimit

PS C:\>.\Query-JobLimits.ps1 -LimitType PeakJobMemoryUsed

PS C:\>.\Query-JobLimits.ps1 -LimitType CpuRateControl

#### Prerequisites
Requires PowerShell version 5.0

0 comments on commit cf9f92d

Please sign in to comment.