github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/libcontainer/cgroups/fs/blkio.go (about)

     1  // +build linux
     2  
     3  package fs
     4  
     5  import (
     6  	"bufio"
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/opencontainers/runc/libcontainer/cgroups"
    14  	"github.com/opencontainers/runc/libcontainer/configs"
    15  )
    16  
    17  type BlkioGroup struct {
    18  }
    19  
    20  func (s *BlkioGroup) Name() string {
    21  	return "blkio"
    22  }
    23  
    24  func (s *BlkioGroup) Apply(d *cgroupData) error {
    25  	_, err := d.join("blkio")
    26  	if err != nil && !cgroups.IsNotFound(err) {
    27  		return err
    28  	}
    29  	return nil
    30  }
    31  
    32  func (s *BlkioGroup) Set(path string, cgroup *configs.Cgroup) error {
    33  	if cgroup.Resources.BlkioWeight != 0 {
    34  		if err := writeFile(path, "blkio.weight", strconv.FormatUint(uint64(cgroup.Resources.BlkioWeight), 10)); err != nil {
    35  			return err
    36  		}
    37  	}
    38  
    39  	if cgroup.Resources.BlkioLeafWeight != 0 {
    40  		if err := writeFile(path, "blkio.leaf_weight", strconv.FormatUint(uint64(cgroup.Resources.BlkioLeafWeight), 10)); err != nil {
    41  			return err
    42  		}
    43  	}
    44  	for _, wd := range cgroup.Resources.BlkioWeightDevice {
    45  		if err := writeFile(path, "blkio.weight_device", wd.WeightString()); err != nil {
    46  			return err
    47  		}
    48  		if err := writeFile(path, "blkio.leaf_weight_device", wd.LeafWeightString()); err != nil {
    49  			return err
    50  		}
    51  	}
    52  	for _, td := range cgroup.Resources.BlkioThrottleReadBpsDevice {
    53  		if err := writeFile(path, "blkio.throttle.read_bps_device", td.String()); err != nil {
    54  			return err
    55  		}
    56  	}
    57  	for _, td := range cgroup.Resources.BlkioThrottleWriteBpsDevice {
    58  		if err := writeFile(path, "blkio.throttle.write_bps_device", td.String()); err != nil {
    59  			return err
    60  		}
    61  	}
    62  	for _, td := range cgroup.Resources.BlkioThrottleReadIOPSDevice {
    63  		if err := writeFile(path, "blkio.throttle.read_iops_device", td.String()); err != nil {
    64  			return err
    65  		}
    66  	}
    67  	for _, td := range cgroup.Resources.BlkioThrottleWriteIOPSDevice {
    68  		if err := writeFile(path, "blkio.throttle.write_iops_device", td.String()); err != nil {
    69  			return err
    70  		}
    71  	}
    72  
    73  	return nil
    74  }
    75  
    76  func (s *BlkioGroup) Remove(d *cgroupData) error {
    77  	return removePath(d.path("blkio"))
    78  }
    79  
    80  /*
    81  examples:
    82  
    83      blkio.sectors
    84      8:0 6792
    85  
    86      blkio.io_service_bytes
    87      8:0 Read 1282048
    88      8:0 Write 2195456
    89      8:0 Sync 2195456
    90      8:0 Async 1282048
    91      8:0 Total 3477504
    92      Total 3477504
    93  
    94      blkio.io_serviced
    95      8:0 Read 124
    96      8:0 Write 104
    97      8:0 Sync 104
    98      8:0 Async 124
    99      8:0 Total 228
   100      Total 228
   101  
   102      blkio.io_queued
   103      8:0 Read 0
   104      8:0 Write 0
   105      8:0 Sync 0
   106      8:0 Async 0
   107      8:0 Total 0
   108      Total 0
   109  */
   110  
   111  func splitBlkioStatLine(r rune) bool {
   112  	return r == ' ' || r == ':'
   113  }
   114  
   115  func getBlkioStat(path string) ([]cgroups.BlkioStatEntry, error) {
   116  	var blkioStats []cgroups.BlkioStatEntry
   117  	f, err := os.Open(path)
   118  	if err != nil {
   119  		if os.IsNotExist(err) {
   120  			return blkioStats, nil
   121  		}
   122  		return nil, err
   123  	}
   124  	defer f.Close()
   125  
   126  	sc := bufio.NewScanner(f)
   127  	for sc.Scan() {
   128  		// format: dev type amount
   129  		fields := strings.FieldsFunc(sc.Text(), splitBlkioStatLine)
   130  		if len(fields) < 3 {
   131  			if len(fields) == 2 && fields[0] == "Total" {
   132  				// skip total line
   133  				continue
   134  			} else {
   135  				return nil, fmt.Errorf("Invalid line found while parsing %s: %s", path, sc.Text())
   136  			}
   137  		}
   138  
   139  		v, err := strconv.ParseUint(fields[0], 10, 64)
   140  		if err != nil {
   141  			return nil, err
   142  		}
   143  		major := v
   144  
   145  		v, err = strconv.ParseUint(fields[1], 10, 64)
   146  		if err != nil {
   147  			return nil, err
   148  		}
   149  		minor := v
   150  
   151  		op := ""
   152  		valueField := 2
   153  		if len(fields) == 4 {
   154  			op = fields[2]
   155  			valueField = 3
   156  		}
   157  		v, err = strconv.ParseUint(fields[valueField], 10, 64)
   158  		if err != nil {
   159  			return nil, err
   160  		}
   161  		blkioStats = append(blkioStats, cgroups.BlkioStatEntry{Major: major, Minor: minor, Op: op, Value: v})
   162  	}
   163  
   164  	return blkioStats, nil
   165  }
   166  
   167  func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
   168  	// Try to read CFQ stats available on all CFQ enabled kernels first
   169  	if blkioStats, err := getBlkioStat(filepath.Join(path, "blkio.io_serviced_recursive")); err == nil && blkioStats != nil {
   170  		return getCFQStats(path, stats)
   171  	}
   172  	return getStats(path, stats) // Use generic stats as fallback
   173  }
   174  
   175  func getCFQStats(path string, stats *cgroups.Stats) error {
   176  	var blkioStats []cgroups.BlkioStatEntry
   177  	var err error
   178  
   179  	if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.sectors_recursive")); err != nil {
   180  		return err
   181  	}
   182  	stats.BlkioStats.SectorsRecursive = blkioStats
   183  
   184  	if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_service_bytes_recursive")); err != nil {
   185  		return err
   186  	}
   187  	stats.BlkioStats.IoServiceBytesRecursive = blkioStats
   188  
   189  	if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_serviced_recursive")); err != nil {
   190  		return err
   191  	}
   192  	stats.BlkioStats.IoServicedRecursive = blkioStats
   193  
   194  	if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_queued_recursive")); err != nil {
   195  		return err
   196  	}
   197  	stats.BlkioStats.IoQueuedRecursive = blkioStats
   198  
   199  	if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_service_time_recursive")); err != nil {
   200  		return err
   201  	}
   202  	stats.BlkioStats.IoServiceTimeRecursive = blkioStats
   203  
   204  	if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_wait_time_recursive")); err != nil {
   205  		return err
   206  	}
   207  	stats.BlkioStats.IoWaitTimeRecursive = blkioStats
   208  
   209  	if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_merged_recursive")); err != nil {
   210  		return err
   211  	}
   212  	stats.BlkioStats.IoMergedRecursive = blkioStats
   213  
   214  	if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.time_recursive")); err != nil {
   215  		return err
   216  	}
   217  	stats.BlkioStats.IoTimeRecursive = blkioStats
   218  
   219  	return nil
   220  }
   221  
   222  func getStats(path string, stats *cgroups.Stats) error {
   223  	var blkioStats []cgroups.BlkioStatEntry
   224  	var err error
   225  
   226  	if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.throttle.io_service_bytes")); err != nil {
   227  		return err
   228  	}
   229  	stats.BlkioStats.IoServiceBytesRecursive = blkioStats
   230  
   231  	if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.throttle.io_serviced")); err != nil {
   232  		return err
   233  	}
   234  	stats.BlkioStats.IoServicedRecursive = blkioStats
   235  
   236  	return nil
   237  }