ns::stats::Collector method cpuCapacity (public)
<instance of ns::stats::Collector> cpuCapacity
Inspect host logical CPUs, process affinity and visible cgroup v1/v2 CPU quotas, cpusets and throttling counters. effectiveCores is the minimum known ceiling, not reserved or guaranteed CPU capacity. Missing probes remain unknown and are reflected in constraint completeness and reasons. Counters can include other processes or sibling cgroups; do not sum ancestor counters as independent process usage. Does not change limits.
- Returns:
- Dictionary of visible CPU ceilings, effectiveCores, constraint completeness, cumulative cgroup throttling counters and limitations; unavailable values are empty.
- Testcases:
- No testcase defined.
Source code: set result {hostLogicalCpus {} affinityCpus {} cpusetCpus {} quotaCores {} effectiveCores {} quotaStatus unknown constraintsComplete false throttlingAvailable false throttlingScope cgroup-hierarchy throttling {} limitations {Visible CPU ceilings are not reserved capacity. Hidden ancestor limits, host contention and CPU shares can reduce availability. Throttling counters are cumulative for each visible cgroup, including other processes; ancestor counters can include sibling groups.}} set reasons {}; set ceilings {} if {![catch {:cpuListCount [:systemText /sys/devices/system/cpu/online]} count] && $count>0} { dict set result hostLogicalCpus $count; lappend ceilings $count } if {![catch {:systemText /proc/self/status} status] && [regexp -line {^Cpus_allowed_list:\s*([^\n]+)} $status -> list] && ![catch {:cpuListCount [string trim $list]} count] && $count>0} { dict set result affinityCpus $count; lappend ceilings $count } else {lappend reasons affinity-unavailable} set memberships {} if {![catch {:systemText /proc/self/cgroup} text]} { foreach line [split $text \n] { if {![regexp {^[0-9]+:([^:]*):(.*)$} $line -> controllers path]} continue if {$controllers eq ""} {dict set memberships unified $path} foreach controller [split $controllers ,] {dict set memberships $controller $path} } } set quotaSeen false; set quotaMissing false; set hierarchySeen false set groups {}; set visited {} if {![catch {:systemText /proc/self/mountinfo} mounts]} { foreach line [split $mounts \n] { set parts [split $line " "] set separator [lsearch -exact $parts -] if {$separator<6} continue set type [lindex $parts [expr {$separator+1}]] if {$type ni {cgroup cgroup2}} continue set root [:mountPath [lindex $parts 3]] set mount [:mountPath [lindex $parts 4]] set controllers [split [lindex $parts [expr {$separator+3}]] ,] set key {}; set cpu false; set cpuset false if {$type eq "cgroup2" && [dict exists $memberships unified]} { set key unified; set cpu true; set cpuset true } else { foreach controller {cpu cpuset} { if {$controller in $controllers && [dict exists $memberships $controller]} { set key $controller if {$controller eq "cpu"} {set cpu true} else {set cpuset true} } } } if {$key eq ""} continue set member [dict get $memberships $key] # Do not traverse outside a visible mount, including namespace # membership paths containing parent components. if {".." in [file split $member]} {lappend reasons cgroup-path-unresolvable; continue} if {$root eq "/"} {set relative [string trimleft $member /] } elseif {$member eq "/" || $member eq $root} {set relative {} } elseif {[string first "$root/" $member]==0} {set relative [string range $member [expr {[string length $root]+1}] end] } else {continue} set directory [file join $mount $relative] set hierarchySeen true while {1} { if {[lsearch -exact $visited [list $directory $cpu $cpuset]]<0} { lappend visited [list $directory $cpu $cpuset] if {$cpu} { if {$type eq "cgroup2"} { set readable [expr {![catch {:systemText $directory/cpu.max} maximum]}] if {$readable && [regexp {^(max|[0-9]+) ([1-9][0-9]*)$} $maximum -> quota period]} { set quotaSeen true if {$quota ne "max" && $quota>0} {lappend ceilings [expr {double($quota)/$period}]; set q [expr {double($quota)/$period}] if {[dict get $result quotaCores] eq "" || $q<[dict get $result quotaCores]} {dict set result quotaCores $q}} } elseif {$directory ne $mount} {set quotaMissing true} } else { if {![catch {:systemText $directory/cpu.cfs_quota_us} quota] && ![catch {:systemText $directory/cpu.cfs_period_us} period] && [string is entier -strict $quota] && [string is entier -strict $period] && $period>0} { set quotaSeen true if {$quota>0} {set q [expr {double($quota)/$period}]; lappend ceilings $q if {[dict get $result quotaCores] eq "" || $q<[dict get $result quotaCores]} {dict set result quotaCores $q}} } else {set quotaMissing true} } if {![catch {:systemText $directory/cpu.stat} counters]} { set row [dict create path $directory] foreach counter [split $counters \n] { lassign $counter name value if {![string is entier -strict $value] || $value<0} continue switch -- $name { nr_periods {dict set row periods $value} nr_throttled {dict set row throttledPeriods $value} throttled_usec {dict set row throttledSeconds [expr {$value/1000000.0}]} throttled_time {dict set row throttledSeconds [expr {$value/1000000000.0}]} } } if {[dict size $row]>1} {dict set groups $directory $row} } } if {$cpuset} { set file [expr {$type eq "cgroup2" ? "cpuset.cpus.effective" : "cpuset.cpus"}] if {![catch {:systemText $directory/$file} list] && $list ne "" && ![catch {:cpuListCount $list} count] && $count>0} { lappend ceilings $count if {[dict get $result cpusetCpus] eq "" || $count<[dict get $result cpusetCpus]} {dict set result cpusetCpus $count} } } } if {$directory eq $mount} break set directory [file dirname $directory] } } } if {!$hierarchySeen} {lappend reasons cgroup-hierarchy-unavailable} if {!$quotaSeen || $quotaMissing} {lappend reasons quota-unavailable-or-partial} dict set result quotaStatus [expr {[dict get $result quotaCores] ne "" ? "limited" : ($quotaSeen && !$quotaMissing ? "unlimited" : "unknown")}] if {[llength $ceilings]} {dict set result effectiveCores [lindex [lsort -real $ceilings] 0]} dict set result constraintsComplete [expr {$reasons eq ""}] dict set result incompleteReasons [lsort -unique $reasons] dict set result throttling $groups dict set result throttlingAvailable [expr {[dict size $groups]>0}] return $resultXQL Not present: Generic, PostgreSQL, Oracle
![[i]](/resources/acs-subsite/ZoomIn16.gif)