On Wed, Oct 21, 2020 at 03:13:19PM +0100, Bruce Richardson wrote: > On Wed, Oct 21, 2020 at 01:01:41PM +0000, Juraj Linkeš wrote: > > > > > > > -----Original Message----- > > > From: Bruce Richardson <bruce.richard...@intel.com> > > > Sent: Wednesday, October 21, 2020 2:02 PM > > > To: Juraj Linkeš <juraj.lin...@pantheon.tech> > > > Cc: ruifeng.w...@arm.com; honnappa.nagaraha...@arm.com; > > > phil.y...@arm.com; vcchu...@amazon.com; dharmik.thak...@arm.com; > > > jerinjac...@gmail.com; hemant.agra...@nxp.com; dev@dpdk.org > > > Subject: Re: [RFC PATCH v3 3/6] build: automatic NUMA and cpu counts > > > detection > > > > > > On Wed, Oct 21, 2020 at 01:37:38PM +0200, Juraj Linkeš wrote: > > > > The build machine's number of cpus and numa nodes vary, resulting in > > > > mismatched counts of RTE_MAX_LCORE and RTE_MAX_NUMA_NODES for > > > many > > > > builds. Automatically discover the host's numa and cpu counts to > > > > remove this mismatch for native builds. Use current defaults for > > > > default builds. > > > > Force the users to specify the counts for cross build in cross files > > > > or on the command line. > > > > Give users the option to override the discovery or values from cross > > > > files by specifying them on the command line with -Dmax_lcores and > > > > -Dmax_numa_nodes. > > > > > > > > Signed-off-by: Juraj Linkeš <juraj.lin...@pantheon.tech> > > > > --- > > > > buildtools/get_cpu_count.py | 7 ++++++ > > > > buildtools/get_numa_count.py | 22 +++++++++++++++++++ > > > > buildtools/meson.build | 2 ++ > > > > config/meson.build | 42 ++++++++++++++++++++++++++++++++++-- > > > > meson_options.txt | 8 +++---- > > > > 5 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 > > > > buildtools/get_cpu_count.py create mode 100644 > > > > buildtools/get_numa_count.py > > > > > > > > diff --git a/buildtools/get_cpu_count.py b/buildtools/get_cpu_count.py > > > > new file mode 100644 index 000000000..386f85f8b > > > > --- /dev/null > > > > +++ b/buildtools/get_cpu_count.py > > > > @@ -0,0 +1,7 @@ > > > > +#!/usr/bin/python3 > > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2020 > > > > +PANTHEON.tech s.r.o. > > > > + > > > > +import os > > > > + > > > > +print(os.cpu_count()) > > > > diff --git a/buildtools/get_numa_count.py > > > > b/buildtools/get_numa_count.py new file mode 100644 index > > > > 000000000..f0c49973a > > > > --- /dev/null > > > > +++ b/buildtools/get_numa_count.py > > > > @@ -0,0 +1,22 @@ > > > > +#!/usr/bin/python3 > > > > +# SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2020 > > > > +PANTHEON.tech s.r.o. > > > > + > > > > +import ctypes > > > > +import glob > > > > +import os > > > > +import subprocess > > > > + > > > > +if os.name == 'posix': > > > > + if os.path.isdir('/sys/devices/system/node'): > > > > + print(len(glob.glob('/sys/devices/system/node/node*'))) > > > > + else: > > > > + print(subprocess.run(['sysctl', 'vm.ndomains'], > > > > +capture_output=True).stdout) > > > > + > > > > +elif os.name == 'nt': > > > > + libkernel32 = ctypes.windll.kernel32 > > > > + > > > > + count = ctypes.c_ulong() > > > > + > > > > + libkernel32.GetNumaHighestNodeNumber(ctypes.pointer(count)) > > > > + print(count.value + 1) > > > > diff --git a/buildtools/meson.build b/buildtools/meson.build index > > > > 04808dabc..925e733b1 100644 > > > > --- a/buildtools/meson.build > > > > +++ b/buildtools/meson.build > > > > @@ -17,3 +17,5 @@ else > > > > endif > > > > map_to_win_cmd = py3 + files('map_to_win.py') sphinx_wrapper = py3 + > > > > files('call-sphinx-build.py') > > > > +get_cpu_count_cmd = py3 + files('get_cpu_count.py') > > > > +get_numa_count_cmd = py3 + files('get_numa_count.py') > > > > diff --git a/config/meson.build b/config/meson.build index > > > > a57c8ae9e..c4477f977 100644 > > > > --- a/config/meson.build > > > > +++ b/config/meson.build > > > > @@ -74,7 +74,11 @@ endif > > > > # still being able to support the CPU features required for DPDK. > > > > # This can be bumped up by the DPDK project, but it can never be an > > > > # invariant like 'native' > > > > +max_lcores = get_option('max_lcores') max_numa_nodes = > > > > +get_option('max_numa_nodes') > > > > if machine == 'default' > > > > + max_numa_nodes = 4 > > > > + max_lcores = 128 > > > > > > This doesn't seem right, since you are overriding the user-specified > > > values with > > > hard-coded ones. > > > > > > > I understand we're using the default build/generic to build portalbe dpdk > > distro packages, meaning the settings for those packages should always be > > the same, no? If not, what should the default/generic build be? And when > > would someone do a default/generic build with their values? It wouldn't be > > a default/generic anymore, right? > > > > > > if host_machine.cpu_family().startswith('x86') > > > > # matches the old pre-meson build systems default > > > > machine = 'corei7' > > > > @@ -83,6 +87,22 @@ if machine == 'default' > > > > elif host_machine.cpu_family().startswith('ppc') > > > > machine = 'power8' > > > > endif > > > > +elif not meson.is_cross_build() > > > > + # find host core count and numa node count for native builds > > > > + if max_lcores == 0 > > > > + max_lcores = > > > run_command(get_cpu_count_cmd).stdout().to_int() > > > > + min_lcores = 2 > > > > + if max_lcores < min_lcores > > > > + message('Found less than @0@ cores, building for > > > @0@ cores'.format(min_lcores)) > > > > + max_lcores = min_lcores > > > > + else > > > > + message('Found @0@ cores'.format(max_lcores)) > > > > + endif > > > > + endif > > > > + if max_numa_nodes == 0 > > > > + max_numa_nodes = > > > run_command(get_numa_count_cmd).stdout().to_int() > > > > + message('Found @0@ numa nodes'.format(max_numa_nodes)) > > > > + endif > > > > endif > > > > > > > > dpdk_conf.set('RTE_MACHINE', machine) @@ -227,8 +247,10 @@ foreach > > > > arg: warning_flags endforeach > > > > > > > > # set other values pulled from the build options > > > > -dpdk_conf.set('RTE_MAX_LCORE', get_option('max_lcores')) > > > > -dpdk_conf.set('RTE_MAX_NUMA_NODES', get_option('max_numa_nodes')) > > > > +if not meson.is_cross_build() > > > > + dpdk_conf.set('RTE_MAX_LCORE', max_lcores) > > > > + dpdk_conf.set('RTE_MAX_NUMA_NODES', max_numa_nodes) endif > > > > > > Rather than conditionally setting the value here, you should move the > > > checks > > > below up above this to simplify things. > > > > > > > Do you mean the cross build checks? Those have to be after > > subdir(arch_subdir) so that we can override the values from cross files (as > > the commit message says). > > > > > > dpdk_conf.set('RTE_MAX_ETHPORTS', get_option('max_ethports')) > > > > dpdk_conf.set('RTE_LIBEAL_USE_HPET', get_option('use_hpet')) > > > > dpdk_conf.set('RTE_ENABLE_TRACE_FP', get_option('enable_trace_fp')) @@ > > > > -247,6 +269,22 @@ compile_time_cpuflags = [] > > > > subdir(arch_subdir) > > > > dpdk_conf.set('RTE_COMPILE_TIME_CPUFLAGS', > > > > ','.join(compile_time_cpuflags)) > > > > > > > > +# check that cpu and numa count is set in cross builds if > > > > +meson.is_cross_build() > > > > + if max_lcores > 0 > > > > + # specified on the cmdline > > > > + dpdk_conf.set('RTE_MAX_LCORE', max_lcores) > > > > + elif not dpdk_conf.has('RTE_MAX_LCORE') > > > > + error('Number of cores for cross build not specified in > > > > @0@ > > > subdir (e.g. in a cross-file) nor on the cmdline'.format(arch_subdir)) > > > > + endif > > > > + if max_numa_nodes > 0 > > > > + # specified on the cmdline > > > > + dpdk_conf.set('RTE_MAX_NUMA_NODES', max_numa_nodes) > > > > + elif not dpdk_conf.has('RTE_MAX_NUMA_NODES') > > > > + error('Number of numa nodes for cross build not > > > > specified in > > > @0@ subdir (e.g. in a cross-file) nor on the cmdline'.format(arch_subdir)) > > > > + endif > > > > +endif > > > > + > > > > # set the install path for the drivers > > > > dpdk_conf.set_quoted('RTE_EAL_PMD_PATH', eal_pmd_path) > > > > > > > > diff --git a/meson_options.txt b/meson_options.txt index > > > > 9bf18ab6b..01b0c45c3 100644 > > > > --- a/meson_options.txt > > > > +++ b/meson_options.txt > > > > @@ -26,10 +26,10 @@ option('machine', type: 'string', value: 'native', > > > > description: 'set the target machine type') > > > > option('max_ethports', > > > > type: 'integer', value: 32, > > > > description: 'maximum number of Ethernet devices') > > > > -option('max_lcores', type: 'integer', value: 128, > > > > - description: 'maximum number of cores/threads supported by EAL') > > > > -option('max_numa_nodes', type: 'integer', value: 4, > > > > - description: 'maximum number of NUMA nodes supported by EAL') > > > > +option('max_lcores', type: 'integer', value: 0, > > > > + description: 'maximum number of cores/threads supported by EAL. > > > > +Value 0 means the number of cpus on the host will be used. For cross > > > > build, > > > set to non-zero to overwrite the cross-file value.') > > > option('max_numa_nodes', > > > type: 'integer', value: 0, > > > > + description: 'maximum number of NUMA nodes supported by EAL. > > > > Value > > > 0 > > > > +means the number of numa nodes on the host will be used. For cross > > > > +build, set to non-zero to overwrite the cross-file value.') > > > > > > I don't like this change, because it very much assumes for > > > non-cross-compiles > > > that people will be running DPDK on the system they build it on. That's a > > > very, > > > very big assumption! > > > > I'll be using definitions from > > https://mesonbuild.com/Cross-compilation.html. > > I understand cross compilation to be building for a diffent host machine > > than the build machine (which is aligned with pretty much every definition > > I found). I understand this to be true not only for builds between > > architectures, but also within an architecture (e.g. x86_64 build machine > > building for x86_64 host machine). > > So yes, when someone does a native build, it stands to reason they want to > > use it on the build machine. If they wanted to use it elsewhere, they would > > cross compile. > > Another thing is the current build philosophy is to detect as much as > > possible (not having statically defined configuration, as you mentioned in > > the past). Detecting the number of cores and numa nodes fits this perfectly. > > And yet another thing is that the assumption seems to be already present in > > the build system - it already detects a lot things, some of which may not > > be satisfied on machines other than the build machine. I may be wrong about > > this. > > > > > I'm ok with having zero as a "detect" option, and having > > > the values overridden from cross-files, but not with detection as the > > > default out- > > > of-the-box option! Lots of users may pull builds from a CI based on VMs > > > with > > > just a few cores, for instance. > > > > If not having the automatic detection is a concern because of users using > > CI builds, then we (if it's from our CI) can change what we're building in > > CI - the default/generic build seems like a good fit because it's supposed > > to work on a variety of systems. Expecting that native build from random > > VMs would work anywhere doesn't seen very realistic - it's been build for > > that VM environment (because it's a native build). > > > > Here's my understanding on which the current version is based: > > 1. Since we want to get away from having statically defined configuration, > > numa and core count discovery is exactly what we should have in the build > > system. Since discorery is currently the default for lib/drivers, it stands > > to reason it should be default for everything else, if possible. > > 2. Native build should produce binaries matching the build machine as well > > as possible. > > 3. Default/generic build should produce binaries executable on a range of > > systems (ideally all systems of a given architecture). > > 4. Other builds, that is non-native builds, are cross-compilation, since > > we're building for host machine other that the build machine. > > > > What I haven't taken into account is users using CI builds. That could be > > remedied by modifying the CI a bit while being consistent with what > > native/default/generic/cross builds are (or should be). And in any case, if > > we're not interested in testing the exact CI environment (which we aren't, > > since we don't want to use 2 cores with 1 numa), we really shouldn't be > > doing native builds there. > > > > I'm interested in hearing where my thinking deviates from yours. > > > > There are a number of points in which we differ, I think. > > Firstly, the use of "native" and "default/generic" for the "machine" > parameter refers only to the instruction-set level from the compiler, and > should not affect any other settings, since all settings are independent. > Therefore, setting "machine" to "native" does not mean that we should > detect cores and numa nodes, and similarly setting it to "default" does not > mean that we should ignore the settings for these values and pick our own > chosen default values. > > Secondly, the use of cross-compilation only applies when you are compiling > for a different architecture or environment (e.g. OS) to what you are > building on. Building on a 4-core x86 machine to run on a dual-socket, > 32-core x86 machine is not cross-compiling, but still needs to work by > default. Something like building a 32-bit binary on a 64-bit OS is in most > cases not done by cross-compilation either, but is rather outside the scope > of the discussion, except as a reference point to show the scope of > differences which can be accomodated as "native builds". > > In terms of dynamic configuration for things like cores and numa nodes, the > ideal end state here is not to have them detected at build time on the host > system, but instead to have them detected at runtime and sized dynamically. > In the absense of that, these values should be set to reasonable defaults > so that when a user compiles up a binary without settings these explicitly > it should run on 95%+ of systems of that type. > > This is my understanding of the issues, anyway. :-) > What could possibly work is to set the defaults for these to "0" as done in your patch, but thereafter have the resulting defaults set per-architecture, rather than globally. That would allow x86 to tune things more for native-style builds, while in all cases allowing user to override.
/Bruce