project('EMPER', 'c', 'cpp', version: '0.0.1-alpha1-SNAPSHOT', default_options : [ 'warning_level=3', 'c_std=gnu11', 'cpp_std=c++2a', 'b_ndebug=if-release', 'werror=true', ]) thread_dep = dependency('threads') conf_data = configuration_data() use_bundled_deps = get_option('use_bundled_deps') liburing_version = '2.2' uring_dep = dependency('liburing', version: liburing_version, required: use_bundled_deps == 'never') if not uring_dep.found() or use_bundled_deps == 'always' message('liburing ' + liburing_version + ' not found in system, using liburing subproject') liburing_sp = subproject('liburing') uring_dep = liburing_sp.get_variable('uring').as_system() endif numa_dep = dependency('numa') # boost header dependency needed for the circular_buffer used in emper/io/Stats.cpp boost_dep = dependency('boost') emper_dependencies = [thread_dep, uring_dep, numa_dep, boost_dep] boost_thread_dep = dependency('boost', modules : ['thread'], required: false) tools_dir = join_paths(meson.source_root(), 'tools') run_target('iwyu', command: join_paths(tools_dir, 'check-iwyu')) option_urcu = get_option('userspace_rcu') conf_data.set('EMPER_LIBURCU', option_urcu) if option_urcu liburcu_dep = dependency('liburcu') emper_dependencies += [liburcu_dep] endif cpp_compiler = meson.get_compiler('cpp') if cpp_compiler.has_header('compare') conf_data.set('EMPER_HAS_COMPARE_H', true) endif cpp_is_clang = cpp_compiler.get_id() == 'clang' if cpp_is_clang # Clang does not know "__attribute__((optimize(-no-omit-frame-pointer)))". add_project_arguments('-Wno-unknown-attributes', language: 'cpp') endif continuation_stealing_mode = get_option('continuation_stealing_mode') ws_queue_default = get_option('ws_queue_default') ws_queue_scheduler = get_option('ws_queue_scheduler') assume_page_size = get_option('assume_page_size') assume_cache_line_size = get_option('assume_cache_line_size') stats_all = get_option('stats_all') stats_worker_sleep_option = get_option('stats_worker_sleep') if stats_worker_sleep_option == 'true' or (stats_all and stats_worker_sleep_option == 'auto') stats_worker_sleep = 'true' else stats_worker_sleep = 'false' endif stats_stack_usage_option = get_option('stats_stack_usage') if stats_stack_usage_option == 'auto' if stats_all stats_stack_usage = 'efficient' else stats_stack_usage = 'disabled' endif else stats_stack_usage = stats_stack_usage_option endif stats_blocked_context_option = get_option('stats_blocked_context') if stats_blocked_context_option == 'true' or (stats_all and stats_blocked_context_option == 'auto') stats_blocked_context = 'true' else stats_blocked_context = 'false' endif stats_blocked_context_count_option = get_option('stats_blocked_context_count') if stats_blocked_context_count_option == 'true' or (stats_all and stats_blocked_context_count_option == 'auto') stats_blocked_context_count = 'true' else stats_blocked_context_count = 'false' endif conf_data.set('EMPER_WORKER_SLEEP', get_option('worker_sleep')) conf_data.set('EMPER_WORKER_WAKEUP_STRATEGY', get_option('worker_wakeup_strategy')) conf_data.set('EMPER_WORKER_IGNORE_WAKEUP_HINT', get_option('worker_ignore_wakeup_hint')) conf_data.set('EMPER_LOCKED_MPSC_QUEUE', get_option('locked_mpsc_queue')) conf_data.set('EMPER_OVERFLOW_QUEUE', get_option('overflow_queue')) conf_data.set('EMPER_STATS', get_option('stats')) conf_data.set('EMPER_OVERFLOW_QUEUE', get_option('overflow_queue')) conf_data.set('EMPER_BLOCKED_CONTEXT_SET', get_option('blocked_context_set')) conf_data.set('EMPER_SET_AFFINITY_ON_BLOCK', get_option('set_affinity_on_block')) conf_data.set('EMPER_IO_COMPLETER_SCHED_PARAM', get_option('io_completer_sched_param')) conf_data.set('EMPER_CONTINUATION_STEALING_MODE', continuation_stealing_mode) conf_data.set('EMPER_CONTINUATION_STEALING_MADVISE_STACK', get_option('continuation_stealing_madvise_stack')) conf_data.set('EMPER_BUILD_WITH_CLANG', cpp_is_clang) conf_data.set('EMPER_CONTEXT_MANAGER_WITH_MEMORY_MANAGER', get_option('context_manager_with_memory_manager')) conf_data.set('EMPER_MEMORY_MANAGER_VICTIM_PERCENTAGE', get_option('memory_manager_victim_percentage')) conf_data.set('EMPER_ASSUME_PAGE_SIZE', assume_page_size) conf_data.set('EMPER_MIN_CONTEXT_STACK_SIZE', get_option('min_context_stack_size')) conf_data.set('EMPER_ASSUME_CACHE_LINE_SIZE', assume_cache_line_size) conf_data.set('EMPER_STACK_GUARD_PAGE', get_option('stack_guard_page')) conf_data.set('EMPER_STATS_STACK_USAGE', stats_stack_usage) conf_data.set('EMPER_STATS_WORKER_SLEEP', stats_worker_sleep) conf_data.set('EMPER_STATS_BLOCKED_CONTEXT', stats_blocked_context) conf_data.set('EMPER_STATS_BLOCKED_CONTEXT_COUNT', stats_blocked_context_count) context_alignment = get_option('context_alignment') if context_alignment == 'none' context_alignas = '' elif context_alignment == 'cache_line_size' context_alignas = 'alignas(@0@)'.format(assume_cache_line_size) elif context_alignment == 'page_size' context_alignas = 'alignas(@0@)'.format(assume_page_size) else error('Unknown context alignment option: ' + context_alignment) endif conf_data.set('EMPER_CONTEXT_ALIGNAS', context_alignas) if ws_queue_scheduler == 'locked' or (ws_queue_scheduler == 'default' and ws_queue_default == 'locked') ws_queue_scheduler_locked = true else ws_queue_scheduler_locked = false endif if continuation_stealing_mode == 'locked' and not ws_queue_scheduler_locked error('*Locked* continuation stealing only works with locked work-stealing queues (ws_queue_scheduler=locked)') endif if continuation_stealing_mode == 'waitfree' conf_data.set('EMPER_CONTINUATION_STEALING_MODE_WAITFREE', true) endif semaphore_impl = get_option('wakeup_semaphore_implementation') conf_data.set('EMPER_' + semaphore_impl.to_upper() + '_WAKEUP_SEMAPHORE', true) sleep_stratey = get_option('worker_sleep_strategy') if sleep_stratey == 'semaphore' conf_data.set('EMPER_SEMAPHORE_SLEEP_STRATEGY', true) elif sleep_stratey == 'pipe' conf_data.set('EMPER_PIPE_SLEEP_STRATEGY', true) else error('Unsupported sleep strategy') endif locked_unbounded_queue_impl = get_option('locked_unbounded_queue_implementation') if locked_unbounded_queue_impl == 'boost_shared_mutex' if not boost_thread_dep.found() error('Boost thread module not found, but locked_unbounded_queue_implementation set to boost_shared_mutex') endif emper_dependencies += [boost_thread_dep] endif conf_data.set('EMPER_' + locked_unbounded_queue_impl.to_upper() + '_LOCKED_UNBOUNDED_QUEUE', true) default_scheduling_strategy = get_option('default_scheduling_strategy') conf_data.set('EMPER_DEFAULT_SCHEDULING_STRATEGY_' + default_scheduling_strategy.to_upper(), true) ws_victim_count = get_option('work_stealing_victim_count') ws_victim_denominator = get_option('work_stealing_victim_denominator') if ws_victim_count != 0 and ws_victim_denominator !=0 error('work_stealing_victim_count and work_stealing_victim_denominator are mutally exclusive') endif conf_data.set('EMPER_WS_VICTIM_COUNT', ws_victim_count) conf_data.set('EMPER_WS_VICTIM_DENOMINATOR', ws_victim_denominator) conf_data.set('EMPER_WAITFREE_WORK_STEALING', get_option('waitfree_work_stealing')) log_level = get_option('log_level') if log_level == 'automatic' # output only error messages in release builds log_level = get_option('debug') ? 'ALL' : 'Info' endif conf_data.set('EMPER_LOG_LEVEL', log_level) conf_data.set('EMPER_LOG_TIMESTAMP', get_option('log_timestamp')) # IO configuration option_io = get_option('io') if option_io conf_data.set('EMPER_IO', true) endif io_bool_options = [ {'option': 'stealing'}, {'option': 'lockless_cq'}, {'option': 'single_uring', 'dependencies': {'io_completer_behavior': 'schedule'}}, {'option': 'try_syscall'}, {'option': 'waitfree_stealing', 'dependencies': {'io_stealing': true, 'io_lockless_cq': true}}, {'option': 'synchronous'}, ] io_raw_options = [ 'worker_uring_entries', 'unbounded_iow_max', 'lockless_memory_order', ] foreach option_dict : io_bool_options option = option_dict['option'] value = get_option('io_' + option) if not value continue endif if not option_io error('io_' + option + ' defined without io') endif dependencies = option_dict.get('dependencies', {}) foreach dependency, dep_value: dependencies if get_option(dependency) != dep_value error('io_' + option + ' defined but dependency ' + dependency + ':' + dep_value.to_string() + ' not satisfied') endif endforeach conf_data.set('EMPER_IO_' + option.to_upper(), value) endforeach foreach option : io_raw_options conf_data.set('EMPER_IO_' + option.to_upper(), get_option('io_' + option)) endforeach io_sqpoll_option = get_option('io_uring_sq_poller') if io_sqpoll_option != 'off' and not option_io error('io_uring_sq_poller set without io') endif conf_data.set('EMPER_IO_SQ_POLLER', io_sqpoll_option) io_completer_behavior = get_option('io_completer_behavior') if io_completer_behavior == 'maybe_wakeup' if get_option('worker_sleep') io_completer_behavior = 'wakeup' else io_completer_behavior = 'none' endif endif conf_data.set('EMPER_IO_COMPLETER_BEHAVIOR', io_completer_behavior) # Decide on scheduling optimization introduced because of the completer # moving work to the AnywhereQueue. check_anywhere_queue_while_stealing = get_option('check_anywhere_queue_while_stealing') if check_anywhere_queue_while_stealing == 'auto' conf_data.set('EMPER_CHECK_ANYWHERE_QUEUE_WHILE_STEALING', io_completer_behavior == 'schedule') else conf_data.set('EMPER_CHECK_ANYWHERE_QUEUE_WHILE_STEALING', check_anywhere_queue_while_stealing == 'true') endif # check io meson options consistency if get_option('io_single_uring') if io_sqpoll_option == 'each' or io_sqpoll_option == 'numa' warning('sqpoller: ' + io_sqpoll_option + ' is useless when using a single io_uring') endif endif subdir('emper') subdir('doc') if not get_option('build_only_emper_dep') subdir('extra-libs') subdir('tests') subdir('apps') subdir('eval') endif