...

Source file src/github.com/opencontainers/runc/libcontainer/cgroups/fs/blkio.go

Documentation: github.com/opencontainers/runc/libcontainer/cgroups/fs

     1  package fs
     2  
     3  import (
     4  	"bufio"
     5  	"os"
     6  	"path/filepath"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/opencontainers/runc/libcontainer/cgroups"
    11  	"github.com/opencontainers/runc/libcontainer/configs"
    12  )
    13  
    14  type BlkioGroup struct {
    15  	weightFilename       string
    16  	weightDeviceFilename string
    17  }
    18  
    19  func (s *BlkioGroup) Name() string {
    20  	return "blkio"
    21  }
    22  
    23  func (s *BlkioGroup) Apply(path string, _ *configs.Resources, pid int) error {
    24  	return apply(path, pid)
    25  }
    26  
    27  func (s *BlkioGroup) Set(path string, r *configs.Resources) error {
    28  	s.detectWeightFilenames(path)
    29  	if r.BlkioWeight != 0 {
    30  		if err := cgroups.WriteFile(path, s.weightFilename, strconv.FormatUint(uint64(r.BlkioWeight), 10)); err != nil {
    31  			return err
    32  		}
    33  	}
    34  
    35  	if r.BlkioLeafWeight != 0 {
    36  		if err := cgroups.WriteFile(path, "blkio.leaf_weight", strconv.FormatUint(uint64(r.BlkioLeafWeight), 10)); err != nil {
    37  			return err
    38  		}
    39  	}
    40  	for _, wd := range r.BlkioWeightDevice {
    41  		if wd.Weight != 0 {
    42  			if err := cgroups.WriteFile(path, s.weightDeviceFilename, wd.WeightString()); err != nil {
    43  				return err
    44  			}
    45  		}
    46  		if wd.LeafWeight != 0 {
    47  			if err := cgroups.WriteFile(path, "blkio.leaf_weight_device", wd.LeafWeightString()); err != nil {
    48  				return err
    49  			}
    50  		}
    51  	}
    52  	for _, td := range r.BlkioThrottleReadBpsDevice {
    53  		if err := cgroups.WriteFile(path, "blkio.throttle.read_bps_device", td.String()); err != nil {
    54  			return err
    55  		}
    56  	}
    57  	for _, td := range r.BlkioThrottleWriteBpsDevice {
    58  		if err := cgroups.WriteFile(path, "blkio.throttle.write_bps_device", td.String()); err != nil {
    59  			return err
    60  		}
    61  	}
    62  	for _, td := range r.BlkioThrottleReadIOPSDevice {
    63  		if err := cgroups.WriteFile(path, "blkio.throttle.read_iops_device", td.String()); err != nil {
    64  			return err
    65  		}
    66  	}
    67  	for _, td := range r.BlkioThrottleWriteIOPSDevice {
    68  		if err := cgroups.WriteFile(path, "blkio.throttle.write_iops_device", td.String()); err != nil {
    69  			return err
    70  		}
    71  	}
    72  
    73  	return nil
    74  }
    75  
    76  /*
    77  examples:
    78  
    79      blkio.sectors
    80      8:0 6792
    81  
    82      blkio.io_service_bytes
    83      8:0 Read 1282048
    84      8:0 Write 2195456
    85      8:0 Sync 2195456
    86      8:0 Async 1282048
    87      8:0 Total 3477504
    88      Total 3477504
    89  
    90      blkio.io_serviced
    91      8:0 Read 124
    92      8:0 Write 104
    93      8:0 Sync 104
    94      8:0 Async 124
    95      8:0 Total 228
    96      Total 228
    97  
    98      blkio.io_queued
    99      8:0 Read 0
   100      8:0 Write 0
   101      8:0 Sync 0
   102      8:0 Async 0
   103      8:0 Total 0
   104      Total 0
   105  */
   106  
   107  func splitBlkioStatLine(r rune) bool {
   108  	return r == ' ' || r == ':'
   109  }
   110  
   111  func getBlkioStat(dir, file string) ([]cgroups.BlkioStatEntry, error) {
   112  	var blkioStats []cgroups.BlkioStatEntry
   113  	f, err := cgroups.OpenFile(dir, file, os.O_RDONLY)
   114  	if err != nil {
   115  		if os.IsNotExist(err) {
   116  			return blkioStats, nil
   117  		}
   118  		return nil, err
   119  	}
   120  	defer f.Close()
   121  
   122  	sc := bufio.NewScanner(f)
   123  	for sc.Scan() {
   124  		// format: dev type amount
   125  		fields := strings.FieldsFunc(sc.Text(), splitBlkioStatLine)
   126  		if len(fields) < 3 {
   127  			if len(fields) == 2 && fields[0] == "Total" {
   128  				// skip total line
   129  				continue
   130  			} else {
   131  				return nil, malformedLine(dir, file, sc.Text())
   132  			}
   133  		}
   134  
   135  		v, err := strconv.ParseUint(fields[0], 10, 64)
   136  		if err != nil {
   137  			return nil, &parseError{Path: dir, File: file, Err: err}
   138  		}
   139  		major := v
   140  
   141  		v, err = strconv.ParseUint(fields[1], 10, 64)
   142  		if err != nil {
   143  			return nil, &parseError{Path: dir, File: file, Err: err}
   144  		}
   145  		minor := v
   146  
   147  		op := ""
   148  		valueField := 2
   149  		if len(fields) == 4 {
   150  			op = fields[2]
   151  			valueField = 3
   152  		}
   153  		v, err = strconv.ParseUint(fields[valueField], 10, 64)
   154  		if err != nil {
   155  			return nil, &parseError{Path: dir, File: file, Err: err}
   156  		}
   157  		blkioStats = append(blkioStats, cgroups.BlkioStatEntry{Major: major, Minor: minor, Op: op, Value: v})
   158  	}
   159  	if err := sc.Err(); err != nil {
   160  		return nil, &parseError{Path: dir, File: file, Err: err}
   161  	}
   162  
   163  	return blkioStats, nil
   164  }
   165  
   166  func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
   167  	type blkioStatInfo struct {
   168  		filename            string
   169  		blkioStatEntriesPtr *[]cgroups.BlkioStatEntry
   170  	}
   171  	bfqDebugStats := []blkioStatInfo{
   172  		{
   173  			filename:            "blkio.bfq.sectors_recursive",
   174  			blkioStatEntriesPtr: &stats.BlkioStats.SectorsRecursive,
   175  		},
   176  		{
   177  			filename:            "blkio.bfq.io_service_time_recursive",
   178  			blkioStatEntriesPtr: &stats.BlkioStats.IoServiceTimeRecursive,
   179  		},
   180  		{
   181  			filename:            "blkio.bfq.io_wait_time_recursive",
   182  			blkioStatEntriesPtr: &stats.BlkioStats.IoWaitTimeRecursive,
   183  		},
   184  		{
   185  			filename:            "blkio.bfq.io_merged_recursive",
   186  			blkioStatEntriesPtr: &stats.BlkioStats.IoMergedRecursive,
   187  		},
   188  		{
   189  			filename:            "blkio.bfq.io_queued_recursive",
   190  			blkioStatEntriesPtr: &stats.BlkioStats.IoQueuedRecursive,
   191  		},
   192  		{
   193  			filename:            "blkio.bfq.time_recursive",
   194  			blkioStatEntriesPtr: &stats.BlkioStats.IoTimeRecursive,
   195  		},
   196  		{
   197  			filename:            "blkio.bfq.io_serviced_recursive",
   198  			blkioStatEntriesPtr: &stats.BlkioStats.IoServicedRecursive,
   199  		},
   200  		{
   201  			filename:            "blkio.bfq.io_service_bytes_recursive",
   202  			blkioStatEntriesPtr: &stats.BlkioStats.IoServiceBytesRecursive,
   203  		},
   204  	}
   205  	bfqStats := []blkioStatInfo{
   206  		{
   207  			filename:            "blkio.bfq.io_serviced_recursive",
   208  			blkioStatEntriesPtr: &stats.BlkioStats.IoServicedRecursive,
   209  		},
   210  		{
   211  			filename:            "blkio.bfq.io_service_bytes_recursive",
   212  			blkioStatEntriesPtr: &stats.BlkioStats.IoServiceBytesRecursive,
   213  		},
   214  	}
   215  	cfqStats := []blkioStatInfo{
   216  		{
   217  			filename:            "blkio.sectors_recursive",
   218  			blkioStatEntriesPtr: &stats.BlkioStats.SectorsRecursive,
   219  		},
   220  		{
   221  			filename:            "blkio.io_service_time_recursive",
   222  			blkioStatEntriesPtr: &stats.BlkioStats.IoServiceTimeRecursive,
   223  		},
   224  		{
   225  			filename:            "blkio.io_wait_time_recursive",
   226  			blkioStatEntriesPtr: &stats.BlkioStats.IoWaitTimeRecursive,
   227  		},
   228  		{
   229  			filename:            "blkio.io_merged_recursive",
   230  			blkioStatEntriesPtr: &stats.BlkioStats.IoMergedRecursive,
   231  		},
   232  		{
   233  			filename:            "blkio.io_queued_recursive",
   234  			blkioStatEntriesPtr: &stats.BlkioStats.IoQueuedRecursive,
   235  		},
   236  		{
   237  			filename:            "blkio.time_recursive",
   238  			blkioStatEntriesPtr: &stats.BlkioStats.IoTimeRecursive,
   239  		},
   240  		{
   241  			filename:            "blkio.io_serviced_recursive",
   242  			blkioStatEntriesPtr: &stats.BlkioStats.IoServicedRecursive,
   243  		},
   244  		{
   245  			filename:            "blkio.io_service_bytes_recursive",
   246  			blkioStatEntriesPtr: &stats.BlkioStats.IoServiceBytesRecursive,
   247  		},
   248  	}
   249  	throttleRecursiveStats := []blkioStatInfo{
   250  		{
   251  			filename:            "blkio.throttle.io_serviced_recursive",
   252  			blkioStatEntriesPtr: &stats.BlkioStats.IoServicedRecursive,
   253  		},
   254  		{
   255  			filename:            "blkio.throttle.io_service_bytes_recursive",
   256  			blkioStatEntriesPtr: &stats.BlkioStats.IoServiceBytesRecursive,
   257  		},
   258  	}
   259  	baseStats := []blkioStatInfo{
   260  		{
   261  			filename:            "blkio.throttle.io_serviced",
   262  			blkioStatEntriesPtr: &stats.BlkioStats.IoServicedRecursive,
   263  		},
   264  		{
   265  			filename:            "blkio.throttle.io_service_bytes",
   266  			blkioStatEntriesPtr: &stats.BlkioStats.IoServiceBytesRecursive,
   267  		},
   268  	}
   269  	orderedStats := [][]blkioStatInfo{
   270  		bfqDebugStats,
   271  		bfqStats,
   272  		cfqStats,
   273  		throttleRecursiveStats,
   274  		baseStats,
   275  	}
   276  
   277  	var blkioStats []cgroups.BlkioStatEntry
   278  	var err error
   279  
   280  	for _, statGroup := range orderedStats {
   281  		for i, statInfo := range statGroup {
   282  			if blkioStats, err = getBlkioStat(path, statInfo.filename); err != nil || blkioStats == nil {
   283  				// if error occurs on first file, move to next group
   284  				if i == 0 {
   285  					break
   286  				}
   287  				return err
   288  			}
   289  			*statInfo.blkioStatEntriesPtr = blkioStats
   290  			// finish if all stats are gathered
   291  			if i == len(statGroup)-1 {
   292  				return nil
   293  			}
   294  		}
   295  	}
   296  	return nil
   297  }
   298  
   299  func (s *BlkioGroup) detectWeightFilenames(path string) {
   300  	if s.weightFilename != "" {
   301  		// Already detected.
   302  		return
   303  	}
   304  	if cgroups.PathExists(filepath.Join(path, "blkio.weight")) {
   305  		s.weightFilename = "blkio.weight"
   306  		s.weightDeviceFilename = "blkio.weight_device"
   307  	} else {
   308  		s.weightFilename = "blkio.bfq.weight"
   309  		s.weightDeviceFilename = "blkio.bfq.weight_device"
   310  	}
   311  }
   312  

View as plain text