mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
Implemented proper detection of number of available CPU cores
This commit is contained in:
+337
@@ -3917,6 +3917,343 @@ AS_VAR_IF([enable_tools],["yes"],
|
||||
)
|
||||
]
|
||||
)
|
||||
AC_CHECK_HEADERS([features.h sys/pstat.h vxCpuLib.h],[],[],[AC_INCLUDES_DEFAULT])
|
||||
AC_CHECK_DECLS(
|
||||
[_SC_NPROCESSORS_ONLN,_SC_NPROC_ONLN,_SC_CRAY_NCPU,_SC_NPROCESSORS_CONF,CTL_HW,HW_NCPUONLINE,HW_NCPU,HW_AVAILCPU],
|
||||
[],[],
|
||||
[[
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif /* HAVE_SYS_TYPES_H */
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
#ifdef HAVE_SYS_SYSCTL_H
|
||||
#include <sys/sysctl.h>
|
||||
#endif /* HAVE_SYS_SYSCTL_H */
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
]]
|
||||
)
|
||||
MHD_CHECK_FUNC([pstat_getdynamic],[[
|
||||
#include <sys/param.h>
|
||||
#include <sys/pstat.h>
|
||||
]],
|
||||
[[
|
||||
struct pst_dynamic psd_data;
|
||||
i][f (1 != pstat_getdynamic(&psd_data, sizeof(psd_data), (size_t)1, 0))
|
||||
return 2;
|
||||
i][f (0 >= psd_data.psd_proc_cnt)
|
||||
return 3;
|
||||
]]
|
||||
)
|
||||
MHD_CHECK_FUNC([vxCpuEnabledGet],[[#include <vxCpuLib.h>]],
|
||||
[[
|
||||
cpuset_t enb_set;
|
||||
enb_set = vxCpuEnabledGet();
|
||||
(void) enb_set;
|
||||
]]
|
||||
)
|
||||
AC_CHECK_HEADERS([sched.h sys/_cpuset.h sys/cpuset.h],[],[],[AC_INCLUDES_DEFAULT])
|
||||
# glibc / Linux kernel
|
||||
MHD_CHECK_FUNC([getpid],[[
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif /* HAVE_SYS_TYPES_H */
|
||||
#include <unistd.h>
|
||||
]],
|
||||
[[
|
||||
pid_t cur_pid;
|
||||
cur_pid = getpid();
|
||||
(void) &cur_pid; /* Mute possible warning */
|
||||
]],
|
||||
[
|
||||
MHD_CHECK_FUNC([sched_getaffinity],[[
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif /* HAVE_SYS_TYPES_H */
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
]],
|
||||
[[
|
||||
cpu_set_t cur_set;
|
||||
i][f (0 != sched_getaffinity(getpid(), sizeof(cur_set), &cur_set))
|
||||
return 2;
|
||||
i][f (0 == CPU_SET (0, &cur_set))
|
||||
return 3; /* Actually this could be a valid result */
|
||||
]],
|
||||
[
|
||||
MHD_CHECK_FUNC([CPU_COUNT],[[
|
||||
#include <stddef.h>
|
||||
#include <sched.h>
|
||||
]],
|
||||
[[
|
||||
cpu_set_t cur_set;
|
||||
CPU_ZERO(&cur_set);
|
||||
i][f (0 != CPU_COUNT(&cur_set))
|
||||
return 2;
|
||||
]],
|
||||
[
|
||||
MHD_CHECK_FUNC([CPU_COUNT_S],[[
|
||||
#include <stddef.h>
|
||||
#include <sched.h>
|
||||
]],
|
||||
[[
|
||||
static const unsigned int set_size_cpus = 2048u;
|
||||
const size_t set_size_bytes = (size_t) CPU_ALLOC_SIZE(set_size_cpus);
|
||||
cpu_set_t *p_set;
|
||||
p_set = CPU_ALLOC(set_size_cpus);
|
||||
i][f (!p_set)
|
||||
return 2;
|
||||
CPU_ZERO_S(set_size_bytes, p_set);
|
||||
i][f (0 != CPU_COUNT_S(set_size_bytes, p_set))
|
||||
{
|
||||
CPU_FREE(p_set);
|
||||
return 3;
|
||||
}
|
||||
CPU_FREE(p_set);
|
||||
]],
|
||||
[AC_CHECK_DECLS([CPU_SETSIZE],[],[],[#include <sched.h>])]
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
# NetBSD
|
||||
# Should work only with -lrt, but actually works without it.
|
||||
MHD_CHECK_FUNC([sched_getaffinity_np],[[
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif /* HAVE_SYS_TYPES_H */
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
]],
|
||||
[[
|
||||
cpuset_t *cpuset_ptr;
|
||||
cpuid_t cpu_num = 0;
|
||||
cpuset_ptr = cpuset_create();
|
||||
i][f (!cpuset_ptr)
|
||||
return 2;
|
||||
i][f (0 != sched_getaffinity_np(getpid(), cpuset_size(cpuset_ptr), cpuset_ptr))
|
||||
{
|
||||
cpuset_destroy(cpuset_ptr);
|
||||
return 3;
|
||||
}
|
||||
i][f (0 >= cpuset_isset(cpu_num, cpuset_ptr))
|
||||
{
|
||||
cpuset_destroy(cpuset_ptr);
|
||||
return 4; /* Actually this could be a valid result */
|
||||
}
|
||||
cpuset_destroy(cpuset_ptr);
|
||||
]]
|
||||
)
|
||||
]
|
||||
)
|
||||
# FreeBSD
|
||||
MHD_CHECK_FUNC([cpuset_getaffinity],[[
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
#include <sys/cpuset.h>
|
||||
]],
|
||||
[[
|
||||
cpuset_t cur_mask;
|
||||
i][f (0 != cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, (id_t) -1, sizeof(cur_mask), &cur_mask))
|
||||
return 2;
|
||||
]],
|
||||
[
|
||||
MHD_CHECK_FUNC([CPU_COUNT],[[
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
#ifdef HAVE_SYS__CPUSET_H
|
||||
#include <sys/_cpuset.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
#include <sys/cpuset.h>
|
||||
]],
|
||||
[[
|
||||
cpuset_t test_mask;
|
||||
CPU_ZERO(&test_mask);
|
||||
i][f (0 != CPU_COUNT(&test_mask))
|
||||
return 2;
|
||||
]],
|
||||
[
|
||||
MHD_CHECK_FUNC([CPU_COUNT_S],[[
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
#ifdef HAVE_SYS__CPUSET_H
|
||||
#include <sys/_cpuset.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
#include <sys/cpuset.h>
|
||||
]],
|
||||
[[
|
||||
static const unsigned int max_cpu_num = 2048u;
|
||||
cpuset_t *mask_ptr;
|
||||
mask_ptr = CPU_ALLOC(max_cpu_num);
|
||||
i][f (! mask_ptr)
|
||||
return 2;
|
||||
i][f (0 != cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, (id_t) -1,
|
||||
CPU_ALLOC_SIZE(max_cpu_num), mask_ptr))
|
||||
{
|
||||
CPU_FREE(mask_ptr);
|
||||
return 3;
|
||||
}
|
||||
i][f (0 == CPU_COUNT_S(CPU_ALLOC_SIZE(max_cpu_num), &test_mask))
|
||||
{
|
||||
CPU_FREE(mask_ptr);
|
||||
return 4;
|
||||
}
|
||||
CPU_FREE(mask_ptr);
|
||||
]]
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
AS_VAR_IF([mhd_cv_func_CPU_COUNT_S],["yes"],
|
||||
[
|
||||
AC_CACHE_CHECK([whether CPU_COUNT_S() expects max CPU number as 'size' parameter],[mhd_cv_func_cpu_count_s_cpus],
|
||||
[
|
||||
AS_VAR_IF([cross-compiling],["yes"],[mhd_cv_func_cpu_count_s_cpus="assuming no"],
|
||||
[
|
||||
AC_LINK_IFELSE(
|
||||
[
|
||||
AC_LANG_PROGRAM([[
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif /* HAVE_SYS_TYPES_H */
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
#ifdef HAVE_SYS__CPUSET_H
|
||||
#include <sys/_cpuset.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
#ifdef HAVE_SYS_CPUSET_H
|
||||
#include <sys/cpuset.h>
|
||||
#endif /* HAVE_SYS_CPUSET_H */
|
||||
#ifdef HAVE_STDDEF_H
|
||||
#include <stddef.h>
|
||||
#endif /* HAVE_STDDEF_H */
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
#ifdef HAVE_SCHED_H
|
||||
#include <sched.h>
|
||||
#endif /* HAVE_SCHED_H */
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_SCHED_GETAFFINITY
|
||||
#define TEST_CPUSET_TYPE cpu_set_t
|
||||
#else /* ! HAVE_SCHED_GETAFFINITY */
|
||||
#define TEST_CPUSET_TYPE cpuset_t
|
||||
#endif /* ! HAVE_SCHED_GETAFFINITY */
|
||||
]],
|
||||
[[
|
||||
TEST_CPUSET_TYPE *p_testset;
|
||||
/* The size of the cpuset that is larger then the test cpuset (in CPUs) */
|
||||
static const unsigned int testset_size_oversized_cpus = (8 * sizeof(long)) * 1024;
|
||||
const size_t testset_size_oversized_bytes = CPU_ALLOC_SIZE(testset_size_oversized_cpus);
|
||||
/* The size of the test cpuset in number of CPUs */
|
||||
const unsigned int testset_size_cpus = (unsigned int) testset_size_oversized_bytes;
|
||||
/* The size of the test cpuset in bytes */
|
||||
const size_t testset_size_bytes = CPU_ALLOC_SIZE(testset_size_cpus);
|
||||
/* The last one CPU in the test set */
|
||||
const unsigned int test_cpu_num1 = testset_size_cpus - 1;
|
||||
/* The penultimate CPU in the test set */
|
||||
const unsigned int test_cpu_num2 = testset_size_cpus - 2;
|
||||
/* The CPU numbers that should be cleared */
|
||||
const unsigned int test_cpu_clear1 = testset_size_cpus - 3;
|
||||
const unsigned int test_cpu_clear2 = testset_size_cpus - 4;
|
||||
unsigned int count_res;
|
||||
int ret = 0;
|
||||
|
||||
/* Allocate oversize area to ensure that memory outside the buffer is not used */
|
||||
p_testset = CPU_ALLOC(testset_size_oversized_cpus);
|
||||
if (! p_testset)
|
||||
{
|
||||
fprintf (stderr, "Error allocating memory.\n");
|
||||
return 99;
|
||||
}
|
||||
/* Set the some CPU numbers and then clear them */
|
||||
CPU_SET_S(test_cpu_clear1, testset_size_bytes, p_testset);
|
||||
CPU_SET_S(test_cpu_clear2, testset_size_bytes, p_testset);
|
||||
CPU_ZERO_S(testset_size_bytes, p_testset);
|
||||
/* Set two CPUs on */
|
||||
CPU_SET_S(test_cpu_num1, testset_size_bytes, p_testset);
|
||||
CPU_SET_S(test_cpu_num2, testset_size_bytes, p_testset);
|
||||
count_res = (unsigned int) CPU_COUNT_S(testset_size_bytes, p_testset);
|
||||
if (0 == count_res)
|
||||
{
|
||||
fprintf (stderr, "Full cpuset cannot be read by CPU_COUNT_S() when using the number of bytes as the size parameter.\n");
|
||||
/* Set the some CPU numbers and then clear them */
|
||||
CPU_SET_S(test_cpu_clear1, testset_size_cpus, p_testset);
|
||||
CPU_SET_S(test_cpu_clear2, testset_size_cpus, p_testset);
|
||||
CPU_ZERO_S(testset_size_cpus, p_testset);
|
||||
/* Set two CPUs on */
|
||||
CPU_SET_S(test_cpu_num1, testset_size_cpus, p_testset);
|
||||
CPU_SET_S(test_cpu_num2, testset_size_cpus, p_testset);
|
||||
count_res = (unsigned int) CPU_COUNT_S(testset_size_cpus, p_testset);
|
||||
if (2 == count_res)
|
||||
{
|
||||
fprintf (stderr, "Full cpuset is read by CPU_COUNT_S() only when using the maximum CPU number as the size parameter.\n");
|
||||
ret = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Wrong result returned by CPU_COUNT_S() when using the maximum CPU number as the size parameter.\n");
|
||||
fprintf (stderr, "Number of 'enabled' CPUs: 2\n");
|
||||
fprintf (stderr, "Number of counted CPUs: %u\n", count_res);
|
||||
fprintf (stderr, "CPU_COUNT_S() could be unreliable.\n");
|
||||
ret = 70;
|
||||
}
|
||||
}
|
||||
else if (2 == count_res)
|
||||
{
|
||||
fprintf (stderr, "Full cpuset is read by CPU_COUNT_S() when using the number of bytes as the size parameter.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Wrong result returned by CPU_COUNT_S() when using the number of bytes as the size parameter.\n");
|
||||
fprintf (stderr, "Number of 'enabled' CPUs: 2\n");
|
||||
fprintf (stderr, "Number of counted CPUs: %u\n", count_res);
|
||||
fprintf (stderr, "CPU_COUNT_S() could be unreliable.\n");
|
||||
ret = 71;
|
||||
}
|
||||
CPU_FREE(p_testset);
|
||||
if (0 != ret)
|
||||
return ret;
|
||||
]]
|
||||
)
|
||||
],
|
||||
[
|
||||
AM_RUN_LOG([./conftest$EXEEXT])
|
||||
count_test_res=$?
|
||||
AS_IF([test $count_test_res -eq 0],[mhd_cv_func_cpu_count_s_cpus="no"],
|
||||
[test $count_test_res -eq 3],[mhd_cv_func_cpu_count_s_cpus="yes"],
|
||||
[
|
||||
AC_MSG_WARN([Unexpected value returned by CPU_COUNT_S() test program. Please report to ${PACKAGE_BUGREPORT}])
|
||||
mhd_cv_func_cpu_count_s_cpus="assuming no"
|
||||
]
|
||||
)
|
||||
],
|
||||
[
|
||||
AC_MSG_WARN([Cannot build CPU_COUNT_S() test program. Please report to ${PACKAGE_BUGREPORT}])
|
||||
mhd_cv_func_cpu_count_s_cpus="assuming no"
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
AS_VAR_IF([mhd_cv_func_cpu_count_s_cpus],["yes"],
|
||||
[AC_DEFINE([MHD_FUNC_CPU_COUNT_S_GETS_CPUS],[1],
|
||||
[Define to '1' if CPU_COUNT_S() function expects max CPU number as 'size' parameter])
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -192,5 +192,81 @@
|
||||
#endif /* MHD_HAVE_MHD_FUNC_ */
|
||||
#endif
|
||||
|
||||
/* Un-define some HAVE_DECL_* macro if they equal zero.
|
||||
This should allow safely use #ifdef in the code.
|
||||
Define HAS_DECL_* macros only if matching HAVE_DECL_* macro
|
||||
has non-zero value. Unlike HAVE_DECL_*, macros HAS_DECL_*
|
||||
cannot have zero value. */
|
||||
#ifdef HAVE_DECL__SC_NPROCESSORS_ONLN
|
||||
# if 0 == HAVE_DECL__SC_NPROCESSORS_ONLN
|
||||
# undef HAVE_DECL__SC_NPROCESSORS_ONLN
|
||||
# else /* 0 != HAVE_DECL__SC_NPROCESSORS_ONLN */
|
||||
# define HAS_DECL__SC_NPROCESSORS_ONLN 1
|
||||
# endif /* 0 != HAVE_DECL__SC_NPROCESSORS_ONLN */
|
||||
#endif /* HAVE_DECL__SC_NPROCESSORS_ONLN */
|
||||
|
||||
#ifdef HAVE_DECL__SC_NPROCESSORS_CONF
|
||||
# if 0 == HAVE_DECL__SC_NPROCESSORS_CONF
|
||||
# undef HAVE_DECL__SC_NPROCESSORS_CONF
|
||||
# else /* 0 != HAVE_DECL__SC_NPROCESSORS_CONF */
|
||||
# define HAS_DECL__SC_NPROCESSORS_CONF 1
|
||||
# endif /* 0 != HAVE_DECL__SC_NPROCESSORS_CONF */
|
||||
#endif /* HAVE_DECL__SC_NPROCESSORS_CONF */
|
||||
|
||||
#ifdef HAVE_DECL__SC_NPROC_ONLN
|
||||
# if 0 == HAVE_DECL__SC_NPROC_ONLN
|
||||
# undef HAVE_DECL__SC_NPROC_ONLN
|
||||
# else /* 0 != HAVE_DECL__SC_NPROC_ONLN */
|
||||
# define HAS_DECL__SC_NPROC_ONLN 1
|
||||
# endif /* 0 != HAVE_DECL__SC_NPROC_ONLN */
|
||||
#endif /* HAVE_DECL__SC_NPROC_ONLN */
|
||||
|
||||
#ifdef HAVE_DECL__SC_CRAY_NCPU
|
||||
# if 0 == HAVE_DECL__SC_CRAY_NCPU
|
||||
# undef HAVE_DECL__SC_CRAY_NCPU
|
||||
# else /* 0 != HAVE_DECL__SC_CRAY_NCPU */
|
||||
# define HAS_DECL__SC_CRAY_NCPU 1
|
||||
# endif /* 0 != HAVE_DECL__SC_CRAY_NCPU */
|
||||
#endif /* HAVE_DECL__SC_CRAY_NCPU */
|
||||
|
||||
#ifdef HAVE_DECL_CTL_HW
|
||||
# if 0 == HAVE_DECL_CTL_HW
|
||||
# undef HAVE_DECL_CTL_HW
|
||||
# else /* 0 != HAVE_DECL_CTL_HW */
|
||||
# define HAS_DECL_CTL_HW 1
|
||||
# endif /* 0 != HAVE_DECL_CTL_HW */
|
||||
#endif /* HAVE_DECL_CTL_HW */
|
||||
|
||||
#ifdef HAVE_DECL_HW_NCPUONLINE
|
||||
# if 0 == HAVE_DECL_HW_NCPUONLINE
|
||||
# undef HAVE_DECL_HW_NCPUONLINE
|
||||
# else /* 0 != HAVE_DECL_HW_NCPUONLINE */
|
||||
# define HAS_DECL_HW_NCPUONLINE 1
|
||||
# endif /* 0 != HAVE_DECL_HW_NCPUONLINE */
|
||||
#endif /* HAVE_DECL_HW_NCPUONLINE */
|
||||
|
||||
#ifdef HAVE_DECL_HW_AVAILCPU
|
||||
# if 0 == HAVE_DECL_HW_AVAILCPU
|
||||
# undef HAVE_DECL_HW_AVAILCPU
|
||||
# else /* 0 != HAVE_DECL_HW_AVAILCPU */
|
||||
# define HAS_DECL_HW_AVAILCPU 1
|
||||
# endif /* 0 != HAVE_DECL_HW_AVAILCPU */
|
||||
#endif /* HAVE_DECL_HW_AVAILCPU */
|
||||
|
||||
#ifdef HAVE_DECL_HW_NCPU
|
||||
# if 0 == HAVE_DECL_HW_NCPU
|
||||
# undef HAVE_DECL_HW_NCPU
|
||||
# else /* 0 != HAVE_DECL_HW_NCPU */
|
||||
# define HAS_DECL_HW_NCPU 1
|
||||
# endif /* 0 != HAVE_DECL_HW_NCPU */
|
||||
#endif /* HAVE_DECL_HW_NCPU */
|
||||
|
||||
#ifdef HAVE_DECL_CPU_SETSIZE
|
||||
# if 0 == HAVE_DECL_CPU_SETSIZE
|
||||
# undef HAVE_DECL_CPU_SETSIZE
|
||||
# else /* 0 != HAVE_DECL_CPU_SETSIZE */
|
||||
# define HAS_DECL_CPU_SETSIZE 1
|
||||
# endif /* 0 != HAVE_DECL_CPU_SETSIZE */
|
||||
#endif /* HAVE_DECL_CPU_SETSIZE */
|
||||
|
||||
#endif /* MHD_OPTIONS_H */
|
||||
|
||||
@@ -36,4 +36,5 @@ endif
|
||||
|
||||
|
||||
perf_replies_SOURCES = \
|
||||
perf_replies.c mhd_tool_str_to_uint.h
|
||||
perf_replies.c mhd_tool_str_to_uint.h \
|
||||
mhd_tool_get_cpu_count.h mhd_tool_get_cpu_count.c
|
||||
|
||||
@@ -0,0 +1,658 @@
|
||||
/*
|
||||
This file is part of GNU libmicrohttpd
|
||||
Copyright (C) 2023 Evgeny Grin (Karlson2k)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file tools/mhd_tool_get_cpu_count.c
|
||||
* @brief Implementation of functions to detect the number of available
|
||||
* CPU cores.
|
||||
* @author Karlson2k (Evgeny Grin)
|
||||
*/
|
||||
|
||||
#include "mhd_options.h"
|
||||
#include "mhd_tool_get_cpu_count.h"
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif /* HAVE_SYS_TYPES_H */
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
#ifdef HAVE_SYS__CPUSET_H
|
||||
# include <sys/_cpuset.h>
|
||||
#endif /* HAVE_SYS_PARAM_H */
|
||||
#ifdef HAVE_STDDEF_H
|
||||
# include <stddef.h>
|
||||
#endif /* HAVE_STDDEF_H */
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif /* HAVE_STRING_H */
|
||||
#ifdef HAVE_SYS_SYSCTL_H
|
||||
# include <sys/sysctl.h>
|
||||
#endif /* HAVE_SYS_SYSCTL_H */
|
||||
#ifdef HAVE_FEATURES_H
|
||||
# include <features.h>
|
||||
#endif /* HAVE_FEATURES_H */
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
#ifdef HAVE_VXCPULIB_H
|
||||
# include <vxCpuLib.h>
|
||||
#endif
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
# ifndef WIN32_LEAN_AND_MEAN
|
||||
# define WIN32_LEAN_AND_MEAN 1
|
||||
# endif /* ! WIN32_LEAN_AND_MEAN */
|
||||
# include <windows.h>
|
||||
# ifndef ALL_PROCESSOR_GROUPS
|
||||
# define ALL_PROCESSOR_GROUPS 0xFFFFu
|
||||
# endif /* ALL_PROCESSOR_GROUPS */
|
||||
#elif defined(_WIN32) && ! defined (__CYGWIN__)
|
||||
# error Windows headers are required for Windows build
|
||||
#endif /* HAVE_WINDOWS_H */
|
||||
#ifdef HAVE_SCHED_H
|
||||
# include <sched.h>
|
||||
#endif /* HAVE_SCHED_H */
|
||||
#ifdef HAVE_SYS_CPUSET_H
|
||||
# include <sys/cpuset.h>
|
||||
#endif /* HAVE_SYS_CPUSET_H */
|
||||
|
||||
#if ! defined(HAS_DECL_CPU_SETSIZE) && ! defined(CPU_SETSIZE)
|
||||
# define CPU_SETSIZE (1024)
|
||||
# define CPU_SETSIZE_SAFE (64)
|
||||
#else /* HAS_DECL_CPU_SETSIZE || CPU_SETSIZE */
|
||||
# define CPU_SETSIZE_SAFE CPU_SETSIZE
|
||||
#endif /* HAS_DECL_CPU_SETSIZE || CPU_SETSIZE */
|
||||
|
||||
/* Check and fix possible missing macros */
|
||||
#if ! defined(HAS_DECL_CTL_HW) && defined(CTL_HW)
|
||||
# define HAS_DECL_CTL_HW 1
|
||||
#endif /* ! HAS_DECL_CTL_HW && CTL_HW */
|
||||
|
||||
#if ! defined(HAS_DECL_HW_NCPUONLINE) && defined(HW_NCPUONLINE)
|
||||
# define HAS_DECL_HW_NCPUONLINE 1
|
||||
#endif /* ! HAS_DECL_HW_NCPUONLINE && HW_NCPUONLINE */
|
||||
|
||||
#if ! defined(HAS_DECL_HW_AVAILCPU) && defined(HW_AVAILCPU)
|
||||
# define HAS_DECL_HW_AVAILCPU 1
|
||||
#endif /* ! HAS_DECL_HW_AVAILCPU && HW_AVAILCPU */
|
||||
|
||||
#if ! defined(HAS_DECL_HW_NCPU) && defined(HW_NCPU)
|
||||
# define HAS_DECL_HW_NCPU 1
|
||||
#endif /* ! HAS_DECL_HW_NCPU && HW_NCPU */
|
||||
|
||||
#if ! defined(HAS_DECL__SC_NPROCESSORS_ONLN) && defined(_SC_NPROCESSORS_ONLN)
|
||||
# define HAS_DECL__SC_NPROCESSORS_ONLN 1
|
||||
#endif /* ! HAS_DECL__SC_NPROCESSORS_ONLN && _SC_NPROCESSORS_ONLN */
|
||||
|
||||
#if ! defined(HAS_DECL__SC_NPROC_ONLN) && defined(_SC_NPROC_ONLN)
|
||||
# define HAS_DECL__SC_NPROC_ONLN 1
|
||||
#endif /* ! HAS_DECL__SC_NPROC_ONLN && _SC_NPROC_ONLN */
|
||||
|
||||
#if ! defined(HAS_DECL__SC_CRAY_NCPU) && defined(_SC_CRAY_NCPU)
|
||||
# define HAS_DECL__SC_CRAY_NCPU 1
|
||||
#endif /* ! HAS_DECL__SC_CRAY_NCPU && _SC_CRAY_NCPU */
|
||||
|
||||
#if ! defined(HAS_DECL__SC_NPROCESSORS_CONF) && defined(_SC_NPROCESSORS_CONF)
|
||||
# define HAS_DECL__SC_NPROCESSORS_CONF 1
|
||||
#endif /* ! HAVE_DECL__SC_NPROCESSORS_CONF && _SC_NPROCESSORS_CONF */
|
||||
|
||||
/* Forward declarations */
|
||||
|
||||
static int
|
||||
mhd_tool_get_sys_cpu_count_sysctl_ (void);
|
||||
|
||||
/**
|
||||
* Detect the number of logical CPU cores available for the process by
|
||||
* sched_getaffinity() (and related) function.
|
||||
* @return the number of detected logical CPU cores or
|
||||
* -1 if failed to detect (or this function unavailable).
|
||||
*/
|
||||
static int
|
||||
mhd_tool_get_proc_cpu_count_sched_getaffinity_ (void)
|
||||
{
|
||||
int ret = -1;
|
||||
#if defined(HAVE_SCHED_GETAFFINITY) && defined(HAVE_GETPID)
|
||||
/* Glibc style */
|
||||
if (0 >= ret)
|
||||
{
|
||||
cpu_set_t cur_set;
|
||||
if (0 == sched_getaffinity (getpid (), sizeof(cur_set), &cur_set))
|
||||
{
|
||||
#ifdef HAVE_CPU_COUNT
|
||||
ret = CPU_COUNT (&cur_set);
|
||||
#else /* ! HAVE_CPU_COUNT */
|
||||
unsigned int i;
|
||||
ret = 0;
|
||||
for (i = 0; i < CPU_SETSIZE_SAFE; ++i)
|
||||
{
|
||||
if (CPU_ISSET (i, &cur_set))
|
||||
++ret;
|
||||
}
|
||||
if (0 == ret)
|
||||
ret = -1;
|
||||
#endif /* ! HAVE_CPU_COUNT */
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_CPU_COUNT_S
|
||||
if (0 >= ret)
|
||||
{
|
||||
/* Use 256 times larger size than size for default maximum CPU number.
|
||||
Hopefully it would be enough even for exotic situations. */
|
||||
static const unsigned int set_size_cpus = 256 * CPU_SETSIZE;
|
||||
const size_t set_size_bytes = CPU_ALLOC_SIZE (set_size_cpus);
|
||||
cpu_set_t *p_set;
|
||||
|
||||
p_set = CPU_ALLOC (set_size_cpus);
|
||||
if (NULL != p_set)
|
||||
{
|
||||
if (0 == sched_getaffinity (getpid (), set_size_bytes, p_set))
|
||||
{
|
||||
#ifndef MHD_FUNC_CPU_COUNT_S_GETS_CPUS
|
||||
ret = CPU_COUNT_S (set_size_bytes, p_set);
|
||||
#else /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */
|
||||
ret = CPU_COUNT_S (set_size_cpus, p_set);
|
||||
#endif /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */
|
||||
}
|
||||
CPU_FREE (p_set);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_CPU_COUNT_S */
|
||||
#endif /* HAVE_SCHED_GETAFFINITY && HAVE_GETPID */
|
||||
if (0 >= ret)
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect the number of logical CPU cores available for the process by
|
||||
* cpuset_getaffinity() function.
|
||||
* @return the number of detected logical CPU cores or
|
||||
* -1 if failed to detect (or this function unavailable).
|
||||
*/
|
||||
static int
|
||||
mhd_tool_get_proc_cpu_count_cpuset_getaffinity_ (void)
|
||||
{
|
||||
int ret = -1;
|
||||
#if defined(HAVE_CPUSET_GETAFFINITY)
|
||||
/* FreeBSD style */
|
||||
if (0 >= ret)
|
||||
{
|
||||
cpuset_t cur_mask;
|
||||
/* The should get "anonymous" mask/set. The anonymous mask is always
|
||||
a subset of the assigned set (which is a subset of the root set). */
|
||||
if (0 == cpuset_getaffinity (CPU_LEVEL_WHICH, CPU_WHICH_PID, (id_t) -1,
|
||||
sizeof(cur_mask), &cur_mask))
|
||||
{
|
||||
#ifdef HAVE_CPU_COUNT
|
||||
ret = CPU_COUNT (&cur_mask);
|
||||
#else /* ! HAVE_CPU_COUNT */
|
||||
unsigned int i;
|
||||
ret = 0;
|
||||
for (i = 0; i < CPU_SETSIZE_SAFE; ++i)
|
||||
{
|
||||
if (CPU_ISSET (i, &cur_mask))
|
||||
++ret;
|
||||
}
|
||||
if (0 == ret)
|
||||
ret = -1;
|
||||
#endif /* ! HAVE_CPU_COUNT */
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_CPU_COUNT_S
|
||||
if (0 >= ret)
|
||||
{
|
||||
/* Use 256 times larger size than size for default maximum CPU number.
|
||||
Hopefully it would be enough even for exotic situations. */
|
||||
static const unsigned int mask_size_cpus = 256 * CPU_SETSIZE;
|
||||
const size_t mask_size_bytes = CPU_ALLOC_SIZE (mask_size_cpus);
|
||||
cpuset_t *p_mask;
|
||||
|
||||
p_mask = CPU_ALLOC (mask_size_cpus);
|
||||
if (NULL != p_mask)
|
||||
{
|
||||
if (0 == cpuset_getaffinity (CPU_LEVEL_WHICH, CPU_WHICH_PID, (id_t) -1,
|
||||
mask_size_bytes, p_mask))
|
||||
{
|
||||
#ifndef MHD_FUNC_CPU_COUNT_S_GETS_CPUS
|
||||
ret = CPU_COUNT_S (mask_size_bytes, p_mask);
|
||||
#else /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */
|
||||
ret = CPU_COUNT_S (mask_size_cpus, p_mask);
|
||||
#endif /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */
|
||||
}
|
||||
CPU_FREE (p_mask);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_CPU_COUNT_S */
|
||||
#endif /* HAVE_CPUSET_GETAFFINITY */
|
||||
if (0 >= ret)
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect the number of logical CPU cores available for the process by
|
||||
* sched_getaffinity_np() (and related) function.
|
||||
* @return the number of detected logical CPU cores or
|
||||
* -1 if failed to detect (or this function unavailable).
|
||||
*/
|
||||
static int
|
||||
mhd_tool_get_proc_cpu_count_sched_getaffinity_np_ (void)
|
||||
{
|
||||
int ret = -1;
|
||||
#if defined(HAVE_SCHED_GETAFFINITY_NP) && defined(HAVE_GETPID)
|
||||
/* NetBSD style */
|
||||
cpuset_t *cpuset_ptr;
|
||||
cpuset_ptr = cpuset_create ();
|
||||
if (NULL != cpuset_ptr)
|
||||
{
|
||||
if (0 == sched_getaffinity_np (getpid (), cpuset_size (cpuset_ptr),
|
||||
cpuset_ptr))
|
||||
{
|
||||
cpuid_t cpu_num;
|
||||
#if defined(HAVE_SYSCONF) && defined(HAVE_DECL__SC_NPROCESSORS_CONF)
|
||||
unsigned int max_num = 0;
|
||||
long sc_value = -1;
|
||||
sc_value = sysconf (_SC_NPROCESSORS_ONLN);
|
||||
if (0 < sc_value)
|
||||
max_num = (unsigned int) sc_value;
|
||||
if (0 < max_num)
|
||||
{
|
||||
ret = 0;
|
||||
for (cpu_num = 0; cpu_num < max_num; ++cpu_num)
|
||||
if (0 < cpuset_isset (cpu_num, cpuset_ptr))
|
||||
++ret;
|
||||
}
|
||||
else /* Combined with the next 'if' */
|
||||
#endif /* HAVE_SYSCONF && HAVE_DECL__SC_NPROCESSORS_CONF */
|
||||
if (1)
|
||||
{
|
||||
int res;
|
||||
cpu_num = 0;
|
||||
ret = 0;
|
||||
do
|
||||
{
|
||||
res = cpuset_isset (cpu_num++, cpuset_ptr);
|
||||
if (0 < res)
|
||||
++ret;
|
||||
} while (0 <= res);
|
||||
}
|
||||
#ifdef __NetBSD__
|
||||
if (0 == ret)
|
||||
{
|
||||
/* On NetBSD "unset" affinity (exactly zero CPUs) means
|
||||
"all CPUs are available". */
|
||||
ret = mhd_tool_get_sys_cpu_count_sysctl_ ();
|
||||
}
|
||||
#endif /* __NetBSD__ */
|
||||
}
|
||||
cpuset_destroy (cpuset_ptr);
|
||||
}
|
||||
#endif /* HAVE_SCHED_GETAFFINITY_NP && HAVE_GETPID */
|
||||
if (0 >= ret)
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect the number of logical CPU cores available for the process.
|
||||
* The number of cores available for this process could be different from
|
||||
* value of cores available on the system. The OS may have limit on number
|
||||
* assigned/allowed cores for single process and process may have limited
|
||||
* CPU affinity.
|
||||
* @return the number of logical CPU cores available for the process or
|
||||
* -1 if failed to detect
|
||||
*/
|
||||
int
|
||||
mhd_tool_get_proc_cpu_count (void)
|
||||
{
|
||||
int res;
|
||||
|
||||
#if defined(__linux__) || defined(__GLIBC__)
|
||||
/* On Linux kernel try first 'sched_getaffinity()' as it should be
|
||||
the native API.
|
||||
Also try it first on other kernels if Glibc is used. */
|
||||
res = mhd_tool_get_proc_cpu_count_sched_getaffinity_ ();
|
||||
if (0 < res)
|
||||
return res;
|
||||
|
||||
res = mhd_tool_get_proc_cpu_count_cpuset_getaffinity_ ();
|
||||
if (0 < res)
|
||||
return res;
|
||||
#else /* ! __linux__ && ! __GLIBC__ */
|
||||
/* On non-Linux kernels 'cpuset_getaffinity()' could be the native API,
|
||||
while 'sched_getaffinity()' could be implemented in compatibility layer. */
|
||||
res = mhd_tool_get_proc_cpu_count_cpuset_getaffinity_ ();
|
||||
if (0 < res)
|
||||
return res;
|
||||
|
||||
res = mhd_tool_get_proc_cpu_count_sched_getaffinity_ ();
|
||||
if (0 < res)
|
||||
return res;
|
||||
#endif /* ! __linux__ && ! __GLIBC__ */
|
||||
|
||||
res = mhd_tool_get_proc_cpu_count_sched_getaffinity_np_ ();
|
||||
if (0 < res)
|
||||
return res;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect the number of processors by special API functions
|
||||
* @return number of processors as returned by special API functions or
|
||||
* -1 in case of error or special API functions unavailable
|
||||
*/
|
||||
static int
|
||||
mhd_tool_get_sys_cpu_count_special_api_ (void)
|
||||
{
|
||||
int ret = -1;
|
||||
#ifdef HAVE_PSTAT_GETDYNAMIC
|
||||
if (0 >= ret)
|
||||
{
|
||||
/* HP-UX things */
|
||||
struct pst_dynamic psd_data;
|
||||
memset ((void *) &psd_data, 0, sizeof(psd_data));
|
||||
if (1 == pstat_getdynamic (&psd_data, sizeof(psd_data), (size_t) 1, 0))
|
||||
{
|
||||
if (0 < psd_data.psd_proc_cnt)
|
||||
ret = (int) psd_data.psd_proc_cnt;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_PSTAT_GETDYNAMIC */
|
||||
#ifdef HAVE_VXCPUENABLEDGET
|
||||
if (0 >= ret)
|
||||
{
|
||||
/* VxWorks */
|
||||
cpuset_t enb_set;
|
||||
enb_set = vxCpuEnabledGet ();
|
||||
/* Count set bits */
|
||||
for (ret = 0; 0 != enb_set; enb_set &= enb_set - 1)
|
||||
++ret;
|
||||
}
|
||||
#endif /* HAVE_VXCPUENABLEDGET */
|
||||
#if defined(_WIN32) && ! defined (__CYGWIN__)
|
||||
if (0 >= ret)
|
||||
{
|
||||
/* Native W32 */
|
||||
HMODULE k32hndl;
|
||||
k32hndl = GetModuleHandleA ("kernel32.dll");
|
||||
if (NULL != k32hndl)
|
||||
{
|
||||
typedef DWORD (WINAPI *GAPC_PTR)(WORD GroupNumber);
|
||||
GAPC_PTR ptrGetActiveProcessorCount;
|
||||
/* Available on W7 or later */
|
||||
ptrGetActiveProcessorCount =
|
||||
(GAPC_PTR) (void *) GetProcAddress (k32hndl, "GetActiveProcessorCount");
|
||||
if (NULL != ptrGetActiveProcessorCount)
|
||||
{
|
||||
DWORD res;
|
||||
res = ptrGetActiveProcessorCount (ALL_PROCESSOR_GROUPS);
|
||||
ret = (int) res;
|
||||
if (res != (DWORD) ret)
|
||||
ret = -1; /* Overflow */
|
||||
}
|
||||
}
|
||||
if ((0 >= ret) && (NULL != k32hndl))
|
||||
{
|
||||
typedef void (WINAPI *GNSI_PTR)(SYSTEM_INFO *pSysInfo);
|
||||
GNSI_PTR ptrGetNativeSystemInfo;
|
||||
/* May give incorrect (low) result on versions from W7 to W11
|
||||
when more then 64 CPUs are available */
|
||||
ptrGetNativeSystemInfo =
|
||||
(GNSI_PTR) (void *) GetProcAddress (k32hndl, "GetNativeSystemInfo");
|
||||
if (NULL != ptrGetNativeSystemInfo)
|
||||
{
|
||||
SYSTEM_INFO sysInfo;
|
||||
|
||||
memset ((void *) &sysInfo, 0, sizeof(sysInfo));
|
||||
ptrGetNativeSystemInfo (&sysInfo);
|
||||
ret = (int) sysInfo.dwNumberOfProcessors;
|
||||
if (sysInfo.dwNumberOfProcessors != (DWORD) ret)
|
||||
ret = -1; /* Overflow */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (0 >= ret)
|
||||
{
|
||||
/* May give incorrect (low) result on versions from W7 to W11
|
||||
when more then 64 CPUs are available */
|
||||
SYSTEM_INFO sysInfo;
|
||||
memset ((void *) &sysInfo, 0, sizeof(sysInfo));
|
||||
GetSystemInfo (&sysInfo);
|
||||
ret = (int) sysInfo.dwNumberOfProcessors;
|
||||
if (sysInfo.dwNumberOfProcessors != (DWORD) ret)
|
||||
ret = -1; /* Overflow */
|
||||
}
|
||||
#endif /* _WIN32 && ! __CYGWIN__ */
|
||||
if (0 >= ret)
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect the number of processors by sysctl*() functions
|
||||
* @return number of processors as returned by 'sysctl*' functions or
|
||||
* -1 in case of error or the number cannot be detected
|
||||
* by these functions
|
||||
*/
|
||||
static int
|
||||
mhd_tool_get_sys_cpu_count_sysctl_ (void)
|
||||
{
|
||||
int ret = -1;
|
||||
/* Do not use sysctl() function on GNU/Linux even if
|
||||
sysctl() is available */
|
||||
#ifndef __linux__
|
||||
#ifdef HAVE_SYSCTLBYNAME
|
||||
if (0 >= ret)
|
||||
{
|
||||
size_t value_size = sizeof(ret);
|
||||
/* Darwin: The number of available logical CPUs */
|
||||
if ((0 != sysctlbyname ("hw.logicalcpu", &ret, &value_size,
|
||||
NULL, 0))
|
||||
|| (sizeof(ret) != value_size))
|
||||
ret = -1;
|
||||
}
|
||||
if (0 >= ret)
|
||||
{
|
||||
size_t value_size = sizeof(ret);
|
||||
/* FreeBSD: The number of online CPUs */
|
||||
if ((0 != sysctlbyname ("kern.smp.cpus", &ret, &value_size,
|
||||
NULL, 0))
|
||||
|| (sizeof(ret) != value_size))
|
||||
ret = -1;
|
||||
}
|
||||
if (0 >= ret)
|
||||
{
|
||||
size_t value_size = sizeof(ret);
|
||||
/* Darwin: The current number of CPUs available to run threads */
|
||||
if ((0 != sysctlbyname ("hw.activecpu", &ret, &value_size,
|
||||
NULL, 0))
|
||||
|| (sizeof(ret) != value_size))
|
||||
ret = -1;
|
||||
}
|
||||
if (0 >= ret)
|
||||
{
|
||||
size_t value_size = sizeof(ret);
|
||||
/* OpenBSD, NetBSD: The number of online CPUs */
|
||||
if ((0 != sysctlbyname ("hw.ncpuonline", &ret, &value_size,
|
||||
NULL, 0))
|
||||
|| (sizeof(ret) != value_size))
|
||||
ret = -1;
|
||||
}
|
||||
if (0 >= ret)
|
||||
{
|
||||
size_t value_size = sizeof(ret);
|
||||
/* Darwin: The old/alternative name for "hw.activecpu" */
|
||||
if ((0 != sysctlbyname ("hw.availcpu", &ret, &value_size,
|
||||
NULL, 0))
|
||||
|| (sizeof(ret) != value_size))
|
||||
ret = -1;
|
||||
}
|
||||
#endif /* HAVE_SYSCTLBYNAME */
|
||||
#if defined(HAVE_SYSCTL) && \
|
||||
defined(HAS_DECL_CTL_HW) && \
|
||||
defined(HAS_DECL_HW_NCPUONLINE)
|
||||
if (0 >= ret)
|
||||
{
|
||||
/* OpenBSD, NetBSD: The number of online CPUs */
|
||||
int mib[2] = { CTL_HW, HW_NCPUONLINE };
|
||||
size_t value_size = sizeof(ret);
|
||||
if ((0 != sysctl (mib, 2, &ret, &value_size, NULL, 0))
|
||||
|| (sizeof(ret) != value_size))
|
||||
ret = -1;
|
||||
}
|
||||
#endif /* HAVE_SYSCTL && HAS_DECL_CTL_HW && HAS_DECL_HW_NCPUONLINE */
|
||||
#if defined(HAVE_SYSCTL) && \
|
||||
defined(HAS_DECL_CTL_HW) && \
|
||||
defined(HAS_DECL_HW_AVAILCPU)
|
||||
if (0 >= ret)
|
||||
{
|
||||
/* Darwin: The MIB name for "hw.activecpu" */
|
||||
int mib[2] = { CTL_HW, HW_AVAILCPU };
|
||||
size_t value_size = sizeof(ret);
|
||||
if ((0 != sysctl (mib, 2, &ret, &value_size, NULL, 0))
|
||||
|| (sizeof(ret) != value_size))
|
||||
ret = -1;
|
||||
}
|
||||
#endif /* HAVE_SYSCTL && HAS_DECL_CTL_HW && HAS_DECL_HW_AVAILCPU */
|
||||
#ifdef HAVE_SYSCTLBYNAME
|
||||
if (0 >= ret)
|
||||
{
|
||||
size_t value_size = sizeof(ret);
|
||||
/* FreeBSD, OpenBSD, NetBSD, Darwin (and others?): The number of CPUs */
|
||||
if ((0 != sysctlbyname ("hw.ncpu", &ret, &value_size,
|
||||
NULL, 0))
|
||||
|| (sizeof(ret) != value_size))
|
||||
ret = -1;
|
||||
}
|
||||
#endif /* HAVE_SYSCTLBYNAME */
|
||||
#if defined(HAVE_SYSCTL) && \
|
||||
defined(HAS_DECL_CTL_HW) && \
|
||||
defined(HAS_DECL_HW_NCPU)
|
||||
if (0 >= ret)
|
||||
{
|
||||
/* FreeBSD, OpenBSD, NetBSD, Darwin (and others?): The number of CPUs */
|
||||
int mib[2] = { CTL_HW, HW_NCPU };
|
||||
size_t value_size = sizeof(ret);
|
||||
if ((0 != sysctl (mib, 2, &ret, &value_size, NULL, 0))
|
||||
|| (sizeof(ret) != value_size))
|
||||
ret = -1;
|
||||
}
|
||||
#endif /* HAVE_SYSCTL && HAS_DECL_CTL_HW && HAS_DECL_HW_NCPU */
|
||||
#endif /* ! __linux__ */
|
||||
if (0 >= ret)
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect the number of processors by sysconf() function
|
||||
* @return number of processors as returned by 'sysconf' function or
|
||||
* -1 in case of error or 'sysconf' unavailable
|
||||
*/
|
||||
static int
|
||||
mhd_tool_get_sys_cpu_count_sysconf_ (void)
|
||||
{
|
||||
int ret = -1;
|
||||
#if defined(HAVE_SYSCONF) && \
|
||||
(defined(HAS_DECL__SC_NPROCESSORS_ONLN) || \
|
||||
defined(HAS_DECL__SC_NPROC_ONLN) || \
|
||||
defined(HAS_DECL__SC_CRAY_NCPU))
|
||||
long value = -1;
|
||||
#ifdef HAS_DECL__SC_NPROCESSORS_ONLN
|
||||
if (0 >= value)
|
||||
value = sysconf (_SC_NPROCESSORS_ONLN);
|
||||
#endif /* HAS_DECL__SC_NPROCESSORS_ONLN */
|
||||
#ifdef HAS_DECL__SC_NPROC_ONLN
|
||||
if (0 >= value)
|
||||
value = sysconf (_SC_NPROC_ONLN);
|
||||
#endif /* HAS_DECL__SC_NPROC_ONLN */
|
||||
#ifdef HAS_DECL__SC_CRAY_NCPU
|
||||
if (0 >= value)
|
||||
value = sysconf (_SC_CRAY_NCPU);
|
||||
#endif /* HAS_DECL__SC_CRAY_NCPU */
|
||||
if (0 >= value)
|
||||
return -1;
|
||||
ret = (int) value;
|
||||
if ((long) ret != value)
|
||||
return -1; /* Overflow */
|
||||
#endif /* HAVE_SYSCONF &&
|
||||
(HAS_DECL__SC_NPROCESSORS_ONLN || HAS_DECL__SC_NPROC_ONLN ||
|
||||
HAS_DECL__SC_CRAY_NCPU) */
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to detect the number of logical CPU cores available for the system.
|
||||
* The number of available logical CPU cores could be changed any time due to
|
||||
* CPU hotplug.
|
||||
* @return the number of logical CPU cores available,
|
||||
* -1 if failed to detect.
|
||||
*/
|
||||
int
|
||||
mhd_tool_get_system_cpu_count (void)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* Try specialised APIs first */
|
||||
res = mhd_tool_get_sys_cpu_count_special_api_ ();
|
||||
if (0 < res)
|
||||
return res;
|
||||
|
||||
/* Try sysctl*(). This is typically a direct interface to
|
||||
kernel values. */
|
||||
res = mhd_tool_get_sys_cpu_count_sysctl_ ();
|
||||
if (0 < res)
|
||||
return res;
|
||||
|
||||
/* Try sysconf() as the last resort as this is a generic interface
|
||||
which can be implemented by parsing system files. */
|
||||
res = mhd_tool_get_sys_cpu_count_sysconf_ ();
|
||||
#if ! defined(__linux__) && ! defined(__GLIBC__)
|
||||
if (0 < res)
|
||||
return res;
|
||||
#else /* __linux__ || __GLIBC__ */
|
||||
if (2 < res)
|
||||
return res;
|
||||
if (0 < res)
|
||||
{
|
||||
/* '1' or '2' could a be fallback number.
|
||||
* See get_nprocs_fallback() in glibc
|
||||
sysdeps/unix/sysv/linux/getsysstats.c */
|
||||
|
||||
int proc_cpu_count;
|
||||
|
||||
proc_cpu_count = mhd_tool_get_proc_cpu_count ();
|
||||
if ((0 < proc_cpu_count) && (proc_cpu_count <= res))
|
||||
{
|
||||
/* The detected number of CPUs available for the process
|
||||
is 1 or 2 and fits detected number of system CPUS.
|
||||
Assume detected number is correct. */
|
||||
return res;
|
||||
}
|
||||
}
|
||||
#endif /* __linux__ || __GLIBC__ */
|
||||
return -1; /* Cannot detect */
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
This file is part of GNU libmicrohttpd
|
||||
Copyright (C) 2023 Evgeny Grin (Karlson2k)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file tools/mhd_tool_get_cpu_count.h
|
||||
* @brief Declaration of functions to detect the number of available
|
||||
* CPU cores.
|
||||
* @author Karlson2k (Evgeny Grin)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SRC_TOOLS_MHD_TOOL_GET_CPU_COUNT_H_
|
||||
#define SRC_TOOLS_MHD_TOOL_GET_CPU_COUNT_H_ 1
|
||||
|
||||
|
||||
/**
|
||||
* Detect the number of logical CPU cores available for the process.
|
||||
* The number of cores available for this process could be different from
|
||||
* value of cores available on the system. The OS may have limit on number
|
||||
* assigned/allowed cores for single process and process may have limited
|
||||
* CPU affinity.
|
||||
* @return the number of logical CPU cores available for the process or
|
||||
* -1 if failed to detect
|
||||
*/
|
||||
int
|
||||
mhd_tool_get_proc_cpu_count (void);
|
||||
|
||||
|
||||
/**
|
||||
* Try to detect the number of logical CPU cores available for the system.
|
||||
* The number of available logical CPU cores could be changed any time due to
|
||||
* CPU hotplug.
|
||||
* @return the number of logical CPU cores available,
|
||||
* -1 if failed to detect.
|
||||
*/
|
||||
int
|
||||
mhd_tool_get_system_cpu_count (void);
|
||||
|
||||
#endif /* SRC_TOOLS_MHD_TOOL_GET_CPU_COUNT_H_ */
|
||||
+104
-28
@@ -39,6 +39,7 @@
|
||||
#include "mhd_options.h"
|
||||
#include "microhttpd.h"
|
||||
#include "mhd_tool_str_to_uint.h"
|
||||
#include "mhd_tool_get_cpu_count.h"
|
||||
|
||||
#if defined(MHD_REAL_CPU_COUNT)
|
||||
#if MHD_REAL_CPU_COUNT == 0
|
||||
@@ -165,28 +166,37 @@ get_cmd_out_as_number (const char *cmd)
|
||||
static unsigned int
|
||||
detect_cpu_core_count (void)
|
||||
{
|
||||
int sys_cpu_count = -1;
|
||||
#if ! defined(_WIN32) || defined(__CYGWIN__)
|
||||
sys_cpu_count = get_cmd_out_as_number ("nproc 2>/dev/null");
|
||||
#endif /* ! _WIN32) || __CYGWIN__ */
|
||||
#ifdef _WIN32
|
||||
if (0 >= sys_cpu_count)
|
||||
sys_cpu_count = get_cmd_out_as_number ("echo %NUMBER_OF_PROCESSORS%");
|
||||
#endif /* _WIN32 */
|
||||
int sys_cpu_count;
|
||||
sys_cpu_count = mhd_tool_get_system_cpu_count ();
|
||||
if (0 >= sys_cpu_count)
|
||||
{
|
||||
fprintf (stderr, "Failed to detect the number of available CPU cores.\n");
|
||||
int proc_cpu_count;
|
||||
fprintf (stderr, "Failed to detect the number of logical CPU cores "
|
||||
"available on the system.\n");
|
||||
proc_cpu_count = mhd_tool_get_proc_cpu_count ();
|
||||
if (0 < proc_cpu_count)
|
||||
{
|
||||
fprintf (stderr, "The number of CPU cores available for this process "
|
||||
"is used as a fallback.\n");
|
||||
sys_cpu_count = proc_cpu_count;
|
||||
}
|
||||
#ifdef MHD_REAL_CPU_COUNT
|
||||
fprintf (stderr, "Hardcoded number is used as a fallback.\n");
|
||||
sys_cpu_count = MHD_REAL_CPU_COUNT;
|
||||
if (0 >= sys_cpu_count)
|
||||
{
|
||||
fprintf (stderr, "configure-detected hardcoded number is used "
|
||||
"as a fallback.\n");
|
||||
sys_cpu_count = MHD_REAL_CPU_COUNT;
|
||||
}
|
||||
#endif
|
||||
if (0 >= sys_cpu_count)
|
||||
sys_cpu_count = 1;
|
||||
printf ("Assuming %d CPU cores.\n", sys_cpu_count);
|
||||
printf ("Assuming %d logical CPU core%s on this system.\n", sys_cpu_count,
|
||||
(1 == sys_cpu_count) ? "" : "s");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Detected %d CPU cores.\n", sys_cpu_count);
|
||||
printf ("Detected %d logical CPU core%s on this system.\n", sys_cpu_count,
|
||||
(1 == sys_cpu_count) ? "" : "s");
|
||||
}
|
||||
return (unsigned int) sys_cpu_count;
|
||||
}
|
||||
@@ -202,20 +212,84 @@ get_cpu_core_count (void)
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
detect_process_cpu_core_count (void)
|
||||
{
|
||||
unsigned int num_proc_cpu_cores;
|
||||
unsigned int sys_cpu_cores;
|
||||
int res;
|
||||
|
||||
sys_cpu_cores = get_cpu_core_count ();
|
||||
res = mhd_tool_get_proc_cpu_count ();
|
||||
if (0 > res)
|
||||
{
|
||||
fprintf (stderr, "Cannot detect the number of logical CPU cores available "
|
||||
"for this process.\n");
|
||||
if (1 != sys_cpu_cores)
|
||||
printf ("Assuming all %u system logical CPU cores are available to run "
|
||||
"threads of this process.\n", sys_cpu_cores);
|
||||
else
|
||||
printf ("Assuming single logical CPU core available for this process.\n");
|
||||
num_proc_cpu_cores = sys_cpu_cores;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Detected %d logical CPU core%s available to run threads "
|
||||
"of this process.\n", res, (1 == res) ? "" : "s");
|
||||
num_proc_cpu_cores = (unsigned int) res;
|
||||
}
|
||||
if (num_proc_cpu_cores > sys_cpu_cores)
|
||||
{
|
||||
fprintf (stderr, "WARNING: Detected number of CPU cores available "
|
||||
"for this process (%u) is larger than detected number "
|
||||
"of CPU cores on the system (%u).\n",
|
||||
num_proc_cpu_cores, sys_cpu_cores);
|
||||
num_proc_cpu_cores = sys_cpu_cores;
|
||||
fprintf (stderr, "Using %u as the number of logical CPU cores available "
|
||||
"for this process.\n", num_proc_cpu_cores);
|
||||
}
|
||||
return num_proc_cpu_cores;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
get_process_cpu_core_count (void)
|
||||
{
|
||||
static unsigned int proc_num_cpu_cores = 0;
|
||||
if (0 == proc_num_cpu_cores)
|
||||
proc_num_cpu_cores = detect_process_cpu_core_count ();
|
||||
return proc_num_cpu_cores;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int num_threads = 0;
|
||||
|
||||
static unsigned int
|
||||
get_num_threads (void)
|
||||
{
|
||||
static const unsigned int max_threads = 32;
|
||||
if (0 < num_threads)
|
||||
return num_threads;
|
||||
|
||||
num_threads = get_cpu_core_count () / 2;
|
||||
if (0 == num_threads)
|
||||
num_threads = 1;
|
||||
else
|
||||
{
|
||||
num_threads = get_cpu_core_count () / 2;
|
||||
if (0 == num_threads)
|
||||
num_threads = 1;
|
||||
else
|
||||
unsigned int num_proc_cpus;
|
||||
num_proc_cpus = get_process_cpu_core_count ();
|
||||
if (num_proc_cpus >= num_threads)
|
||||
{
|
||||
printf ("Using half of all available CPU cores, assuming the other half "
|
||||
"is used by client / requests generator.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Using all CPU cores available for this process as more than "
|
||||
"half of CPU cores on this system are still available for use "
|
||||
"by client / requests generator.\n");
|
||||
num_threads = num_proc_cpus;
|
||||
}
|
||||
}
|
||||
if (max_threads < num_threads)
|
||||
{
|
||||
@@ -1059,9 +1133,10 @@ check_apply_param__all_cpus (void)
|
||||
if (! tool_params.all_cpus)
|
||||
return;
|
||||
|
||||
num_threads = get_cpu_core_count ();
|
||||
num_threads = get_process_cpu_core_count ();
|
||||
printf ("Requested use of all available CPU cores for MHD threads.\n");
|
||||
print_all_cores_used ();
|
||||
if (get_cpu_core_count () == num_threads)
|
||||
print_all_cores_used ();
|
||||
}
|
||||
|
||||
|
||||
@@ -1075,20 +1150,21 @@ check_apply_param__threads (void)
|
||||
return;
|
||||
|
||||
num_threads = tool_params.threads;
|
||||
|
||||
if (get_process_cpu_core_count () < num_threads)
|
||||
{
|
||||
fprintf (stderr, "WARNING: The requested number of threads (%u) is "
|
||||
"higher than the number of detected available CPU cores (%u).\n",
|
||||
num_threads, get_process_cpu_core_count ());
|
||||
fprintf (stderr, "This decreases the performance. "
|
||||
"Consider using fewer threads.\n");
|
||||
}
|
||||
if (get_cpu_core_count () == num_threads)
|
||||
{
|
||||
printf ("The requested number of threads is equal to the number of "
|
||||
"detected CPU cores.\n");
|
||||
print_all_cores_used ();
|
||||
}
|
||||
else if (get_cpu_core_count () < num_threads)
|
||||
{
|
||||
fprintf (stderr, "WARNING: The requested number of threads (%u) is "
|
||||
"higher than the number of detected CPU cores (%u).\n",
|
||||
num_threads, get_cpu_core_count ());
|
||||
fprintf (stderr, "This decreases the performance. "
|
||||
"Consider using fewer threads.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1228,7 +1304,7 @@ static struct MHD_Response *resp_single = NULL;
|
||||
The system will keep it in cache. */
|
||||
static const char tiny_body[] = "Hi!";
|
||||
static char *body_dyn = NULL; /* Non-static body data */
|
||||
size_t body_dyn_size;
|
||||
static size_t body_dyn_size;
|
||||
|
||||
/* Non-zero - success, zero - failure */
|
||||
static int
|
||||
|
||||
Reference in New Issue
Block a user