Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions pkg/monitor/nvidia/v0/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,49 +81,57 @@ func (s Spec) DeviceNum() int {
return int(s.sr.num)
}

// activeProcs returns the process slots currently in use. procnum is read from
// the shared-memory region and may be corrupt (negative or larger than the
// backing array); clamp it to a valid range so slicing can never panic.
func (s Spec) activeProcs() []shrregProcSlotT {
n := min(max(int(s.sr.procnum), 0), len(s.sr.procs))
return s.sr.procs[:n]
}

func (s Spec) DeviceMemoryContextSize(idx int) uint64 {
v := uint64(0)
for _, p := range s.sr.procs {
for _, p := range s.activeProcs() {
v += p.used[idx].contextSize
}
return v
}

func (s Spec) DeviceMemoryModuleSize(idx int) uint64 {
v := uint64(0)
for _, p := range s.sr.procs {
for _, p := range s.activeProcs() {
v += p.used[idx].moduleSize
}
return v
}

func (s Spec) DeviceMemoryBufferSize(idx int) uint64 {
v := uint64(0)
for _, p := range s.sr.procs {
for _, p := range s.activeProcs() {
v += p.used[idx].bufferSize
}
return v
}

func (s Spec) DeviceMemoryOffset(idx int) uint64 {
v := uint64(0)
for _, p := range s.sr.procs {
for _, p := range s.activeProcs() {
v += p.used[idx].offset
}
return v
}

func (s Spec) DeviceMemoryTotal(idx int) uint64 {
v := uint64(0)
for _, p := range s.sr.procs {
for _, p := range s.activeProcs() {
v += p.used[idx].total
}
return v
}

func (s Spec) DeviceSmUtil(idx int) uint64 {
v := uint64(0)
for _, p := range s.sr.procs {
for _, p := range s.activeProcs() {
v += p.deviceUtil[idx].smUtil
}
return v
Expand Down
144 changes: 132 additions & 12 deletions pkg/monitor/nvidia/v0/spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ func TestSpec_DeviceMemoryContextSize(t *testing.T) {
{
name: "device memory context size for index 1",
spec: &Spec{sr: &sharedRegionT{
num: 2,
num: 2,
procnum: 2,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{contextSize: 100}, {contextSize: 200}}},
{used: [16]deviceMemory{{contextSize: 300}, {contextSize: 400}}},
Expand All @@ -77,7 +78,8 @@ func TestSpec_DeviceMemoryContextSize(t *testing.T) {
{
name: "device memory context size for index 0",
spec: &Spec{sr: &sharedRegionT{
num: 2,
num: 2,
procnum: 2,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{contextSize: 100}, {contextSize: 200}}},
{used: [16]deviceMemory{{contextSize: 300}, {contextSize: 400}}},
Expand All @@ -86,6 +88,19 @@ func TestSpec_DeviceMemoryContextSize(t *testing.T) {
input: 0,
expected: uint64(400),
},
{
name: "stale proc slot beyond procnum is ignored",
spec: &Spec{sr: &sharedRegionT{
num: 2,
procnum: 1,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{contextSize: 100}, {contextSize: 200}}},
{used: [16]deviceMemory{{contextSize: 300}, {contextSize: 400}}},
},
}},
input: 1,
expected: uint64(200),
},
}

for _, tt := range tests {
Expand All @@ -103,7 +118,8 @@ func TestSpec_DeviceMemoryModuleSize(t *testing.T) {
{
name: "device memory module size for index 1",
spec: &Spec{sr: &sharedRegionT{
num: 2,
num: 2,
procnum: 2,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{moduleSize: 100}, {moduleSize: 200}}},
{used: [16]deviceMemory{{moduleSize: 300}, {moduleSize: 400}}},
Expand All @@ -115,7 +131,8 @@ func TestSpec_DeviceMemoryModuleSize(t *testing.T) {
{
name: "device memory module size for index 0",
spec: &Spec{sr: &sharedRegionT{
num: 2,
num: 2,
procnum: 2,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{moduleSize: 100}, {moduleSize: 200}}},
{used: [16]deviceMemory{{moduleSize: 300}, {moduleSize: 400}}},
Expand All @@ -124,6 +141,19 @@ func TestSpec_DeviceMemoryModuleSize(t *testing.T) {
input: 0,
expected: uint64(400),
},
{
name: "stale proc slot beyond procnum is ignored",
spec: &Spec{sr: &sharedRegionT{
num: 2,
procnum: 1,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{moduleSize: 100}, {moduleSize: 200}}},
{used: [16]deviceMemory{{moduleSize: 300}, {moduleSize: 400}}},
},
}},
input: 1,
expected: uint64(200),
},
}

for _, tt := range tests {
Expand All @@ -141,7 +171,8 @@ func TestSpec_DeviceMemoryBufferSize(t *testing.T) {
{
name: "device memory buffer size for index 1",
spec: &Spec{sr: &sharedRegionT{
num: 2,
num: 2,
procnum: 2,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{bufferSize: 100}, {bufferSize: 200}}},
{used: [16]deviceMemory{{bufferSize: 300}, {bufferSize: 400}}},
Expand All @@ -153,7 +184,8 @@ func TestSpec_DeviceMemoryBufferSize(t *testing.T) {
{
name: "device memory buffer size for index 0",
spec: &Spec{sr: &sharedRegionT{
num: 2,
num: 2,
procnum: 2,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{bufferSize: 100}, {bufferSize: 200}}},
{used: [16]deviceMemory{{bufferSize: 300}, {bufferSize: 400}}},
Expand All @@ -162,6 +194,19 @@ func TestSpec_DeviceMemoryBufferSize(t *testing.T) {
input: 0,
expected: uint64(400),
},
{
name: "stale proc slot beyond procnum is ignored",
spec: &Spec{sr: &sharedRegionT{
num: 2,
procnum: 1,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{bufferSize: 100}, {bufferSize: 200}}},
{used: [16]deviceMemory{{bufferSize: 300}, {bufferSize: 400}}},
},
}},
input: 1,
expected: uint64(200),
},
}

for _, tt := range tests {
Expand All @@ -179,7 +224,8 @@ func TestSpec_DeviceMemoryOffset(t *testing.T) {
{
name: "device memory offset for index 1",
spec: &Spec{sr: &sharedRegionT{
num: 2,
num: 2,
procnum: 2,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{offset: 100}, {offset: 200}}},
{used: [16]deviceMemory{{offset: 300}, {offset: 400}}},
Expand All @@ -191,7 +237,8 @@ func TestSpec_DeviceMemoryOffset(t *testing.T) {
{
name: "device memory offset for index 0",
spec: &Spec{sr: &sharedRegionT{
num: 2,
num: 2,
procnum: 2,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{offset: 100}, {offset: 200}}},
{used: [16]deviceMemory{{offset: 300}, {offset: 400}}},
Expand All @@ -200,6 +247,19 @@ func TestSpec_DeviceMemoryOffset(t *testing.T) {
input: 0,
expected: uint64(400),
},
{
name: "stale proc slot beyond procnum is ignored",
spec: &Spec{sr: &sharedRegionT{
num: 2,
procnum: 1,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{offset: 100}, {offset: 200}}},
{used: [16]deviceMemory{{offset: 300}, {offset: 400}}},
},
}},
input: 1,
expected: uint64(200),
},
}

for _, tt := range tests {
Expand All @@ -217,7 +277,8 @@ func TestSpec_DeviceMemoryTotal(t *testing.T) {
{
name: "device memory total for index 1",
spec: &Spec{sr: &sharedRegionT{
num: 2,
num: 2,
procnum: 2,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{total: 100}, {total: 200}}},
{used: [16]deviceMemory{{total: 300}, {total: 400}}},
Expand All @@ -229,7 +290,8 @@ func TestSpec_DeviceMemoryTotal(t *testing.T) {
{
name: "device memory total for index 0",
spec: &Spec{sr: &sharedRegionT{
num: 2,
num: 2,
procnum: 2,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{total: 100}, {total: 200}}},
{used: [16]deviceMemory{{total: 300}, {total: 400}}},
Expand All @@ -238,6 +300,19 @@ func TestSpec_DeviceMemoryTotal(t *testing.T) {
input: 0,
expected: uint64(400),
},
{
name: "stale proc slot beyond procnum is ignored",
spec: &Spec{sr: &sharedRegionT{
num: 2,
procnum: 1,
procs: [1024]shrregProcSlotT{
{used: [16]deviceMemory{{total: 100}, {total: 200}}},
{used: [16]deviceMemory{{total: 300}, {total: 400}}},
},
}},
input: 1,
expected: uint64(200),
},
}

for _, tt := range tests {
Expand All @@ -255,7 +330,8 @@ func TestSpec_DeviceSmUtil(t *testing.T) {
{
name: "device sm util for index 1",
spec: &Spec{sr: &sharedRegionT{
num: 2,
num: 2,
procnum: 2,
procs: [1024]shrregProcSlotT{
{deviceUtil: [16]deviceUtilization{{smUtil: 100}, {smUtil: 200}}},
{deviceUtil: [16]deviceUtilization{{smUtil: 300}, {smUtil: 400}}},
Expand All @@ -267,7 +343,8 @@ func TestSpec_DeviceSmUtil(t *testing.T) {
{
name: "device sm util for index 0",
spec: &Spec{sr: &sharedRegionT{
num: 2,
num: 2,
procnum: 2,
procs: [1024]shrregProcSlotT{
{deviceUtil: [16]deviceUtilization{{smUtil: 100}, {smUtil: 200}}},
{deviceUtil: [16]deviceUtilization{{smUtil: 300}, {smUtil: 400}}},
Expand All @@ -276,6 +353,19 @@ func TestSpec_DeviceSmUtil(t *testing.T) {
input: 0,
expected: uint64(400),
},
{
name: "stale proc slot beyond procnum is ignored",
spec: &Spec{sr: &sharedRegionT{
num: 2,
procnum: 1,
procs: [1024]shrregProcSlotT{
{deviceUtil: [16]deviceUtilization{{smUtil: 100}, {smUtil: 200}}},
{deviceUtil: [16]deviceUtilization{{smUtil: 300}, {smUtil: 400}}},
},
}},
input: 1,
expected: uint64(200),
},
}

for _, tt := range tests {
Expand All @@ -288,6 +378,36 @@ func TestSpec_DeviceSmUtil(t *testing.T) {
}
}

func TestSpec_CorruptProcnumIsClamped(t *testing.T) {
tests := []struct {
name string
procnum int32
expected uint64
}{
// Negative procnum clamps to 0 active slots, so nothing is summed.
{name: "negative procnum", procnum: -5, expected: 0},
// procnum larger than the backing array clamps to its length; only the
// single populated slot contributes.
{name: "procnum over backing array", procnum: 2000, expected: 100},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sr := &sharedRegionT{num: 2, procnum: tt.procnum}
sr.procs[0].used[0].total = 100
sr.procs[0].deviceUtil[0].smUtil = 100
s := Spec{sr: sr}
// A corrupt procnum must never panic the slice bound.
if got := s.DeviceMemoryTotal(0); got != tt.expected {
t.Errorf("DeviceMemoryTotal(0) = %d, want %d", got, tt.expected)
}
if got := s.DeviceSmUtil(0); got != tt.expected {
t.Errorf("DeviceSmUtil(0) = %d, want %d", got, tt.expected)
}
})
}
}

func TestDeviceMemoryLimit(t *testing.T) {
testCases := []struct {
name string
Expand Down
Loading
Loading