Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) #!/usr/bin/env python3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3) # Copyright (C) 2019 Tejun Heo <tj@kernel.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4) # Copyright (C) 2019 Andy Newell <newella@fb.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5) # Copyright (C) 2019 Facebook
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) desc = """
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) Generate linear IO cost model coefficients used by the blk-iocost
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) controller.  If the target raw testdev is specified, destructive tests
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) are performed against the whole device; otherwise, on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) ./iocost-coef-fio.testfile.  The result can be written directly to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) /sys/fs/cgroup/io.cost.model.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) On high performance devices, --numjobs > 1 is needed to achieve
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) saturation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) See Documentation/admin-guide/cgroup-v2.rst and block/blk-iocost.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) """
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) import argparse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) import re
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) import json
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) import glob
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) import os
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) import sys
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) import atexit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) import shutil
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) import tempfile
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) import subprocess
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) parser = argparse.ArgumentParser(description=desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33)                                  formatter_class=argparse.RawTextHelpFormatter)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) parser.add_argument('--testdev', metavar='DEV',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35)                     help='Raw block device to use for testing, ignores --testfile-size')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) parser.add_argument('--testfile-size-gb', type=float, metavar='GIGABYTES', default=16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37)                     help='Testfile size in gigabytes (default: %(default)s)')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) parser.add_argument('--duration', type=int, metavar='SECONDS', default=120,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39)                     help='Individual test run duration in seconds (default: %(default)s)')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) parser.add_argument('--seqio-block-mb', metavar='MEGABYTES', type=int, default=128,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41)                     help='Sequential test block size in megabytes (default: %(default)s)')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) parser.add_argument('--seq-depth', type=int, metavar='DEPTH', default=64,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43)                     help='Sequential test queue depth (default: %(default)s)')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) parser.add_argument('--rand-depth', type=int, metavar='DEPTH', default=64,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45)                     help='Random test queue depth (default: %(default)s)')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) parser.add_argument('--numjobs', type=int, metavar='JOBS', default=1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47)                     help='Number of parallel fio jobs to run (default: %(default)s)')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) parser.add_argument('--quiet', action='store_true')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) parser.add_argument('--verbose', action='store_true')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) def info(msg):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52)     if not args.quiet:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53)         print(msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) def dbg(msg):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56)     if args.verbose and not args.quiet:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57)         print(msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) # determine ('DEVNAME', 'MAJ:MIN') for @path
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) def dir_to_dev(path):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61)     # find the block device the current directory is on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62)     devname = subprocess.run(f'findmnt -nvo SOURCE -T{path}',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63)                              stdout=subprocess.PIPE, shell=True).stdout
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64)     devname = os.path.basename(devname).decode('utf-8').strip()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66)     # partition -> whole device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67)     parents = glob.glob('/sys/block/*/' + devname)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68)     if len(parents):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69)         devname = os.path.basename(os.path.dirname(parents[0]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70)     rdev = os.stat(f'/dev/{devname}').st_rdev
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71)     return (devname, f'{os.major(rdev)}:{os.minor(rdev)}')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) def create_testfile(path, size):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74)     global args
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76)     if os.path.isfile(path) and os.stat(path).st_size == size:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77)         return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79)     info(f'Creating testfile {path}')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80)     subprocess.check_call(f'rm -f {path}', shell=True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81)     subprocess.check_call(f'touch {path}', shell=True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82)     subprocess.call(f'chattr +C {path}', shell=True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83)     subprocess.check_call(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84)         f'pv -s {size} -pr /dev/urandom {"-q" if args.quiet else ""} | '
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85)         f'dd of={path} count={size} '
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86)         f'iflag=count_bytes,fullblock oflag=direct bs=16M status=none',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87)         shell=True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) def run_fio(testfile, duration, iotype, iodepth, blocksize, jobs):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90)     global args
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92)     eta = 'never' if args.quiet else 'always'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93)     outfile = tempfile.NamedTemporaryFile()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94)     cmd = (f'fio --direct=1 --ioengine=libaio --name=coef '
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95)            f'--filename={testfile} --runtime={round(duration)} '
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96)            f'--readwrite={iotype} --iodepth={iodepth} --blocksize={blocksize} '
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97)            f'--eta={eta} --output-format json --output={outfile.name} '
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98)            f'--time_based --numjobs={jobs}')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99)     if args.verbose:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)         dbg(f'Running {cmd}')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)     subprocess.check_call(cmd, shell=True)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)     with open(outfile.name, 'r') as f:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)         d = json.loads(f.read())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)     return sum(j['read']['bw_bytes'] + j['write']['bw_bytes'] for j in d['jobs'])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) def restore_elevator_nomerges():
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)     global elevator_path, nomerges_path, elevator, nomerges
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)     info(f'Restoring elevator to {elevator} and nomerges to {nomerges}')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)     with open(elevator_path, 'w') as f:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)         f.write(elevator)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)     with open(nomerges_path, 'w') as f:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)         f.write(nomerges)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) args = parser.parse_args()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) missing = False
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) for cmd in [ 'findmnt', 'pv', 'dd', 'fio' ]:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)     if not shutil.which(cmd):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)         print(f'Required command "{cmd}" is missing', file=sys.stderr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)         missing = True
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if missing:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)     sys.exit(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if args.testdev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)     devname = os.path.basename(args.testdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)     rdev = os.stat(f'/dev/{devname}').st_rdev
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)     devno = f'{os.major(rdev)}:{os.minor(rdev)}'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)     testfile = f'/dev/{devname}'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)     info(f'Test target: {devname}({devno})')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)     devname, devno = dir_to_dev('.')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)     testfile = 'iocost-coef-fio.testfile'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)     testfile_size = int(args.testfile_size_gb * 2 ** 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)     create_testfile(testfile, testfile_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)     info(f'Test target: {testfile} on {devname}({devno})')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) elevator_path = f'/sys/block/{devname}/queue/scheduler'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) nomerges_path = f'/sys/block/{devname}/queue/nomerges'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) with open(elevator_path, 'r') as f:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)     elevator = re.sub(r'.*\[(.*)\].*', r'\1', f.read().strip())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) with open(nomerges_path, 'r') as f:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)     nomerges = f.read().strip()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) info(f'Temporarily disabling elevator and merges')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) atexit.register(restore_elevator_nomerges)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) with open(elevator_path, 'w') as f:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)     f.write('none')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) with open(nomerges_path, 'w') as f:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)     f.write('1')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) info('Determining rbps...')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) rbps = run_fio(testfile, args.duration, 'read',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)                1, args.seqio_block_mb * (2 ** 20), args.numjobs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) info(f'\nrbps={rbps}, determining rseqiops...')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) rseqiops = round(run_fio(testfile, args.duration, 'read',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)                          args.seq_depth, 4096, args.numjobs) / 4096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) info(f'\nrseqiops={rseqiops}, determining rrandiops...')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) rrandiops = round(run_fio(testfile, args.duration, 'randread',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)                           args.rand_depth, 4096, args.numjobs) / 4096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) info(f'\nrrandiops={rrandiops}, determining wbps...')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) wbps = run_fio(testfile, args.duration, 'write',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)                1, args.seqio_block_mb * (2 ** 20), args.numjobs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) info(f'\nwbps={wbps}, determining wseqiops...')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) wseqiops = round(run_fio(testfile, args.duration, 'write',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)                          args.seq_depth, 4096, args.numjobs) / 4096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) info(f'\nwseqiops={wseqiops}, determining wrandiops...')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) wrandiops = round(run_fio(testfile, args.duration, 'randwrite',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)                           args.rand_depth, 4096, args.numjobs) / 4096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) info(f'\nwrandiops={wrandiops}')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) restore_elevator_nomerges()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) atexit.unregister(restore_elevator_nomerges)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) info('')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) print(f'{devno} rbps={rbps} rseqiops={rseqiops} rrandiops={rrandiops} '
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)       f'wbps={wbps} wseqiops={wseqiops} wrandiops={wrandiops}')