github.com/google/cadvisor@v0.49.1/container/libcontainer/helpers.go (about) 1 // Copyright 2014 Google Inc. All Rights Reserved. 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 libcontainer 16 17 import ( 18 "fmt" 19 20 info "github.com/google/cadvisor/info/v1" 21 22 "github.com/opencontainers/runc/libcontainer/cgroups" 23 24 "github.com/google/cadvisor/container" 25 26 fs "github.com/opencontainers/runc/libcontainer/cgroups/fs" 27 fs2 "github.com/opencontainers/runc/libcontainer/cgroups/fs2" 28 configs "github.com/opencontainers/runc/libcontainer/configs" 29 "k8s.io/klog/v2" 30 ) 31 32 // GetCgroupSubsystems returns information about the cgroup subsystems that are 33 // of interest as a map of cgroup controllers to their mount points. 34 // For example, "cpu" -> "/sys/fs/cgroup/cpu". 35 // 36 // The incudeMetrics arguments specifies which metrics are requested, 37 // and is used to filter out some cgroups and their mounts. If nil, 38 // all supported cgroup subsystems are included. 39 // 40 // For cgroup v2, includedMetrics argument is unused, the only map key is "" 41 // (empty string), and the value is the unified cgroup mount point. 42 func GetCgroupSubsystems(includedMetrics container.MetricSet) (map[string]string, error) { 43 if cgroups.IsCgroup2UnifiedMode() { 44 return map[string]string{"": fs2.UnifiedMountpoint}, nil 45 } 46 // Get all cgroup mounts. 47 allCgroups, err := cgroups.GetCgroupMounts(true) 48 if err != nil { 49 return nil, err 50 } 51 52 return getCgroupSubsystemsHelper(allCgroups, includedMetrics) 53 } 54 55 func getCgroupSubsystemsHelper(allCgroups []cgroups.Mount, includedMetrics container.MetricSet) (map[string]string, error) { 56 if len(allCgroups) == 0 { 57 return nil, fmt.Errorf("failed to find cgroup mounts") 58 } 59 60 // Trim the mounts to only the subsystems we care about. 61 mountPoints := make(map[string]string, len(allCgroups)) 62 for _, mount := range allCgroups { 63 for _, subsystem := range mount.Subsystems { 64 if !needSubsys(subsystem, includedMetrics) { 65 continue 66 } 67 if _, ok := mountPoints[subsystem]; ok { 68 // duplicate mount for this subsystem; use the first one we saw 69 klog.V(5).Infof("skipping %s, already using mount at %s", mount.Mountpoint, mountPoints[subsystem]) 70 continue 71 } 72 mountPoints[subsystem] = mount.Mountpoint 73 } 74 } 75 76 return mountPoints, nil 77 } 78 79 // A map of cgroup subsystems we support listing (should be the minimal set 80 // we need stats from) to a respective MetricKind. 81 var supportedSubsystems = map[string]container.MetricKind{ 82 "cpu": container.CpuUsageMetrics, 83 "cpuacct": container.CpuUsageMetrics, 84 "memory": container.MemoryUsageMetrics, 85 "hugetlb": container.HugetlbUsageMetrics, 86 "pids": container.ProcessMetrics, 87 "cpuset": container.CPUSetMetrics, 88 "blkio": container.DiskIOMetrics, 89 "io": container.DiskIOMetrics, 90 "devices": "", 91 "perf_event": container.PerfMetrics, 92 } 93 94 // Check if this cgroup subsystem/controller is of use. 95 func needSubsys(name string, metrics container.MetricSet) bool { 96 // Check if supported. 97 metric, supported := supportedSubsystems[name] 98 if !supported { 99 return false 100 } 101 // Check if needed. 102 if metrics == nil || metric == "" { 103 return true 104 } 105 106 return metrics.Has(metric) 107 } 108 109 func diskStatsCopy0(major, minor uint64) *info.PerDiskStats { 110 disk := info.PerDiskStats{ 111 Major: major, 112 Minor: minor, 113 } 114 disk.Stats = make(map[string]uint64) 115 return &disk 116 } 117 118 type diskKey struct { 119 Major uint64 120 Minor uint64 121 } 122 123 func diskStatsCopy1(diskStat map[diskKey]*info.PerDiskStats) []info.PerDiskStats { 124 i := 0 125 stat := make([]info.PerDiskStats, len(diskStat)) 126 for _, disk := range diskStat { 127 stat[i] = *disk 128 i++ 129 } 130 return stat 131 } 132 133 func diskStatsCopy(blkioStats []cgroups.BlkioStatEntry) (stat []info.PerDiskStats) { 134 if len(blkioStats) == 0 { 135 return 136 } 137 diskStat := make(map[diskKey]*info.PerDiskStats) 138 for i := range blkioStats { 139 major := blkioStats[i].Major 140 minor := blkioStats[i].Minor 141 key := diskKey{ 142 Major: major, 143 Minor: minor, 144 } 145 diskp, ok := diskStat[key] 146 if !ok { 147 diskp = diskStatsCopy0(major, minor) 148 diskStat[key] = diskp 149 } 150 op := blkioStats[i].Op 151 if op == "" { 152 op = "Count" 153 } 154 diskp.Stats[op] = blkioStats[i].Value 155 } 156 return diskStatsCopy1(diskStat) 157 } 158 159 func NewCgroupManager(name string, paths map[string]string) (cgroups.Manager, error) { 160 config := &configs.Cgroup{ 161 Name: name, 162 Resources: &configs.Resources{}, 163 } 164 if cgroups.IsCgroup2UnifiedMode() { 165 path := paths[""] 166 return fs2.NewManager(config, path) 167 } 168 169 return fs.NewManager(config, paths) 170 }