// Copyright 2014 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package libcontainer import ( "fmt" info "github.com/google/cadvisor/info/v1" "github.com/google/cadvisor/container" "github.com/opencontainers/runc/libcontainer/cgroups" "k8s.io/klog" ) type CgroupSubsystems struct { // Cgroup subsystem mounts. // e.g.: "/sys/fs/cgroup/cpu" -> ["cpu", "cpuacct"] Mounts []cgroups.Mount // Cgroup subsystem to their mount location. // e.g.: "cpu" -> "/sys/fs/cgroup/cpu" MountPoints map[string]string } // Get information about the cgroup subsystems those we want func GetCgroupSubsystems(includedMetrics container.MetricSet) (CgroupSubsystems, error) { // Get all cgroup mounts. allCgroups, err := cgroups.GetCgroupMounts(true) if err != nil { return CgroupSubsystems{}, err } disableCgroups := map[string]struct{}{} //currently we only support disable blkio subsystem if !includedMetrics.Has(container.DiskIOMetrics) { disableCgroups["blkio"] = struct{}{} } return getCgroupSubsystemsHelper(allCgroups, disableCgroups) } // Get information about all the cgroup subsystems. func GetAllCgroupSubsystems() (CgroupSubsystems, error) { // Get all cgroup mounts. allCgroups, err := cgroups.GetCgroupMounts(true) if err != nil { return CgroupSubsystems{}, err } emptyDisableCgroups := map[string]struct{}{} return getCgroupSubsystemsHelper(allCgroups, emptyDisableCgroups) } func getCgroupSubsystemsHelper(allCgroups []cgroups.Mount, disableCgroups map[string]struct{}) (CgroupSubsystems, error) { if len(allCgroups) == 0 { return CgroupSubsystems{}, fmt.Errorf("failed to find cgroup mounts") } // Trim the mounts to only the subsystems we care about. supportedCgroups := make([]cgroups.Mount, 0, len(allCgroups)) recordedMountpoints := make(map[string]struct{}, len(allCgroups)) mountPoints := make(map[string]string, len(allCgroups)) for _, mount := range allCgroups { for _, subsystem := range mount.Subsystems { if _, exists := disableCgroups[subsystem]; exists { continue } if _, ok := supportedSubsystems[subsystem]; !ok { // Unsupported subsystem continue } if _, ok := mountPoints[subsystem]; ok { // duplicate mount for this subsystem; use the first one we saw klog.V(5).Infof("skipping %s, already using mount at %s", mount.Mountpoint, mountPoints[subsystem]) continue } if _, ok := recordedMountpoints[mount.Mountpoint]; !ok { // avoid appending the same mount twice in e.g. `cpu,cpuacct` case supportedCgroups = append(supportedCgroups, mount) recordedMountpoints[mount.Mountpoint] = struct{}{} } mountPoints[subsystem] = mount.Mountpoint } } return CgroupSubsystems{ Mounts: supportedCgroups, MountPoints: mountPoints, }, nil } // Cgroup subsystems we support listing (should be the minimal set we need stats from). var supportedSubsystems map[string]struct{} = map[string]struct{}{ "cpu": {}, "cpuacct": {}, "memory": {}, "cpuset": {}, "blkio": {}, "devices": {}, } func DiskStatsCopy0(major, minor uint64) *info.PerDiskStats { disk := info.PerDiskStats{ Major: major, Minor: minor, } disk.Stats = make(map[string]uint64) return &disk } type DiskKey struct { Major uint64 Minor uint64 } func DiskStatsCopy1(disk_stat map[DiskKey]*info.PerDiskStats) []info.PerDiskStats { i := 0 stat := make([]info.PerDiskStats, len(disk_stat)) for _, disk := range disk_stat { stat[i] = *disk i++ } return stat } func DiskStatsCopy(blkio_stats []cgroups.BlkioStatEntry) (stat []info.PerDiskStats) { if len(blkio_stats) == 0 { return } disk_stat := make(map[DiskKey]*info.PerDiskStats) for i := range blkio_stats { major := blkio_stats[i].Major minor := blkio_stats[i].Minor disk_key := DiskKey{ Major: major, Minor: minor, } diskp, ok := disk_stat[disk_key] if !ok { diskp = DiskStatsCopy0(major, minor) disk_stat[disk_key] = diskp } op := blkio_stats[i].Op if op == "" { op = "Count" } diskp.Stats[op] = blkio_stats[i].Value } return DiskStatsCopy1(disk_stat) }