mirror of
https://github.com/JakeHillion/scx.git
synced 2024-11-29 20:50:22 +00:00
454 lines
16 KiB
Meson
454 lines
16 KiB
Meson
project('sched_ext schedulers', 'c',
|
|
version: '1.0.5',
|
|
license: 'GPL-2.0',)
|
|
|
|
if meson.version().version_compare('<1.2')
|
|
error('meson >= 1.2 required')
|
|
endif
|
|
|
|
fs = import('fs')
|
|
|
|
cc = meson.get_compiler('c')
|
|
|
|
enable_rust = get_option('enable_rust')
|
|
|
|
bpf_clang = find_program(get_option('bpf_clang'))
|
|
|
|
run_veristat = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/veristat'))
|
|
run_veristat_diff = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/veristat_diff'))
|
|
|
|
enable_stress = get_option('enable_stress')
|
|
|
|
veristat_scheduler = get_option('veristat_scheduler')
|
|
|
|
veristat_diff_dir = get_option('veristat_diff_dir')
|
|
|
|
build_outside_src = get_option('build_outside_src')
|
|
|
|
if enable_stress
|
|
run_stress_tests = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/run_stress_tests'))
|
|
endif
|
|
|
|
get_clang_ver = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/get_clang_ver'))
|
|
get_bpftool_ver = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/get_bpftool_ver'))
|
|
bpftool_build_skel = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/bpftool_build_skel'))
|
|
get_sys_incls = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/get_sys_incls'))
|
|
test_sched = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/test_sched'))
|
|
fetch_libbpf = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/fetch_libbpf'))
|
|
build_libbpf = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/build_libbpf'))
|
|
fetch_bpftool = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/fetch_bpftool'))
|
|
build_bpftool = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/build_bpftool'))
|
|
|
|
bpf_clang_ver = run_command(get_clang_ver, bpf_clang, check: true).stdout().strip()
|
|
if bpf_clang_ver == ''
|
|
error('Unable to find clang version')
|
|
endif
|
|
|
|
bpf_clang_maj = bpf_clang_ver.split('.')[0].to_int()
|
|
|
|
if bpf_clang_maj < 16
|
|
error('clang < 16 loses high 32 bits of 64 bit enums when compiling BPF (@0@ ver=@1@)'
|
|
.format(bpf_clang.full_path(), bpf_clang_ver))
|
|
elif bpf_clang_maj < 17
|
|
warning('clang >= 17 recommended (@0@ ver=@1@)'
|
|
.format(bpf_clang.full_path(), bpf_clang_ver))
|
|
endif
|
|
|
|
# These are for building libbpf and/or bpftool
|
|
|
|
if meson.get_compiler('c').get_id() == 'gcc'
|
|
extra_args = ['-Wno-sign-compare', '-Wno-maybe-uninitialized', '-Wno-calloc-transposed-args']
|
|
else
|
|
extra_args = []
|
|
endif
|
|
|
|
executable('cc_cflags_probe', 'meson-scripts/cc_cflags_probe.c', install: false, pie: true, c_args : extra_args)
|
|
|
|
jq = find_program('jq')
|
|
make = find_program('make')
|
|
nproc = find_program('nproc')
|
|
|
|
make_jobs = 1
|
|
if nproc.found()
|
|
make_jobs = run_command(nproc, check: true).stdout().to_int()
|
|
endif
|
|
|
|
libbpf_path = '@0@/libbpf'.format(meson.current_build_dir())
|
|
libbpf_src_path = '@0@/src'.format(libbpf_path)
|
|
libbpf_a = '@0@/libbpf.a'.format(libbpf_src_path)
|
|
should_build_libbpf = true
|
|
libbpf_h = get_option('libbpf_h')
|
|
libbpf_local_h = get_option('libbpf_h')
|
|
|
|
if get_option('libbpf_a') == 'disabled'
|
|
libbpf_a = ''
|
|
should_build_libbpf = false
|
|
elif get_option('libbpf_a') != ''
|
|
libbpf_a = get_option('libbpf_a')
|
|
if not fs.exists(libbpf_a)
|
|
error('@0@ does not exist.'.format(libbpf_a))
|
|
endif
|
|
should_build_libbpf = false
|
|
endif
|
|
|
|
# WARNING! To build libbpf with the same compiler(CC) and CFLAGS
|
|
# as the schedulers we need to do this hack whereby we create a dummy exe
|
|
# then read the compiler and args from meson's compile_commands.json
|
|
# and re-set them when we build libbpf with make
|
|
if should_build_libbpf
|
|
if not jq.found() or not make.found()
|
|
error('To build the libbpf library "make" and "jq" are required')
|
|
endif
|
|
|
|
libbpf_header_paths = ['/src/usr/include', '/include/uapi']
|
|
|
|
libbpf_h = []
|
|
|
|
# This exists because meson doesn't like absolute paths for include_directories
|
|
# if they are found within the same directory as the source
|
|
libbpf_local_h = []
|
|
local_build_path = meson.current_build_dir().replace(meson.current_source_dir(), '')
|
|
|
|
foreach path : libbpf_header_paths
|
|
libbpf_h += ['@0@'.format(libbpf_path) + path]
|
|
if not build_outside_src
|
|
libbpf_local_h += ['.@0@/libbpf'.format(local_build_path) + path]
|
|
else
|
|
libbpf_local_h += ['@0@/libbpf'.format(local_build_path) + path]
|
|
endif
|
|
endforeach
|
|
|
|
message('Fetching libbpf repo')
|
|
libbpf_commit = '686f600bca59e107af4040d0838ca2b02c14ff50'
|
|
run_command(fetch_libbpf, meson.current_build_dir(), libbpf_commit, check: true)
|
|
|
|
make_jobs = 1
|
|
if nproc.found()
|
|
make_jobs = run_command(nproc, check: true).stdout().to_int()
|
|
endif
|
|
|
|
libbpf = custom_target('libbpf',
|
|
output: '@PLAINNAME@.__PHONY__',
|
|
input: 'meson-scripts/cc_cflags_probe.c',
|
|
command: [build_libbpf, jq, make, libbpf_src_path, '@0@'.format(make_jobs)],
|
|
build_by_default: true)
|
|
else
|
|
# this is a noop when we're not building libbpf ourselves
|
|
libbpf = custom_target('libbpf',
|
|
output: '@PLAINNAME@.__PHONY__',
|
|
input: 'meson-scripts/cc_cflags_probe.c',
|
|
command: ['echo'],
|
|
build_by_default: true)
|
|
endif
|
|
|
|
if libbpf_a != ''
|
|
libbpf_dep = [declare_dependency(
|
|
link_args: libbpf_a,
|
|
include_directories: libbpf_local_h),
|
|
cc.find_library('elf'),
|
|
cc.find_library('z'),
|
|
cc.find_library('zstd')]
|
|
else
|
|
libbpf_dep = dependency('libbpf', version: '>=1.4')
|
|
endif
|
|
|
|
if get_option('kernel_headers') != ''
|
|
kernel_headers = get_option('kernel_headers')
|
|
kernel_dep = [declare_dependency(include_directories: kernel_headers)]
|
|
else
|
|
kernel_dep = []
|
|
endif
|
|
|
|
bpftool_path = '@0@/bpftool/src'.format(meson.current_build_dir())
|
|
should_build_bpftool = true
|
|
bpftool_exe_path = '@0@/bpftool'.format(bpftool_path)
|
|
|
|
if get_option('bpftool') == 'disabled'
|
|
bpftool = find_program('bpftool')
|
|
should_build_bpftool = false
|
|
bpftool_exe_path = bpftool.full_path()
|
|
elif get_option('bpftool') != ''
|
|
bpftool = find_program(get_option('bpftool'))
|
|
should_build_bpftool = false
|
|
bpftool_exe_path = bpftool.full_path()
|
|
endif
|
|
|
|
if should_build_bpftool
|
|
message('Fetching bpftool repo')
|
|
bpftool_commit = '77a72987353fcae8ce330fd87d4c7afb7677a169'
|
|
run_command(fetch_bpftool, meson.current_build_dir(), bpftool_commit, check: true)
|
|
|
|
bpftool_target = custom_target('bpftool_target',
|
|
output: '@PLAINNAME@.__PHONY__',
|
|
input: 'meson-scripts/bpftool_dummy.c',
|
|
command: [build_bpftool, jq, make, bpftool_path, '@0@'.format(make_jobs)],
|
|
build_by_default: true)
|
|
else
|
|
bpftool_ver = run_command(get_bpftool_ver, bpftool_exe_path, check: true).stdout().strip()
|
|
bpftool_maj = bpftool_ver.split('.')[0].to_int()
|
|
bpftool_min = bpftool_ver.split('.')[1].to_int()
|
|
if bpftool_maj < 7 or (bpftool_maj == 7 and bpftool_min < 4)
|
|
error('bpftool >= 7.4 required (@0@ ver=@1@)'.format(bpftool_exe_path, bpftool_ver))
|
|
endif
|
|
# this is a noop when we're not building bpftool ourselves
|
|
bpftool_target = custom_target('bpftool_target',
|
|
output: '@PLAINNAME@.__PHONY__',
|
|
input: 'meson-scripts/bpftool_dummy.c',
|
|
command: ['echo'],
|
|
build_by_default: true)
|
|
endif
|
|
# end libbpf/bpftool stuff
|
|
|
|
#
|
|
# Determine bpf_base_cflags which will be used to compile all .bpf.o files.
|
|
# Note that "-target bpf" is not included to accommodate
|
|
# libbpf_cargo::SkeletonBuilder.
|
|
#
|
|
# Map https://mesonbuild.com/Reference-tables.html#cpu-families to the
|
|
# __TARGET_ARCH list in tools/lib/bpf/bpf_tracing.h in the kernel tree.
|
|
#
|
|
arch_dict = {
|
|
'x86': 'x86',
|
|
'x86_64': 'x86',
|
|
's390x': 's390',
|
|
'arm': 'arm',
|
|
'aarch64': 'arm64',
|
|
'mips': 'mips',
|
|
'mips64': 'mips',
|
|
'ppc': 'powerpc',
|
|
'ppc64': 'powerpc',
|
|
'sparc': 'sparc',
|
|
'sparc64': 'sparc',
|
|
'riscv32': 'riscv',
|
|
'riscv64': 'riscv',
|
|
'arc': 'arc',
|
|
'loongarch64': 'loongarch'
|
|
}
|
|
|
|
cpu = host_machine.cpu_family()
|
|
if cpu not in arch_dict
|
|
error('CPU family "@0@" is not in known arch dict'.format(cpu))
|
|
endif
|
|
|
|
sys_incls = run_command(get_sys_incls, bpf_clang, check: true).stdout().splitlines()
|
|
bpf_base_cflags = ['-g', '-O2', '-Wall', '-Wno-compare-distinct-pointer-types',
|
|
'-D__TARGET_ARCH_' + arch_dict[cpu], '-mcpu=v3',
|
|
'-m@0@-endian'.format(host_machine.endian())] + sys_incls
|
|
|
|
if get_option('werror')
|
|
bpf_base_cflags += '-Werror'
|
|
endif
|
|
|
|
message('cpu=@0@ bpf_base_cflags=@1@'.format(cpu, bpf_base_cflags))
|
|
|
|
libbpf_c_headers = []
|
|
|
|
if libbpf_a != ''
|
|
foreach header: libbpf_h
|
|
libbpf_c_headers += ['-I', header]
|
|
endforeach
|
|
endif
|
|
|
|
#
|
|
# Generators to build BPF skel file for C schedulers.
|
|
#
|
|
gen_bpf_o = generator(bpf_clang,
|
|
output: '@BASENAME@.o',
|
|
depends: [libbpf],
|
|
arguments: [bpf_base_cflags, '-target', 'bpf', libbpf_c_headers, '@EXTRA_ARGS@',
|
|
'-c', '@INPUT@', '-o', '@OUTPUT@'])
|
|
gen_bpf_skel = generator(bpftool_build_skel,
|
|
output: ['@BASENAME@.skel.h','@BASENAME@.subskel.h' ],
|
|
depends: [libbpf, bpftool_target],
|
|
arguments: [bpftool_exe_path, '@INPUT@', '@OUTPUT0@', '@OUTPUT1@'])
|
|
|
|
#
|
|
# For rust sub-projects.
|
|
#
|
|
cargo_build_args = ['--quiet']
|
|
if get_option('buildtype') == 'release' or get_option('buildtype') == 'plain'
|
|
cargo_build_args += '--release'
|
|
endif
|
|
|
|
if get_option('offline')
|
|
cargo_build_args += '--offline'
|
|
endif
|
|
|
|
if get_option('kernel') != ''
|
|
kernel = get_option('kernel')
|
|
endif
|
|
|
|
if enable_rust
|
|
cargo = find_program(get_option('cargo'))
|
|
cargo_fetch = find_program(join_paths(meson.current_source_dir(),
|
|
'meson-scripts/cargo_fetch'))
|
|
cargo_env = environment()
|
|
cargo_env.set('BPF_CLANG', bpf_clang.full_path())
|
|
|
|
meson.add_install_script('meson-scripts/install_rust_user_scheds')
|
|
|
|
foreach flag: bpf_base_cflags
|
|
cargo_env.append('BPF_BASE_CFLAGS', flag, separator: ' ')
|
|
endforeach
|
|
|
|
if libbpf_a != ''
|
|
foreach header: libbpf_h
|
|
cargo_env.append('BPF_EXTRA_CFLAGS_PRE_INCL', '-I' + header, separator: ' ')
|
|
endforeach
|
|
|
|
cargo_env.append('RUSTFLAGS',
|
|
'-C relocation-model=pic -C link-args=-lelf -C link-args=-lz -C link-args=-lzstd -L '
|
|
+ fs.parent(libbpf_a), separator: ' ')
|
|
|
|
#
|
|
# XXX - scx_rusty's original Cargo.toml contained a dependency matching
|
|
# the following. However, it doesn't seem necessary to enable linking to
|
|
# libbpf.a. Ask Dan Schatzberg about the role the dependency line plays.
|
|
#
|
|
#cargo_build_args += ['--config',
|
|
# 'dependencies.libbpf-sys.version="1.2"',
|
|
# '--config',
|
|
# 'dependencies.libbpf-sys.features=["novendor", "static"]']
|
|
endif
|
|
|
|
if get_option('cargo_home') != ''
|
|
cargo_env.set('CARGO_HOME', get_option('cargo_home'))
|
|
endif
|
|
|
|
run_target('fetch', command: [cargo_fetch, cargo], env: cargo_env)
|
|
|
|
rust_scheds = ['scx_lavd', 'scx_bpfland', 'scx_rustland', 'scx_rlfifo',
|
|
'scx_rusty',
|
|
'scx_layered'] # scx_mitosis temporarily excluded
|
|
rust_misc = ['scx_stats', 'scx_stats_derive', 'scx_utils',
|
|
'scx_rustland_core',
|
|
'scx_loader']
|
|
|
|
sched_deps = [libbpf, bpftool_target]
|
|
cargo_cmd = [cargo, 'build', '--manifest-path=@INPUT@', '--target-dir=@OUTDIR@',
|
|
cargo_build_args]
|
|
|
|
# target to compile all rust subprojects
|
|
custom_target('rust_all',
|
|
output: '@PLAINNAME@.__PHONY__',
|
|
input: 'Cargo.toml',
|
|
command: cargo_cmd,
|
|
env: cargo_env,
|
|
depends: sched_deps,
|
|
build_by_default: true,
|
|
build_always_stale: true)
|
|
|
|
# targets to build individual rust subprojects
|
|
foreach p : rust_scheds + rust_misc
|
|
custom_target(p,
|
|
output: p + '@PLAINNAME@.__PHONY__',
|
|
input: 'Cargo.toml',
|
|
command: cargo_cmd + ['-p', p],
|
|
env: cargo_env,
|
|
depends: sched_deps,
|
|
build_by_default: false,
|
|
build_always_stale: true)
|
|
endforeach
|
|
else
|
|
rust_scheds = []
|
|
endif
|
|
|
|
run_target('test_sched', command: [test_sched, kernel])
|
|
run_target('veristat', command: [run_veristat, meson.current_build_dir(),
|
|
get_option('veristat_scheduler'), get_option('kernel')])
|
|
|
|
if get_option('vng_rw_mount') == true
|
|
foreach s : rust_scheds
|
|
run_target('test_sched_'+s, command: [test_sched, kernel, s, 'VNG_RW=true'])
|
|
run_target('veristat_'+s, command: [run_veristat, meson.current_build_dir(),
|
|
get_option('veristat_scheduler'), get_option('kernel'), s, 'VNG_RW=true'])
|
|
endforeach
|
|
else
|
|
foreach s : rust_scheds
|
|
run_target('test_sched_'+s, command: [test_sched, kernel, s])
|
|
run_target('veristat_'+s, command: [run_veristat, meson.current_build_dir(),
|
|
get_option('veristat_scheduler'), get_option('kernel'), s])
|
|
endforeach
|
|
endif
|
|
|
|
run_target('veristat_diff', command: [run_veristat_diff, meson.current_build_dir(),
|
|
get_option('veristat_scheduler'), get_option('kernel'),
|
|
get_option('veristat_diff_dir')])
|
|
|
|
if enable_stress
|
|
# not sure there's a better way
|
|
# only different...
|
|
copys = [
|
|
custom_target('copy stress wrapper',
|
|
input : 'scripts/bpftrace_stress_wrapper.sh',
|
|
output : 'bpftrace_stress_wrapper.sh',
|
|
command : ['cp', '-a', '@INPUT@', '@OUTPUT@'],
|
|
install : false,
|
|
build_by_default : true),
|
|
custom_target('copy dsq_lat',
|
|
input : 'scripts/dsq_lat.bt',
|
|
output : 'dsq_lat.bt',
|
|
command : ['cp', '-a', '@INPUT@', '@OUTPUT@'],
|
|
install : false,
|
|
build_by_default : true),
|
|
custom_target('copy runq_lat',
|
|
input : 'scripts/process_runqlat.bt',
|
|
output : 'process_runqlat.bt',
|
|
command : ['cp', '-a', '@INPUT@', '@OUTPUT@'],
|
|
install : false,
|
|
build_by_default : true)
|
|
]
|
|
run_target('stress_tests', command: [run_stress_tests, '-k', kernel, '-b',
|
|
meson.current_build_dir()], depends: [copys])
|
|
|
|
if get_option('vng_rw_mount') == true
|
|
foreach s : rust_scheds
|
|
run_target('stress_tests_'+s, command: [run_stress_tests, '-k', kernel, '-b',
|
|
meson.current_build_dir(), '--sched', s,
|
|
'--rw', 'true', '--headers', get_option('kernel_headers')],
|
|
depends: [copys])
|
|
endforeach
|
|
else
|
|
foreach s : rust_scheds
|
|
run_target('stress_tests_'+s, command: [run_stress_tests, '-k', kernel, '-b',
|
|
meson.current_build_dir(), '--sched', s], depends: [copys])
|
|
endforeach
|
|
endif
|
|
endif
|
|
|
|
subdir('scheds')
|
|
|
|
systemd = dependency('systemd', required: get_option('systemd'))
|
|
|
|
if systemd.found()
|
|
subdir('services/systemd')
|
|
endif
|
|
|
|
openrc = dependency('openrc', required: get_option('openrc'))
|
|
|
|
if openrc.found()
|
|
subdir('services/openrc')
|
|
endif
|
|
|
|
libalpm = dependency('libalpm', required: get_option('libalpm'))
|
|
|
|
if libalpm.found() and systemd.found()
|
|
subdir('libalpm/systemd')
|
|
endif
|
|
|
|
if libalpm.found() and openrc.found()
|
|
subdir('libalpm/openrc')
|
|
endif
|