github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/runsc/boot/events.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package boot 16 17 import ( 18 "errors" 19 20 "github.com/MerlinKodo/gvisor/pkg/sentry/control" 21 "github.com/MerlinKodo/gvisor/pkg/sentry/usage" 22 ) 23 24 // EventOut is the return type of the Event command. 25 type EventOut struct { 26 Event Event `json:"event"` 27 28 // ContainerUsage maps each container ID to its total CPU usage. 29 ContainerUsage map[string]uint64 `json:"containerUsage"` 30 } 31 32 // Event struct for encoding the event data to JSON. Corresponds to runc's 33 // main.event struct. 34 type Event struct { 35 Type string `json:"type"` 36 ID string `json:"id"` 37 Data Stats `json:"data"` 38 } 39 40 // Stats is the runc specific stats structure for stability when encoding and 41 // decoding stats. 42 type Stats struct { 43 CPU CPU `json:"cpu"` 44 Memory Memory `json:"memory"` 45 Pids Pids `json:"pids"` 46 } 47 48 // Pids contains stats on processes. 49 type Pids struct { 50 Current uint64 `json:"current,omitempty"` 51 Limit uint64 `json:"limit,omitempty"` 52 } 53 54 // MemoryEntry contains stats on a kind of memory. 55 type MemoryEntry struct { 56 Limit uint64 `json:"limit"` 57 Usage uint64 `json:"usage,omitempty"` 58 Max uint64 `json:"max,omitempty"` 59 Failcnt uint64 `json:"failcnt"` 60 } 61 62 // Memory contains stats on memory. 63 type Memory struct { 64 Cache uint64 `json:"cache,omitempty"` 65 Usage MemoryEntry `json:"usage,omitempty"` 66 Swap MemoryEntry `json:"swap,omitempty"` 67 Kernel MemoryEntry `json:"kernel,omitempty"` 68 KernelTCP MemoryEntry `json:"kernelTCP,omitempty"` 69 Raw map[string]uint64 `json:"raw,omitempty"` 70 } 71 72 // CPU contains stats on the CPU. 73 type CPU struct { 74 Usage CPUUsage `json:"usage"` 75 } 76 77 // CPUUsage contains stats on CPU usage. 78 type CPUUsage struct { 79 Kernel uint64 `json:"kernel,omitempty"` 80 User uint64 `json:"user,omitempty"` 81 Total uint64 `json:"total,omitempty"` 82 PerCPU []uint64 `json:"percpu,omitempty"` 83 } 84 85 // Event gets the events from the container. 86 func (cm *containerManager) Event(cid *string, out *EventOut) error { 87 *out = EventOut{ 88 Event: Event{ 89 ID: *cid, 90 Type: "stats", 91 }, 92 } 93 94 // PIDs and check that container exists before going further. 95 pids, err := cm.l.pidsCount(*cid) 96 if err != nil { 97 return err 98 } 99 out.Event.Data.Pids.Current = uint64(pids) 100 101 // Memory usage. 102 mem := cm.l.k.MemoryFile() 103 _ = mem.UpdateUsage(0) // best effort to update. 104 _, totalUsage := usage.MemoryAccounting.Copy() 105 switch containers := cm.l.containerCount(); containers { 106 case 0: 107 return errors.New("no container was found") 108 109 case 1: 110 // There is a single container, so total usage can only come from it. 111 112 default: 113 // In the multi-container case, reports 0 for the root (pause) container, 114 // since it's small and idle. Then equally split the usage to the other 115 // containers. At least the sum of all containers will correctly account 116 // for the memory used by the sandbox. 117 // 118 // TODO(gvisor.dev/issue/172): Proper per-container accounting. 119 if *cid == cm.l.sandboxID { 120 totalUsage = 0 121 } else { 122 totalUsage /= uint64(containers - 1) 123 } 124 } 125 126 out.Event.Data.Memory.Usage.Usage = totalUsage 127 128 // CPU usage by container. 129 out.ContainerUsage = control.ContainerUsage(cm.l.k) 130 131 return nil 132 }