diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2023-07-12 21:29:45 +0300 |
---|---|---|
committer | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2023-07-29 23:38:13 +0300 |
commit | e87d26c42902db03560ef2e71e7e656bfd32b5a7 (patch) | |
tree | c62cc4340e3eedc3c52c4904fb65bb47a2e7768b | |
parent | 8a6307e08c45672e10736ceed95cf0ee377123e0 (diff) | |
download | libmicrohttpd-e87d26c42902db03560ef2e71e7e656bfd32b5a7.tar.gz libmicrohttpd-e87d26c42902db03560ef2e71e7e656bfd32b5a7.zip |
Implemented proper detection of number of available CPU cores
-rw-r--r-- | configure.ac | 337 | ||||
-rw-r--r-- | src/include/mhd_options.h | 76 | ||||
-rw-r--r-- | src/tools/Makefile.am | 3 | ||||
-rw-r--r-- | src/tools/mhd_tool_get_cpu_count.c | 658 | ||||
-rw-r--r-- | src/tools/mhd_tool_get_cpu_count.h | 55 | ||||
-rw-r--r-- | src/tools/perf_replies.c | 132 |
6 files changed, 1232 insertions, 29 deletions
diff --git a/configure.ac b/configure.ac index 65a700fb..b9160692 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -3917,6 +3917,343 @@ AS_VAR_IF([enable_tools],["yes"], | |||
3917 | ) | 3917 | ) |
3918 | ] | 3918 | ] |
3919 | ) | 3919 | ) |
3920 | AC_CHECK_HEADERS([features.h sys/pstat.h vxCpuLib.h],[],[],[AC_INCLUDES_DEFAULT]) | ||
3921 | AC_CHECK_DECLS( | ||
3922 | [_SC_NPROCESSORS_ONLN,_SC_NPROC_ONLN,_SC_CRAY_NCPU,_SC_NPROCESSORS_CONF,CTL_HW,HW_NCPUONLINE,HW_NCPU,HW_AVAILCPU], | ||
3923 | [],[], | ||
3924 | [[ | ||
3925 | #ifdef HAVE_SYS_TYPES_H | ||
3926 | #include <sys/types.h> | ||
3927 | #endif /* HAVE_SYS_TYPES_H */ | ||
3928 | #ifdef HAVE_SYS_PARAM_H | ||
3929 | #include <sys/param.h> | ||
3930 | #endif /* HAVE_SYS_PARAM_H */ | ||
3931 | #ifdef HAVE_SYS_SYSCTL_H | ||
3932 | #include <sys/sysctl.h> | ||
3933 | #endif /* HAVE_SYS_SYSCTL_H */ | ||
3934 | #ifdef HAVE_UNISTD_H | ||
3935 | #include <unistd.h> | ||
3936 | #endif /* HAVE_UNISTD_H */ | ||
3937 | ]] | ||
3938 | ) | ||
3939 | MHD_CHECK_FUNC([pstat_getdynamic],[[ | ||
3940 | #include <sys/param.h> | ||
3941 | #include <sys/pstat.h> | ||
3942 | ]], | ||
3943 | [[ | ||
3944 | struct pst_dynamic psd_data; | ||
3945 | i][f (1 != pstat_getdynamic(&psd_data, sizeof(psd_data), (size_t)1, 0)) | ||
3946 | return 2; | ||
3947 | i][f (0 >= psd_data.psd_proc_cnt) | ||
3948 | return 3; | ||
3949 | ]] | ||
3950 | ) | ||
3951 | MHD_CHECK_FUNC([vxCpuEnabledGet],[[#include <vxCpuLib.h>]], | ||
3952 | [[ | ||
3953 | cpuset_t enb_set; | ||
3954 | enb_set = vxCpuEnabledGet(); | ||
3955 | (void) enb_set; | ||
3956 | ]] | ||
3957 | ) | ||
3958 | AC_CHECK_HEADERS([sched.h sys/_cpuset.h sys/cpuset.h],[],[],[AC_INCLUDES_DEFAULT]) | ||
3959 | # glibc / Linux kernel | ||
3960 | MHD_CHECK_FUNC([getpid],[[ | ||
3961 | #ifdef HAVE_SYS_TYPES_H | ||
3962 | #include <sys/types.h> | ||
3963 | #endif /* HAVE_SYS_TYPES_H */ | ||
3964 | #include <unistd.h> | ||
3965 | ]], | ||
3966 | [[ | ||
3967 | pid_t cur_pid; | ||
3968 | cur_pid = getpid(); | ||
3969 | (void) &cur_pid; /* Mute possible warning */ | ||
3970 | ]], | ||
3971 | [ | ||
3972 | MHD_CHECK_FUNC([sched_getaffinity],[[ | ||
3973 | #ifdef HAVE_SYS_TYPES_H | ||
3974 | #include <sys/types.h> | ||
3975 | #endif /* HAVE_SYS_TYPES_H */ | ||
3976 | #include <unistd.h> | ||
3977 | #include <sched.h> | ||
3978 | ]], | ||
3979 | [[ | ||
3980 | cpu_set_t cur_set; | ||
3981 | i][f (0 != sched_getaffinity(getpid(), sizeof(cur_set), &cur_set)) | ||
3982 | return 2; | ||
3983 | i][f (0 == CPU_SET (0, &cur_set)) | ||
3984 | return 3; /* Actually this could be a valid result */ | ||
3985 | ]], | ||
3986 | [ | ||
3987 | MHD_CHECK_FUNC([CPU_COUNT],[[ | ||
3988 | #include <stddef.h> | ||
3989 | #include <sched.h> | ||
3990 | ]], | ||
3991 | [[ | ||
3992 | cpu_set_t cur_set; | ||
3993 | CPU_ZERO(&cur_set); | ||
3994 | i][f (0 != CPU_COUNT(&cur_set)) | ||
3995 | return 2; | ||
3996 | ]], | ||
3997 | [ | ||
3998 | MHD_CHECK_FUNC([CPU_COUNT_S],[[ | ||
3999 | #include <stddef.h> | ||
4000 | #include <sched.h> | ||
4001 | ]], | ||
4002 | [[ | ||
4003 | static const unsigned int set_size_cpus = 2048u; | ||
4004 | const size_t set_size_bytes = (size_t) CPU_ALLOC_SIZE(set_size_cpus); | ||
4005 | cpu_set_t *p_set; | ||
4006 | p_set = CPU_ALLOC(set_size_cpus); | ||
4007 | i][f (!p_set) | ||
4008 | return 2; | ||
4009 | CPU_ZERO_S(set_size_bytes, p_set); | ||
4010 | i][f (0 != CPU_COUNT_S(set_size_bytes, p_set)) | ||
4011 | { | ||
4012 | CPU_FREE(p_set); | ||
4013 | return 3; | ||
4014 | } | ||
4015 | CPU_FREE(p_set); | ||
4016 | ]], | ||
4017 | [AC_CHECK_DECLS([CPU_SETSIZE],[],[],[#include <sched.h>])] | ||
4018 | ) | ||
4019 | ] | ||
4020 | ) | ||
4021 | ] | ||
4022 | ) | ||
4023 | # NetBSD | ||
4024 | # Should work only with -lrt, but actually works without it. | ||
4025 | MHD_CHECK_FUNC([sched_getaffinity_np],[[ | ||
4026 | #ifdef HAVE_SYS_TYPES_H | ||
4027 | #include <sys/types.h> | ||
4028 | #endif /* HAVE_SYS_TYPES_H */ | ||
4029 | #include <unistd.h> | ||
4030 | #include <sched.h> | ||
4031 | ]], | ||
4032 | [[ | ||
4033 | cpuset_t *cpuset_ptr; | ||
4034 | cpuid_t cpu_num = 0; | ||
4035 | cpuset_ptr = cpuset_create(); | ||
4036 | i][f (!cpuset_ptr) | ||
4037 | return 2; | ||
4038 | i][f (0 != sched_getaffinity_np(getpid(), cpuset_size(cpuset_ptr), cpuset_ptr)) | ||
4039 | { | ||
4040 | cpuset_destroy(cpuset_ptr); | ||
4041 | return 3; | ||
4042 | } | ||
4043 | i][f (0 >= cpuset_isset(cpu_num, cpuset_ptr)) | ||
4044 | { | ||
4045 | cpuset_destroy(cpuset_ptr); | ||
4046 | return 4; /* Actually this could be a valid result */ | ||
4047 | } | ||
4048 | cpuset_destroy(cpuset_ptr); | ||
4049 | ]] | ||
4050 | ) | ||
4051 | ] | ||
4052 | ) | ||
4053 | # FreeBSD | ||
4054 | MHD_CHECK_FUNC([cpuset_getaffinity],[[ | ||
4055 | #ifdef HAVE_SYS_PARAM_H | ||
4056 | #include <sys/param.h> | ||
4057 | #endif /* HAVE_SYS_PARAM_H */ | ||
4058 | #include <sys/cpuset.h> | ||
4059 | ]], | ||
4060 | [[ | ||
4061 | cpuset_t cur_mask; | ||
4062 | i][f (0 != cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, (id_t) -1, sizeof(cur_mask), &cur_mask)) | ||
4063 | return 2; | ||
4064 | ]], | ||
4065 | [ | ||
4066 | MHD_CHECK_FUNC([CPU_COUNT],[[ | ||
4067 | #ifdef HAVE_SYS_PARAM_H | ||
4068 | #include <sys/param.h> | ||
4069 | #endif /* HAVE_SYS_PARAM_H */ | ||
4070 | #ifdef HAVE_SYS__CPUSET_H | ||
4071 | #include <sys/_cpuset.h> | ||
4072 | #endif /* HAVE_SYS_PARAM_H */ | ||
4073 | #include <sys/cpuset.h> | ||
4074 | ]], | ||
4075 | [[ | ||
4076 | cpuset_t test_mask; | ||
4077 | CPU_ZERO(&test_mask); | ||
4078 | i][f (0 != CPU_COUNT(&test_mask)) | ||
4079 | return 2; | ||
4080 | ]], | ||
4081 | [ | ||
4082 | MHD_CHECK_FUNC([CPU_COUNT_S],[[ | ||
4083 | #ifdef HAVE_SYS_PARAM_H | ||
4084 | #include <sys/param.h> | ||
4085 | #endif /* HAVE_SYS_PARAM_H */ | ||
4086 | #ifdef HAVE_SYS__CPUSET_H | ||
4087 | #include <sys/_cpuset.h> | ||
4088 | #endif /* HAVE_SYS_PARAM_H */ | ||
4089 | #include <sys/cpuset.h> | ||
4090 | ]], | ||
4091 | [[ | ||
4092 | static const unsigned int max_cpu_num = 2048u; | ||
4093 | cpuset_t *mask_ptr; | ||
4094 | mask_ptr = CPU_ALLOC(max_cpu_num); | ||
4095 | i][f (! mask_ptr) | ||
4096 | return 2; | ||
4097 | i][f (0 != cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, (id_t) -1, | ||
4098 | CPU_ALLOC_SIZE(max_cpu_num), mask_ptr)) | ||
4099 | { | ||
4100 | CPU_FREE(mask_ptr); | ||
4101 | return 3; | ||
4102 | } | ||
4103 | i][f (0 == CPU_COUNT_S(CPU_ALLOC_SIZE(max_cpu_num), &test_mask)) | ||
4104 | { | ||
4105 | CPU_FREE(mask_ptr); | ||
4106 | return 4; | ||
4107 | } | ||
4108 | CPU_FREE(mask_ptr); | ||
4109 | ]] | ||
4110 | ) | ||
4111 | ] | ||
4112 | ) | ||
4113 | ] | ||
4114 | ) | ||
4115 | AS_VAR_IF([mhd_cv_func_CPU_COUNT_S],["yes"], | ||
4116 | [ | ||
4117 | AC_CACHE_CHECK([whether CPU_COUNT_S() expects max CPU number as 'size' parameter],[mhd_cv_func_cpu_count_s_cpus], | ||
4118 | [ | ||
4119 | AS_VAR_IF([cross-compiling],["yes"],[mhd_cv_func_cpu_count_s_cpus="assuming no"], | ||
4120 | [ | ||
4121 | AC_LINK_IFELSE( | ||
4122 | [ | ||
4123 | AC_LANG_PROGRAM([[ | ||
4124 | #ifdef HAVE_SYS_TYPES_H | ||
4125 | #include <sys/types.h> | ||
4126 | #endif /* HAVE_SYS_TYPES_H */ | ||
4127 | #ifdef HAVE_SYS_PARAM_H | ||
4128 | #include <sys/param.h> | ||
4129 | #endif /* HAVE_SYS_PARAM_H */ | ||
4130 | #ifdef HAVE_SYS__CPUSET_H | ||
4131 | #include <sys/_cpuset.h> | ||
4132 | #endif /* HAVE_SYS_PARAM_H */ | ||
4133 | #ifdef HAVE_SYS_CPUSET_H | ||
4134 | #include <sys/cpuset.h> | ||
4135 | #endif /* HAVE_SYS_CPUSET_H */ | ||
4136 | #ifdef HAVE_STDDEF_H | ||
4137 | #include <stddef.h> | ||
4138 | #endif /* HAVE_STDDEF_H */ | ||
4139 | #ifdef HAVE_UNISTD_H | ||
4140 | #include <unistd.h> | ||
4141 | #endif /* HAVE_UNISTD_H */ | ||
4142 | #ifdef HAVE_SCHED_H | ||
4143 | #include <sched.h> | ||
4144 | #endif /* HAVE_SCHED_H */ | ||
4145 | #include <stdio.h> | ||
4146 | |||
4147 | #ifdef HAVE_SCHED_GETAFFINITY | ||
4148 | #define TEST_CPUSET_TYPE cpu_set_t | ||
4149 | #else /* ! HAVE_SCHED_GETAFFINITY */ | ||
4150 | #define TEST_CPUSET_TYPE cpuset_t | ||
4151 | #endif /* ! HAVE_SCHED_GETAFFINITY */ | ||
4152 | ]], | ||
4153 | [[ | ||
4154 | TEST_CPUSET_TYPE *p_testset; | ||
4155 | /* The size of the cpuset that is larger then the test cpuset (in CPUs) */ | ||
4156 | static const unsigned int testset_size_oversized_cpus = (8 * sizeof(long)) * 1024; | ||
4157 | const size_t testset_size_oversized_bytes = CPU_ALLOC_SIZE(testset_size_oversized_cpus); | ||
4158 | /* The size of the test cpuset in number of CPUs */ | ||
4159 | const unsigned int testset_size_cpus = (unsigned int) testset_size_oversized_bytes; | ||
4160 | /* The size of the test cpuset in bytes */ | ||
4161 | const size_t testset_size_bytes = CPU_ALLOC_SIZE(testset_size_cpus); | ||
4162 | /* The last one CPU in the test set */ | ||
4163 | const unsigned int test_cpu_num1 = testset_size_cpus - 1; | ||
4164 | /* The penultimate CPU in the test set */ | ||
4165 | const unsigned int test_cpu_num2 = testset_size_cpus - 2; | ||
4166 | /* The CPU numbers that should be cleared */ | ||
4167 | const unsigned int test_cpu_clear1 = testset_size_cpus - 3; | ||
4168 | const unsigned int test_cpu_clear2 = testset_size_cpus - 4; | ||
4169 | unsigned int count_res; | ||
4170 | int ret = 0; | ||
4171 | |||
4172 | /* Allocate oversize area to ensure that memory outside the buffer is not used */ | ||
4173 | p_testset = CPU_ALLOC(testset_size_oversized_cpus); | ||
4174 | if (! p_testset) | ||
4175 | { | ||
4176 | fprintf (stderr, "Error allocating memory.\n"); | ||
4177 | return 99; | ||
4178 | } | ||
4179 | /* Set the some CPU numbers and then clear them */ | ||
4180 | CPU_SET_S(test_cpu_clear1, testset_size_bytes, p_testset); | ||
4181 | CPU_SET_S(test_cpu_clear2, testset_size_bytes, p_testset); | ||
4182 | CPU_ZERO_S(testset_size_bytes, p_testset); | ||
4183 | /* Set two CPUs on */ | ||
4184 | CPU_SET_S(test_cpu_num1, testset_size_bytes, p_testset); | ||
4185 | CPU_SET_S(test_cpu_num2, testset_size_bytes, p_testset); | ||
4186 | count_res = (unsigned int) CPU_COUNT_S(testset_size_bytes, p_testset); | ||
4187 | if (0 == count_res) | ||
4188 | { | ||
4189 | fprintf (stderr, "Full cpuset cannot be read by CPU_COUNT_S() when using the number of bytes as the size parameter.\n"); | ||
4190 | /* Set the some CPU numbers and then clear them */ | ||
4191 | CPU_SET_S(test_cpu_clear1, testset_size_cpus, p_testset); | ||
4192 | CPU_SET_S(test_cpu_clear2, testset_size_cpus, p_testset); | ||
4193 | CPU_ZERO_S(testset_size_cpus, p_testset); | ||
4194 | /* Set two CPUs on */ | ||
4195 | CPU_SET_S(test_cpu_num1, testset_size_cpus, p_testset); | ||
4196 | CPU_SET_S(test_cpu_num2, testset_size_cpus, p_testset); | ||
4197 | count_res = (unsigned int) CPU_COUNT_S(testset_size_cpus, p_testset); | ||
4198 | if (2 == count_res) | ||
4199 | { | ||
4200 | fprintf (stderr, "Full cpuset is read by CPU_COUNT_S() only when using the maximum CPU number as the size parameter.\n"); | ||
4201 | ret = 3; | ||
4202 | } | ||
4203 | else | ||
4204 | { | ||
4205 | fprintf (stderr, "Wrong result returned by CPU_COUNT_S() when using the maximum CPU number as the size parameter.\n"); | ||
4206 | fprintf (stderr, "Number of 'enabled' CPUs: 2\n"); | ||
4207 | fprintf (stderr, "Number of counted CPUs: %u\n", count_res); | ||
4208 | fprintf (stderr, "CPU_COUNT_S() could be unreliable.\n"); | ||
4209 | ret = 70; | ||
4210 | } | ||
4211 | } | ||
4212 | else if (2 == count_res) | ||
4213 | { | ||
4214 | fprintf (stderr, "Full cpuset is read by CPU_COUNT_S() when using the number of bytes as the size parameter.\n"); | ||
4215 | } | ||
4216 | else | ||
4217 | { | ||
4218 | fprintf (stderr, "Wrong result returned by CPU_COUNT_S() when using the number of bytes as the size parameter.\n"); | ||
4219 | fprintf (stderr, "Number of 'enabled' CPUs: 2\n"); | ||
4220 | fprintf (stderr, "Number of counted CPUs: %u\n", count_res); | ||
4221 | fprintf (stderr, "CPU_COUNT_S() could be unreliable.\n"); | ||
4222 | ret = 71; | ||
4223 | } | ||
4224 | CPU_FREE(p_testset); | ||
4225 | if (0 != ret) | ||
4226 | return ret; | ||
4227 | ]] | ||
4228 | ) | ||
4229 | ], | ||
4230 | [ | ||
4231 | AM_RUN_LOG([./conftest$EXEEXT]) | ||
4232 | count_test_res=$? | ||
4233 | AS_IF([test $count_test_res -eq 0],[mhd_cv_func_cpu_count_s_cpus="no"], | ||
4234 | [test $count_test_res -eq 3],[mhd_cv_func_cpu_count_s_cpus="yes"], | ||
4235 | [ | ||
4236 | AC_MSG_WARN([Unexpected value returned by CPU_COUNT_S() test program. Please report to ${PACKAGE_BUGREPORT}]) | ||
4237 | mhd_cv_func_cpu_count_s_cpus="assuming no" | ||
4238 | ] | ||
4239 | ) | ||
4240 | ], | ||
4241 | [ | ||
4242 | AC_MSG_WARN([Cannot build CPU_COUNT_S() test program. Please report to ${PACKAGE_BUGREPORT}]) | ||
4243 | mhd_cv_func_cpu_count_s_cpus="assuming no" | ||
4244 | ] | ||
4245 | ) | ||
4246 | ] | ||
4247 | ) | ||
4248 | ] | ||
4249 | ) | ||
4250 | AS_VAR_IF([mhd_cv_func_cpu_count_s_cpus],["yes"], | ||
4251 | [AC_DEFINE([MHD_FUNC_CPU_COUNT_S_GETS_CPUS],[1], | ||
4252 | [Define to '1' if CPU_COUNT_S() function expects max CPU number as 'size' parameter]) | ||
4253 | ] | ||
4254 | ) | ||
4255 | ] | ||
4256 | ) | ||
3920 | ] | 4257 | ] |
3921 | ) | 4258 | ) |
3922 | 4259 | ||
diff --git a/src/include/mhd_options.h b/src/include/mhd_options.h index a7fadfae..faefd328 100644 --- a/src/include/mhd_options.h +++ b/src/include/mhd_options.h | |||
@@ -192,5 +192,81 @@ | |||
192 | #endif /* MHD_HAVE_MHD_FUNC_ */ | 192 | #endif /* MHD_HAVE_MHD_FUNC_ */ |
193 | #endif | 193 | #endif |
194 | 194 | ||
195 | /* Un-define some HAVE_DECL_* macro if they equal zero. | ||
196 | This should allow safely use #ifdef in the code. | ||
197 | Define HAS_DECL_* macros only if matching HAVE_DECL_* macro | ||
198 | has non-zero value. Unlike HAVE_DECL_*, macros HAS_DECL_* | ||
199 | cannot have zero value. */ | ||
200 | #ifdef HAVE_DECL__SC_NPROCESSORS_ONLN | ||
201 | # if 0 == HAVE_DECL__SC_NPROCESSORS_ONLN | ||
202 | # undef HAVE_DECL__SC_NPROCESSORS_ONLN | ||
203 | # else /* 0 != HAVE_DECL__SC_NPROCESSORS_ONLN */ | ||
204 | # define HAS_DECL__SC_NPROCESSORS_ONLN 1 | ||
205 | # endif /* 0 != HAVE_DECL__SC_NPROCESSORS_ONLN */ | ||
206 | #endif /* HAVE_DECL__SC_NPROCESSORS_ONLN */ | ||
207 | |||
208 | #ifdef HAVE_DECL__SC_NPROCESSORS_CONF | ||
209 | # if 0 == HAVE_DECL__SC_NPROCESSORS_CONF | ||
210 | # undef HAVE_DECL__SC_NPROCESSORS_CONF | ||
211 | # else /* 0 != HAVE_DECL__SC_NPROCESSORS_CONF */ | ||
212 | # define HAS_DECL__SC_NPROCESSORS_CONF 1 | ||
213 | # endif /* 0 != HAVE_DECL__SC_NPROCESSORS_CONF */ | ||
214 | #endif /* HAVE_DECL__SC_NPROCESSORS_CONF */ | ||
215 | |||
216 | #ifdef HAVE_DECL__SC_NPROC_ONLN | ||
217 | # if 0 == HAVE_DECL__SC_NPROC_ONLN | ||
218 | # undef HAVE_DECL__SC_NPROC_ONLN | ||
219 | # else /* 0 != HAVE_DECL__SC_NPROC_ONLN */ | ||
220 | # define HAS_DECL__SC_NPROC_ONLN 1 | ||
221 | # endif /* 0 != HAVE_DECL__SC_NPROC_ONLN */ | ||
222 | #endif /* HAVE_DECL__SC_NPROC_ONLN */ | ||
223 | |||
224 | #ifdef HAVE_DECL__SC_CRAY_NCPU | ||
225 | # if 0 == HAVE_DECL__SC_CRAY_NCPU | ||
226 | # undef HAVE_DECL__SC_CRAY_NCPU | ||
227 | # else /* 0 != HAVE_DECL__SC_CRAY_NCPU */ | ||
228 | # define HAS_DECL__SC_CRAY_NCPU 1 | ||
229 | # endif /* 0 != HAVE_DECL__SC_CRAY_NCPU */ | ||
230 | #endif /* HAVE_DECL__SC_CRAY_NCPU */ | ||
231 | |||
232 | #ifdef HAVE_DECL_CTL_HW | ||
233 | # if 0 == HAVE_DECL_CTL_HW | ||
234 | # undef HAVE_DECL_CTL_HW | ||
235 | # else /* 0 != HAVE_DECL_CTL_HW */ | ||
236 | # define HAS_DECL_CTL_HW 1 | ||
237 | # endif /* 0 != HAVE_DECL_CTL_HW */ | ||
238 | #endif /* HAVE_DECL_CTL_HW */ | ||
239 | |||
240 | #ifdef HAVE_DECL_HW_NCPUONLINE | ||
241 | # if 0 == HAVE_DECL_HW_NCPUONLINE | ||
242 | # undef HAVE_DECL_HW_NCPUONLINE | ||
243 | # else /* 0 != HAVE_DECL_HW_NCPUONLINE */ | ||
244 | # define HAS_DECL_HW_NCPUONLINE 1 | ||
245 | # endif /* 0 != HAVE_DECL_HW_NCPUONLINE */ | ||
246 | #endif /* HAVE_DECL_HW_NCPUONLINE */ | ||
247 | |||
248 | #ifdef HAVE_DECL_HW_AVAILCPU | ||
249 | # if 0 == HAVE_DECL_HW_AVAILCPU | ||
250 | # undef HAVE_DECL_HW_AVAILCPU | ||
251 | # else /* 0 != HAVE_DECL_HW_AVAILCPU */ | ||
252 | # define HAS_DECL_HW_AVAILCPU 1 | ||
253 | # endif /* 0 != HAVE_DECL_HW_AVAILCPU */ | ||
254 | #endif /* HAVE_DECL_HW_AVAILCPU */ | ||
255 | |||
256 | #ifdef HAVE_DECL_HW_NCPU | ||
257 | # if 0 == HAVE_DECL_HW_NCPU | ||
258 | # undef HAVE_DECL_HW_NCPU | ||
259 | # else /* 0 != HAVE_DECL_HW_NCPU */ | ||
260 | # define HAS_DECL_HW_NCPU 1 | ||
261 | # endif /* 0 != HAVE_DECL_HW_NCPU */ | ||
262 | #endif /* HAVE_DECL_HW_NCPU */ | ||
263 | |||
264 | #ifdef HAVE_DECL_CPU_SETSIZE | ||
265 | # if 0 == HAVE_DECL_CPU_SETSIZE | ||
266 | # undef HAVE_DECL_CPU_SETSIZE | ||
267 | # else /* 0 != HAVE_DECL_CPU_SETSIZE */ | ||
268 | # define HAS_DECL_CPU_SETSIZE 1 | ||
269 | # endif /* 0 != HAVE_DECL_CPU_SETSIZE */ | ||
270 | #endif /* HAVE_DECL_CPU_SETSIZE */ | ||
195 | 271 | ||
196 | #endif /* MHD_OPTIONS_H */ | 272 | #endif /* MHD_OPTIONS_H */ |
diff --git a/src/tools/Makefile.am b/src/tools/Makefile.am index d9064969..da776afe 100644 --- a/src/tools/Makefile.am +++ b/src/tools/Makefile.am | |||
@@ -36,4 +36,5 @@ endif | |||
36 | 36 | ||
37 | 37 | ||
38 | perf_replies_SOURCES = \ | 38 | perf_replies_SOURCES = \ |
39 | perf_replies.c mhd_tool_str_to_uint.h | 39 | perf_replies.c mhd_tool_str_to_uint.h \ |
40 | mhd_tool_get_cpu_count.h mhd_tool_get_cpu_count.c | ||
diff --git a/src/tools/mhd_tool_get_cpu_count.c b/src/tools/mhd_tool_get_cpu_count.c new file mode 100644 index 00000000..81badf28 --- /dev/null +++ b/src/tools/mhd_tool_get_cpu_count.c | |||
@@ -0,0 +1,658 @@ | |||
1 | /* | ||
2 | This file is part of GNU libmicrohttpd | ||
3 | Copyright (C) 2023 Evgeny Grin (Karlson2k) | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | |||
20 | /** | ||
21 | * @file tools/mhd_tool_get_cpu_count.c | ||
22 | * @brief Implementation of functions to detect the number of available | ||
23 | * CPU cores. | ||
24 | * @author Karlson2k (Evgeny Grin) | ||
25 | */ | ||
26 | |||
27 | #include "mhd_options.h" | ||
28 | #include "mhd_tool_get_cpu_count.h" | ||
29 | #ifdef HAVE_SYS_TYPES_H | ||
30 | # include <sys/types.h> | ||
31 | #endif /* HAVE_SYS_TYPES_H */ | ||
32 | #ifdef HAVE_SYS_PARAM_H | ||
33 | # include <sys/param.h> | ||
34 | #endif /* HAVE_SYS_PARAM_H */ | ||
35 | #ifdef HAVE_SYS__CPUSET_H | ||
36 | # include <sys/_cpuset.h> | ||
37 | #endif /* HAVE_SYS_PARAM_H */ | ||
38 | #ifdef HAVE_STDDEF_H | ||
39 | # include <stddef.h> | ||
40 | #endif /* HAVE_STDDEF_H */ | ||
41 | #ifdef HAVE_STRING_H | ||
42 | # include <string.h> | ||
43 | #endif /* HAVE_STRING_H */ | ||
44 | #ifdef HAVE_SYS_SYSCTL_H | ||
45 | # include <sys/sysctl.h> | ||
46 | #endif /* HAVE_SYS_SYSCTL_H */ | ||
47 | #ifdef HAVE_FEATURES_H | ||
48 | # include <features.h> | ||
49 | #endif /* HAVE_FEATURES_H */ | ||
50 | #ifdef HAVE_UNISTD_H | ||
51 | # include <unistd.h> | ||
52 | #endif /* HAVE_UNISTD_H */ | ||
53 | #ifdef HAVE_VXCPULIB_H | ||
54 | # include <vxCpuLib.h> | ||
55 | #endif | ||
56 | #ifdef HAVE_WINDOWS_H | ||
57 | # ifndef WIN32_LEAN_AND_MEAN | ||
58 | # define WIN32_LEAN_AND_MEAN 1 | ||
59 | # endif /* ! WIN32_LEAN_AND_MEAN */ | ||
60 | # include <windows.h> | ||
61 | # ifndef ALL_PROCESSOR_GROUPS | ||
62 | # define ALL_PROCESSOR_GROUPS 0xFFFFu | ||
63 | # endif /* ALL_PROCESSOR_GROUPS */ | ||
64 | #elif defined(_WIN32) && ! defined (__CYGWIN__) | ||
65 | # error Windows headers are required for Windows build | ||
66 | #endif /* HAVE_WINDOWS_H */ | ||
67 | #ifdef HAVE_SCHED_H | ||
68 | # include <sched.h> | ||
69 | #endif /* HAVE_SCHED_H */ | ||
70 | #ifdef HAVE_SYS_CPUSET_H | ||
71 | # include <sys/cpuset.h> | ||
72 | #endif /* HAVE_SYS_CPUSET_H */ | ||
73 | |||
74 | #if ! defined(HAS_DECL_CPU_SETSIZE) && ! defined(CPU_SETSIZE) | ||
75 | # define CPU_SETSIZE (1024) | ||
76 | # define CPU_SETSIZE_SAFE (64) | ||
77 | #else /* HAS_DECL_CPU_SETSIZE || CPU_SETSIZE */ | ||
78 | # define CPU_SETSIZE_SAFE CPU_SETSIZE | ||
79 | #endif /* HAS_DECL_CPU_SETSIZE || CPU_SETSIZE */ | ||
80 | |||
81 | /* Check and fix possible missing macros */ | ||
82 | #if ! defined(HAS_DECL_CTL_HW) && defined(CTL_HW) | ||
83 | # define HAS_DECL_CTL_HW 1 | ||
84 | #endif /* ! HAS_DECL_CTL_HW && CTL_HW */ | ||
85 | |||
86 | #if ! defined(HAS_DECL_HW_NCPUONLINE) && defined(HW_NCPUONLINE) | ||
87 | # define HAS_DECL_HW_NCPUONLINE 1 | ||
88 | #endif /* ! HAS_DECL_HW_NCPUONLINE && HW_NCPUONLINE */ | ||
89 | |||
90 | #if ! defined(HAS_DECL_HW_AVAILCPU) && defined(HW_AVAILCPU) | ||
91 | # define HAS_DECL_HW_AVAILCPU 1 | ||
92 | #endif /* ! HAS_DECL_HW_AVAILCPU && HW_AVAILCPU */ | ||
93 | |||
94 | #if ! defined(HAS_DECL_HW_NCPU) && defined(HW_NCPU) | ||
95 | # define HAS_DECL_HW_NCPU 1 | ||
96 | #endif /* ! HAS_DECL_HW_NCPU && HW_NCPU */ | ||
97 | |||
98 | #if ! defined(HAS_DECL__SC_NPROCESSORS_ONLN) && defined(_SC_NPROCESSORS_ONLN) | ||
99 | # define HAS_DECL__SC_NPROCESSORS_ONLN 1 | ||
100 | #endif /* ! HAS_DECL__SC_NPROCESSORS_ONLN && _SC_NPROCESSORS_ONLN */ | ||
101 | |||
102 | #if ! defined(HAS_DECL__SC_NPROC_ONLN) && defined(_SC_NPROC_ONLN) | ||
103 | # define HAS_DECL__SC_NPROC_ONLN 1 | ||
104 | #endif /* ! HAS_DECL__SC_NPROC_ONLN && _SC_NPROC_ONLN */ | ||
105 | |||
106 | #if ! defined(HAS_DECL__SC_CRAY_NCPU) && defined(_SC_CRAY_NCPU) | ||
107 | # define HAS_DECL__SC_CRAY_NCPU 1 | ||
108 | #endif /* ! HAS_DECL__SC_CRAY_NCPU && _SC_CRAY_NCPU */ | ||
109 | |||
110 | #if ! defined(HAS_DECL__SC_NPROCESSORS_CONF) && defined(_SC_NPROCESSORS_CONF) | ||
111 | # define HAS_DECL__SC_NPROCESSORS_CONF 1 | ||
112 | #endif /* ! HAVE_DECL__SC_NPROCESSORS_CONF && _SC_NPROCESSORS_CONF */ | ||
113 | |||
114 | /* Forward declarations */ | ||
115 | |||
116 | static int | ||
117 | mhd_tool_get_sys_cpu_count_sysctl_ (void); | ||
118 | |||
119 | /** | ||
120 | * Detect the number of logical CPU cores available for the process by | ||
121 | * sched_getaffinity() (and related) function. | ||
122 | * @return the number of detected logical CPU cores or | ||
123 | * -1 if failed to detect (or this function unavailable). | ||
124 | */ | ||
125 | static int | ||
126 | mhd_tool_get_proc_cpu_count_sched_getaffinity_ (void) | ||
127 | { | ||
128 | int ret = -1; | ||
129 | #if defined(HAVE_SCHED_GETAFFINITY) && defined(HAVE_GETPID) | ||
130 | /* Glibc style */ | ||
131 | if (0 >= ret) | ||
132 | { | ||
133 | cpu_set_t cur_set; | ||
134 | if (0 == sched_getaffinity (getpid (), sizeof(cur_set), &cur_set)) | ||
135 | { | ||
136 | #ifdef HAVE_CPU_COUNT | ||
137 | ret = CPU_COUNT (&cur_set); | ||
138 | #else /* ! HAVE_CPU_COUNT */ | ||
139 | unsigned int i; | ||
140 | ret = 0; | ||
141 | for (i = 0; i < CPU_SETSIZE_SAFE; ++i) | ||
142 | { | ||
143 | if (CPU_ISSET (i, &cur_set)) | ||
144 | ++ret; | ||
145 | } | ||
146 | if (0 == ret) | ||
147 | ret = -1; | ||
148 | #endif /* ! HAVE_CPU_COUNT */ | ||
149 | } | ||
150 | } | ||
151 | #ifdef HAVE_CPU_COUNT_S | ||
152 | if (0 >= ret) | ||
153 | { | ||
154 | /* Use 256 times larger size than size for default maximum CPU number. | ||
155 | Hopefully it would be enough even for exotic situations. */ | ||
156 | static const unsigned int set_size_cpus = 256 * CPU_SETSIZE; | ||
157 | const size_t set_size_bytes = CPU_ALLOC_SIZE (set_size_cpus); | ||
158 | cpu_set_t *p_set; | ||
159 | |||
160 | p_set = CPU_ALLOC (set_size_cpus); | ||
161 | if (NULL != p_set) | ||
162 | { | ||
163 | if (0 == sched_getaffinity (getpid (), set_size_bytes, p_set)) | ||
164 | { | ||
165 | #ifndef MHD_FUNC_CPU_COUNT_S_GETS_CPUS | ||
166 | ret = CPU_COUNT_S (set_size_bytes, p_set); | ||
167 | #else /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */ | ||
168 | ret = CPU_COUNT_S (set_size_cpus, p_set); | ||
169 | #endif /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */ | ||
170 | } | ||
171 | CPU_FREE (p_set); | ||
172 | } | ||
173 | } | ||
174 | #endif /* HAVE_CPU_COUNT_S */ | ||
175 | #endif /* HAVE_SCHED_GETAFFINITY && HAVE_GETPID */ | ||
176 | if (0 >= ret) | ||
177 | return -1; | ||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | |||
182 | /** | ||
183 | * Detect the number of logical CPU cores available for the process by | ||
184 | * cpuset_getaffinity() function. | ||
185 | * @return the number of detected logical CPU cores or | ||
186 | * -1 if failed to detect (or this function unavailable). | ||
187 | */ | ||
188 | static int | ||
189 | mhd_tool_get_proc_cpu_count_cpuset_getaffinity_ (void) | ||
190 | { | ||
191 | int ret = -1; | ||
192 | #if defined(HAVE_CPUSET_GETAFFINITY) | ||
193 | /* FreeBSD style */ | ||
194 | if (0 >= ret) | ||
195 | { | ||
196 | cpuset_t cur_mask; | ||
197 | /* The should get "anonymous" mask/set. The anonymous mask is always | ||
198 | a subset of the assigned set (which is a subset of the root set). */ | ||
199 | if (0 == cpuset_getaffinity (CPU_LEVEL_WHICH, CPU_WHICH_PID, (id_t) -1, | ||
200 | sizeof(cur_mask), &cur_mask)) | ||
201 | { | ||
202 | #ifdef HAVE_CPU_COUNT | ||
203 | ret = CPU_COUNT (&cur_mask); | ||
204 | #else /* ! HAVE_CPU_COUNT */ | ||
205 | unsigned int i; | ||
206 | ret = 0; | ||
207 | for (i = 0; i < CPU_SETSIZE_SAFE; ++i) | ||
208 | { | ||
209 | if (CPU_ISSET (i, &cur_mask)) | ||
210 | ++ret; | ||
211 | } | ||
212 | if (0 == ret) | ||
213 | ret = -1; | ||
214 | #endif /* ! HAVE_CPU_COUNT */ | ||
215 | } | ||
216 | } | ||
217 | #ifdef HAVE_CPU_COUNT_S | ||
218 | if (0 >= ret) | ||
219 | { | ||
220 | /* Use 256 times larger size than size for default maximum CPU number. | ||
221 | Hopefully it would be enough even for exotic situations. */ | ||
222 | static const unsigned int mask_size_cpus = 256 * CPU_SETSIZE; | ||
223 | const size_t mask_size_bytes = CPU_ALLOC_SIZE (mask_size_cpus); | ||
224 | cpuset_t *p_mask; | ||
225 | |||
226 | p_mask = CPU_ALLOC (mask_size_cpus); | ||
227 | if (NULL != p_mask) | ||
228 | { | ||
229 | if (0 == cpuset_getaffinity (CPU_LEVEL_WHICH, CPU_WHICH_PID, (id_t) -1, | ||
230 | mask_size_bytes, p_mask)) | ||
231 | { | ||
232 | #ifndef MHD_FUNC_CPU_COUNT_S_GETS_CPUS | ||
233 | ret = CPU_COUNT_S (mask_size_bytes, p_mask); | ||
234 | #else /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */ | ||
235 | ret = CPU_COUNT_S (mask_size_cpus, p_mask); | ||
236 | #endif /* MHD_FUNC_CPU_COUNT_S_GETS_CPUS */ | ||
237 | } | ||
238 | CPU_FREE (p_mask); | ||
239 | } | ||
240 | } | ||
241 | #endif /* HAVE_CPU_COUNT_S */ | ||
242 | #endif /* HAVE_CPUSET_GETAFFINITY */ | ||
243 | if (0 >= ret) | ||
244 | return -1; | ||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | |||
249 | /** | ||
250 | * Detect the number of logical CPU cores available for the process by | ||
251 | * sched_getaffinity_np() (and related) function. | ||
252 | * @return the number of detected logical CPU cores or | ||
253 | * -1 if failed to detect (or this function unavailable). | ||
254 | */ | ||
255 | static int | ||
256 | mhd_tool_get_proc_cpu_count_sched_getaffinity_np_ (void) | ||
257 | { | ||
258 | int ret = -1; | ||
259 | #if defined(HAVE_SCHED_GETAFFINITY_NP) && defined(HAVE_GETPID) | ||
260 | /* NetBSD style */ | ||
261 | cpuset_t *cpuset_ptr; | ||
262 | cpuset_ptr = cpuset_create (); | ||
263 | if (NULL != cpuset_ptr) | ||
264 | { | ||
265 | if (0 == sched_getaffinity_np (getpid (), cpuset_size (cpuset_ptr), | ||
266 | cpuset_ptr)) | ||
267 | { | ||
268 | cpuid_t cpu_num; | ||
269 | #if defined(HAVE_SYSCONF) && defined(HAVE_DECL__SC_NPROCESSORS_CONF) | ||
270 | unsigned int max_num = 0; | ||
271 | long sc_value = -1; | ||
272 | sc_value = sysconf (_SC_NPROCESSORS_ONLN); | ||
273 | if (0 < sc_value) | ||
274 | max_num = (unsigned int) sc_value; | ||
275 | if (0 < max_num) | ||
276 | { | ||
277 | ret = 0; | ||
278 | for (cpu_num = 0; cpu_num < max_num; ++cpu_num) | ||
279 | if (0 < cpuset_isset (cpu_num, cpuset_ptr)) | ||
280 | ++ret; | ||
281 | } | ||
282 | else /* Combined with the next 'if' */ | ||
283 | #endif /* HAVE_SYSCONF && HAVE_DECL__SC_NPROCESSORS_CONF */ | ||
284 | if (1) | ||
285 | { | ||
286 | int res; | ||
287 | cpu_num = 0; | ||
288 | ret = 0; | ||
289 | do | ||
290 | { | ||
291 | res = cpuset_isset (cpu_num++, cpuset_ptr); | ||
292 | if (0 < res) | ||
293 | ++ret; | ||
294 | } while (0 <= res); | ||
295 | } | ||
296 | #ifdef __NetBSD__ | ||
297 | if (0 == ret) | ||
298 | { | ||
299 | /* On NetBSD "unset" affinity (exactly zero CPUs) means | ||
300 | "all CPUs are available". */ | ||
301 | ret = mhd_tool_get_sys_cpu_count_sysctl_ (); | ||
302 | } | ||
303 | #endif /* __NetBSD__ */ | ||
304 | } | ||
305 | cpuset_destroy (cpuset_ptr); | ||
306 | } | ||
307 | #endif /* HAVE_SCHED_GETAFFINITY_NP && HAVE_GETPID */ | ||
308 | if (0 >= ret) | ||
309 | return -1; | ||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | |||
314 | /** | ||
315 | * Detect the number of logical CPU cores available for the process. | ||
316 | * The number of cores available for this process could be different from | ||
317 | * value of cores available on the system. The OS may have limit on number | ||
318 | * assigned/allowed cores for single process and process may have limited | ||
319 | * CPU affinity. | ||
320 | * @return the number of logical CPU cores available for the process or | ||
321 | * -1 if failed to detect | ||
322 | */ | ||
323 | int | ||
324 | mhd_tool_get_proc_cpu_count (void) | ||
325 | { | ||
326 | int res; | ||
327 | |||
328 | #if defined(__linux__) || defined(__GLIBC__) | ||
329 | /* On Linux kernel try first 'sched_getaffinity()' as it should be | ||
330 | the native API. | ||
331 | Also try it first on other kernels if Glibc is used. */ | ||
332 | res = mhd_tool_get_proc_cpu_count_sched_getaffinity_ (); | ||
333 | if (0 < res) | ||
334 | return res; | ||
335 | |||
336 | res = mhd_tool_get_proc_cpu_count_cpuset_getaffinity_ (); | ||
337 | if (0 < res) | ||
338 | return res; | ||
339 | #else /* ! __linux__ && ! __GLIBC__ */ | ||
340 | /* On non-Linux kernels 'cpuset_getaffinity()' could be the native API, | ||
341 | while 'sched_getaffinity()' could be implemented in compatibility layer. */ | ||
342 | res = mhd_tool_get_proc_cpu_count_cpuset_getaffinity_ (); | ||
343 | if (0 < res) | ||
344 | return res; | ||
345 | |||
346 | res = mhd_tool_get_proc_cpu_count_sched_getaffinity_ (); | ||
347 | if (0 < res) | ||
348 | return res; | ||
349 | #endif /* ! __linux__ && ! __GLIBC__ */ | ||
350 | |||
351 | res = mhd_tool_get_proc_cpu_count_sched_getaffinity_np_ (); | ||
352 | if (0 < res) | ||
353 | return res; | ||
354 | |||
355 | return -1; | ||
356 | } | ||
357 | |||
358 | |||
359 | /** | ||
360 | * Detect the number of processors by special API functions | ||
361 | * @return number of processors as returned by special API functions or | ||
362 | * -1 in case of error or special API functions unavailable | ||
363 | */ | ||
364 | static int | ||
365 | mhd_tool_get_sys_cpu_count_special_api_ (void) | ||
366 | { | ||
367 | int ret = -1; | ||
368 | #ifdef HAVE_PSTAT_GETDYNAMIC | ||
369 | if (0 >= ret) | ||
370 | { | ||
371 | /* HP-UX things */ | ||
372 | struct pst_dynamic psd_data; | ||
373 | memset ((void *) &psd_data, 0, sizeof(psd_data)); | ||
374 | if (1 == pstat_getdynamic (&psd_data, sizeof(psd_data), (size_t) 1, 0)) | ||
375 | { | ||
376 | if (0 < psd_data.psd_proc_cnt) | ||
377 | ret = (int) psd_data.psd_proc_cnt; | ||
378 | } | ||
379 | } | ||
380 | #endif /* HAVE_PSTAT_GETDYNAMIC */ | ||
381 | #ifdef HAVE_VXCPUENABLEDGET | ||
382 | if (0 >= ret) | ||
383 | { | ||
384 | /* VxWorks */ | ||
385 | cpuset_t enb_set; | ||
386 | enb_set = vxCpuEnabledGet (); | ||
387 | /* Count set bits */ | ||
388 | for (ret = 0; 0 != enb_set; enb_set &= enb_set - 1) | ||
389 | ++ret; | ||
390 | } | ||
391 | #endif /* HAVE_VXCPUENABLEDGET */ | ||
392 | #if defined(_WIN32) && ! defined (__CYGWIN__) | ||
393 | if (0 >= ret) | ||
394 | { | ||
395 | /* Native W32 */ | ||
396 | HMODULE k32hndl; | ||
397 | k32hndl = GetModuleHandleA ("kernel32.dll"); | ||
398 | if (NULL != k32hndl) | ||
399 | { | ||
400 | typedef DWORD (WINAPI *GAPC_PTR)(WORD GroupNumber); | ||
401 | GAPC_PTR ptrGetActiveProcessorCount; | ||
402 | /* Available on W7 or later */ | ||
403 | ptrGetActiveProcessorCount = | ||
404 | (GAPC_PTR) (void *) GetProcAddress (k32hndl, "GetActiveProcessorCount"); | ||
405 | if (NULL != ptrGetActiveProcessorCount) | ||
406 | { | ||
407 | DWORD res; | ||
408 | res = ptrGetActiveProcessorCount (ALL_PROCESSOR_GROUPS); | ||
409 | ret = (int) res; | ||
410 | if (res != (DWORD) ret) | ||
411 | ret = -1; /* Overflow */ | ||
412 | } | ||
413 | } | ||
414 | if ((0 >= ret) && (NULL != k32hndl)) | ||
415 | { | ||
416 | typedef void (WINAPI *GNSI_PTR)(SYSTEM_INFO *pSysInfo); | ||
417 | GNSI_PTR ptrGetNativeSystemInfo; | ||
418 | /* May give incorrect (low) result on versions from W7 to W11 | ||
419 | when more then 64 CPUs are available */ | ||
420 | ptrGetNativeSystemInfo = | ||
421 | (GNSI_PTR) (void *) GetProcAddress (k32hndl, "GetNativeSystemInfo"); | ||
422 | if (NULL != ptrGetNativeSystemInfo) | ||
423 | { | ||
424 | SYSTEM_INFO sysInfo; | ||
425 | |||
426 | memset ((void *) &sysInfo, 0, sizeof(sysInfo)); | ||
427 | ptrGetNativeSystemInfo (&sysInfo); | ||
428 | ret = (int) sysInfo.dwNumberOfProcessors; | ||
429 | if (sysInfo.dwNumberOfProcessors != (DWORD) ret) | ||
430 | ret = -1; /* Overflow */ | ||
431 | } | ||
432 | } | ||
433 | } | ||
434 | if (0 >= ret) | ||
435 | { | ||
436 | /* May give incorrect (low) result on versions from W7 to W11 | ||
437 | when more then 64 CPUs are available */ | ||
438 | SYSTEM_INFO sysInfo; | ||
439 | memset ((void *) &sysInfo, 0, sizeof(sysInfo)); | ||
440 | GetSystemInfo (&sysInfo); | ||
441 | ret = (int) sysInfo.dwNumberOfProcessors; | ||
442 | if (sysInfo.dwNumberOfProcessors != (DWORD) ret) | ||
443 | ret = -1; /* Overflow */ | ||
444 | } | ||
445 | #endif /* _WIN32 && ! __CYGWIN__ */ | ||
446 | if (0 >= ret) | ||
447 | return -1; | ||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | |||
452 | /** | ||
453 | * Detect the number of processors by sysctl*() functions | ||
454 | * @return number of processors as returned by 'sysctl*' functions or | ||
455 | * -1 in case of error or the number cannot be detected | ||
456 | * by these functions | ||
457 | */ | ||
458 | static int | ||
459 | mhd_tool_get_sys_cpu_count_sysctl_ (void) | ||
460 | { | ||
461 | int ret = -1; | ||
462 | /* Do not use sysctl() function on GNU/Linux even if | ||
463 | sysctl() is available */ | ||
464 | #ifndef __linux__ | ||
465 | #ifdef HAVE_SYSCTLBYNAME | ||
466 | if (0 >= ret) | ||
467 | { | ||
468 | size_t value_size = sizeof(ret); | ||
469 | /* Darwin: The number of available logical CPUs */ | ||
470 | if ((0 != sysctlbyname ("hw.logicalcpu", &ret, &value_size, | ||
471 | NULL, 0)) | ||
472 | || (sizeof(ret) != value_size)) | ||
473 | ret = -1; | ||
474 | } | ||
475 | if (0 >= ret) | ||
476 | { | ||
477 | size_t value_size = sizeof(ret); | ||
478 | /* FreeBSD: The number of online CPUs */ | ||
479 | if ((0 != sysctlbyname ("kern.smp.cpus", &ret, &value_size, | ||
480 | NULL, 0)) | ||
481 | || (sizeof(ret) != value_size)) | ||
482 | ret = -1; | ||
483 | } | ||
484 | if (0 >= ret) | ||
485 | { | ||
486 | size_t value_size = sizeof(ret); | ||
487 | /* Darwin: The current number of CPUs available to run threads */ | ||
488 | if ((0 != sysctlbyname ("hw.activecpu", &ret, &value_size, | ||
489 | NULL, 0)) | ||
490 | || (sizeof(ret) != value_size)) | ||
491 | ret = -1; | ||
492 | } | ||
493 | if (0 >= ret) | ||
494 | { | ||
495 | size_t value_size = sizeof(ret); | ||
496 | /* OpenBSD, NetBSD: The number of online CPUs */ | ||
497 | if ((0 != sysctlbyname ("hw.ncpuonline", &ret, &value_size, | ||
498 | NULL, 0)) | ||
499 | || (sizeof(ret) != value_size)) | ||
500 | ret = -1; | ||
501 | } | ||
502 | if (0 >= ret) | ||
503 | { | ||
504 | size_t value_size = sizeof(ret); | ||
505 | /* Darwin: The old/alternative name for "hw.activecpu" */ | ||
506 | if ((0 != sysctlbyname ("hw.availcpu", &ret, &value_size, | ||
507 | NULL, 0)) | ||
508 | || (sizeof(ret) != value_size)) | ||
509 | ret = -1; | ||
510 | } | ||
511 | #endif /* HAVE_SYSCTLBYNAME */ | ||
512 | #if defined(HAVE_SYSCTL) && \ | ||
513 | defined(HAS_DECL_CTL_HW) && \ | ||
514 | defined(HAS_DECL_HW_NCPUONLINE) | ||
515 | if (0 >= ret) | ||
516 | { | ||
517 | /* OpenBSD, NetBSD: The number of online CPUs */ | ||
518 | int mib[2] = { CTL_HW, HW_NCPUONLINE }; | ||
519 | size_t value_size = sizeof(ret); | ||
520 | if ((0 != sysctl (mib, 2, &ret, &value_size, NULL, 0)) | ||
521 | || (sizeof(ret) != value_size)) | ||
522 | ret = -1; | ||
523 | } | ||
524 | #endif /* HAVE_SYSCTL && HAS_DECL_CTL_HW && HAS_DECL_HW_NCPUONLINE */ | ||
525 | #if defined(HAVE_SYSCTL) && \ | ||
526 | defined(HAS_DECL_CTL_HW) && \ | ||
527 | defined(HAS_DECL_HW_AVAILCPU) | ||
528 | if (0 >= ret) | ||
529 | { | ||
530 | /* Darwin: The MIB name for "hw.activecpu" */ | ||
531 | int mib[2] = { CTL_HW, HW_AVAILCPU }; | ||
532 | size_t value_size = sizeof(ret); | ||
533 | if ((0 != sysctl (mib, 2, &ret, &value_size, NULL, 0)) | ||
534 | || (sizeof(ret) != value_size)) | ||
535 | ret = -1; | ||
536 | } | ||
537 | #endif /* HAVE_SYSCTL && HAS_DECL_CTL_HW && HAS_DECL_HW_AVAILCPU */ | ||
538 | #ifdef HAVE_SYSCTLBYNAME | ||
539 | if (0 >= ret) | ||
540 | { | ||
541 | size_t value_size = sizeof(ret); | ||
542 | /* FreeBSD, OpenBSD, NetBSD, Darwin (and others?): The number of CPUs */ | ||
543 | if ((0 != sysctlbyname ("hw.ncpu", &ret, &value_size, | ||
544 | NULL, 0)) | ||
545 | || (sizeof(ret) != value_size)) | ||
546 | ret = -1; | ||
547 | } | ||
548 | #endif /* HAVE_SYSCTLBYNAME */ | ||
549 | #if defined(HAVE_SYSCTL) && \ | ||
550 | defined(HAS_DECL_CTL_HW) && \ | ||
551 | defined(HAS_DECL_HW_NCPU) | ||
552 | if (0 >= ret) | ||
553 | { | ||
554 | /* FreeBSD, OpenBSD, NetBSD, Darwin (and others?): The number of CPUs */ | ||
555 | int mib[2] = { CTL_HW, HW_NCPU }; | ||
556 | size_t value_size = sizeof(ret); | ||
557 | if ((0 != sysctl (mib, 2, &ret, &value_size, NULL, 0)) | ||
558 | || (sizeof(ret) != value_size)) | ||
559 | ret = -1; | ||
560 | } | ||
561 | #endif /* HAVE_SYSCTL && HAS_DECL_CTL_HW && HAS_DECL_HW_NCPU */ | ||
562 | #endif /* ! __linux__ */ | ||
563 | if (0 >= ret) | ||
564 | return -1; | ||
565 | return ret; | ||
566 | } | ||
567 | |||
568 | |||
569 | /** | ||
570 | * Detect the number of processors by sysconf() function | ||
571 | * @return number of processors as returned by 'sysconf' function or | ||
572 | * -1 in case of error or 'sysconf' unavailable | ||
573 | */ | ||
574 | static int | ||
575 | mhd_tool_get_sys_cpu_count_sysconf_ (void) | ||
576 | { | ||
577 | int ret = -1; | ||
578 | #if defined(HAVE_SYSCONF) && \ | ||
579 | (defined(HAS_DECL__SC_NPROCESSORS_ONLN) || \ | ||
580 | defined(HAS_DECL__SC_NPROC_ONLN) || \ | ||
581 | defined(HAS_DECL__SC_CRAY_NCPU)) | ||
582 | long value = -1; | ||
583 | #ifdef HAS_DECL__SC_NPROCESSORS_ONLN | ||
584 | if (0 >= value) | ||
585 | value = sysconf (_SC_NPROCESSORS_ONLN); | ||
586 | #endif /* HAS_DECL__SC_NPROCESSORS_ONLN */ | ||
587 | #ifdef HAS_DECL__SC_NPROC_ONLN | ||
588 | if (0 >= value) | ||
589 | value = sysconf (_SC_NPROC_ONLN); | ||
590 | #endif /* HAS_DECL__SC_NPROC_ONLN */ | ||
591 | #ifdef HAS_DECL__SC_CRAY_NCPU | ||
592 | if (0 >= value) | ||
593 | value = sysconf (_SC_CRAY_NCPU); | ||
594 | #endif /* HAS_DECL__SC_CRAY_NCPU */ | ||
595 | if (0 >= value) | ||
596 | return -1; | ||
597 | ret = (int) value; | ||
598 | if ((long) ret != value) | ||
599 | return -1; /* Overflow */ | ||
600 | #endif /* HAVE_SYSCONF && | ||
601 | (HAS_DECL__SC_NPROCESSORS_ONLN || HAS_DECL__SC_NPROC_ONLN || | ||
602 | HAS_DECL__SC_CRAY_NCPU) */ | ||
603 | return ret; | ||
604 | } | ||
605 | |||
606 | |||
607 | /** | ||
608 | * Try to detect the number of logical CPU cores available for the system. | ||
609 | * The number of available logical CPU cores could be changed any time due to | ||
610 | * CPU hotplug. | ||
611 | * @return the number of logical CPU cores available, | ||
612 | * -1 if failed to detect. | ||
613 | */ | ||
614 | int | ||
615 | mhd_tool_get_system_cpu_count (void) | ||
616 | { | ||
617 | int res; | ||
618 | |||
619 | /* Try specialised APIs first */ | ||
620 | res = mhd_tool_get_sys_cpu_count_special_api_ (); | ||
621 | if (0 < res) | ||
622 | return res; | ||
623 | |||
624 | /* Try sysctl*(). This is typically a direct interface to | ||
625 | kernel values. */ | ||
626 | res = mhd_tool_get_sys_cpu_count_sysctl_ (); | ||
627 | if (0 < res) | ||
628 | return res; | ||
629 | |||
630 | /* Try sysconf() as the last resort as this is a generic interface | ||
631 | which can be implemented by parsing system files. */ | ||
632 | res = mhd_tool_get_sys_cpu_count_sysconf_ (); | ||
633 | #if ! defined(__linux__) && ! defined(__GLIBC__) | ||
634 | if (0 < res) | ||
635 | return res; | ||
636 | #else /* __linux__ || __GLIBC__ */ | ||
637 | if (2 < res) | ||
638 | return res; | ||
639 | if (0 < res) | ||
640 | { | ||
641 | /* '1' or '2' could a be fallback number. | ||
642 | * See get_nprocs_fallback() in glibc | ||
643 | sysdeps/unix/sysv/linux/getsysstats.c */ | ||
644 | |||
645 | int proc_cpu_count; | ||
646 | |||
647 | proc_cpu_count = mhd_tool_get_proc_cpu_count (); | ||
648 | if ((0 < proc_cpu_count) && (proc_cpu_count <= res)) | ||
649 | { | ||
650 | /* The detected number of CPUs available for the process | ||
651 | is 1 or 2 and fits detected number of system CPUS. | ||
652 | Assume detected number is correct. */ | ||
653 | return res; | ||
654 | } | ||
655 | } | ||
656 | #endif /* __linux__ || __GLIBC__ */ | ||
657 | return -1; /* Cannot detect */ | ||
658 | } | ||
diff --git a/src/tools/mhd_tool_get_cpu_count.h b/src/tools/mhd_tool_get_cpu_count.h new file mode 100644 index 00000000..84091e0f --- /dev/null +++ b/src/tools/mhd_tool_get_cpu_count.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | This file is part of GNU libmicrohttpd | ||
3 | Copyright (C) 2023 Evgeny Grin (Karlson2k) | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. | ||
9 | |||
10 | This library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | |||
20 | /** | ||
21 | * @file tools/mhd_tool_get_cpu_count.h | ||
22 | * @brief Declaration of functions to detect the number of available | ||
23 | * CPU cores. | ||
24 | * @author Karlson2k (Evgeny Grin) | ||
25 | */ | ||
26 | |||
27 | |||
28 | #ifndef SRC_TOOLS_MHD_TOOL_GET_CPU_COUNT_H_ | ||
29 | #define SRC_TOOLS_MHD_TOOL_GET_CPU_COUNT_H_ 1 | ||
30 | |||
31 | |||
32 | /** | ||
33 | * Detect the number of logical CPU cores available for the process. | ||
34 | * The number of cores available for this process could be different from | ||
35 | * value of cores available on the system. The OS may have limit on number | ||
36 | * assigned/allowed cores for single process and process may have limited | ||
37 | * CPU affinity. | ||
38 | * @return the number of logical CPU cores available for the process or | ||
39 | * -1 if failed to detect | ||
40 | */ | ||
41 | int | ||
42 | mhd_tool_get_proc_cpu_count (void); | ||
43 | |||
44 | |||
45 | /** | ||
46 | * Try to detect the number of logical CPU cores available for the system. | ||
47 | * The number of available logical CPU cores could be changed any time due to | ||
48 | * CPU hotplug. | ||
49 | * @return the number of logical CPU cores available, | ||
50 | * -1 if failed to detect. | ||
51 | */ | ||
52 | int | ||
53 | mhd_tool_get_system_cpu_count (void); | ||
54 | |||
55 | #endif /* SRC_TOOLS_MHD_TOOL_GET_CPU_COUNT_H_ */ | ||
diff --git a/src/tools/perf_replies.c b/src/tools/perf_replies.c index 24df534f..9f2a5305 100644 --- a/src/tools/perf_replies.c +++ b/src/tools/perf_replies.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "mhd_options.h" | 39 | #include "mhd_options.h" |
40 | #include "microhttpd.h" | 40 | #include "microhttpd.h" |
41 | #include "mhd_tool_str_to_uint.h" | 41 | #include "mhd_tool_str_to_uint.h" |
42 | #include "mhd_tool_get_cpu_count.h" | ||
42 | 43 | ||
43 | #if defined(MHD_REAL_CPU_COUNT) | 44 | #if defined(MHD_REAL_CPU_COUNT) |
44 | #if MHD_REAL_CPU_COUNT == 0 | 45 | #if MHD_REAL_CPU_COUNT == 0 |
@@ -165,28 +166,37 @@ get_cmd_out_as_number (const char *cmd) | |||
165 | static unsigned int | 166 | static unsigned int |
166 | detect_cpu_core_count (void) | 167 | detect_cpu_core_count (void) |
167 | { | 168 | { |
168 | int sys_cpu_count = -1; | 169 | int sys_cpu_count; |
169 | #if ! defined(_WIN32) || defined(__CYGWIN__) | 170 | sys_cpu_count = mhd_tool_get_system_cpu_count (); |
170 | sys_cpu_count = get_cmd_out_as_number ("nproc 2>/dev/null"); | ||
171 | #endif /* ! _WIN32) || __CYGWIN__ */ | ||
172 | #ifdef _WIN32 | ||
173 | if (0 >= sys_cpu_count) | ||
174 | sys_cpu_count = get_cmd_out_as_number ("echo %NUMBER_OF_PROCESSORS%"); | ||
175 | #endif /* _WIN32 */ | ||
176 | if (0 >= sys_cpu_count) | 171 | if (0 >= sys_cpu_count) |
177 | { | 172 | { |
178 | fprintf (stderr, "Failed to detect the number of available CPU cores.\n"); | 173 | int proc_cpu_count; |
174 | fprintf (stderr, "Failed to detect the number of logical CPU cores " | ||
175 | "available on the system.\n"); | ||
176 | proc_cpu_count = mhd_tool_get_proc_cpu_count (); | ||
177 | if (0 < proc_cpu_count) | ||
178 | { | ||
179 | fprintf (stderr, "The number of CPU cores available for this process " | ||
180 | "is used as a fallback.\n"); | ||
181 | sys_cpu_count = proc_cpu_count; | ||
182 | } | ||
179 | #ifdef MHD_REAL_CPU_COUNT | 183 | #ifdef MHD_REAL_CPU_COUNT |
180 | fprintf (stderr, "Hardcoded number is used as a fallback.\n"); | 184 | if (0 >= sys_cpu_count) |
181 | sys_cpu_count = MHD_REAL_CPU_COUNT; | 185 | { |
186 | fprintf (stderr, "configure-detected hardcoded number is used " | ||
187 | "as a fallback.\n"); | ||
188 | sys_cpu_count = MHD_REAL_CPU_COUNT; | ||
189 | } | ||
182 | #endif | 190 | #endif |
183 | if (0 >= sys_cpu_count) | 191 | if (0 >= sys_cpu_count) |
184 | sys_cpu_count = 1; | 192 | sys_cpu_count = 1; |
185 | printf ("Assuming %d CPU cores.\n", sys_cpu_count); | 193 | printf ("Assuming %d logical CPU core%s on this system.\n", sys_cpu_count, |
194 | (1 == sys_cpu_count) ? "" : "s"); | ||
186 | } | 195 | } |
187 | else | 196 | else |
188 | { | 197 | { |
189 | printf ("Detected %d CPU cores.\n", sys_cpu_count); | 198 | printf ("Detected %d logical CPU core%s on this system.\n", sys_cpu_count, |
199 | (1 == sys_cpu_count) ? "" : "s"); | ||
190 | } | 200 | } |
191 | return (unsigned int) sys_cpu_count; | 201 | return (unsigned int) sys_cpu_count; |
192 | } | 202 | } |
@@ -202,20 +212,84 @@ get_cpu_core_count (void) | |||
202 | } | 212 | } |
203 | 213 | ||
204 | 214 | ||
215 | static unsigned int | ||
216 | detect_process_cpu_core_count (void) | ||
217 | { | ||
218 | unsigned int num_proc_cpu_cores; | ||
219 | unsigned int sys_cpu_cores; | ||
220 | int res; | ||
221 | |||
222 | sys_cpu_cores = get_cpu_core_count (); | ||
223 | res = mhd_tool_get_proc_cpu_count (); | ||
224 | if (0 > res) | ||
225 | { | ||
226 | fprintf (stderr, "Cannot detect the number of logical CPU cores available " | ||
227 | "for this process.\n"); | ||
228 | if (1 != sys_cpu_cores) | ||
229 | printf ("Assuming all %u system logical CPU cores are available to run " | ||
230 | "threads of this process.\n", sys_cpu_cores); | ||
231 | else | ||
232 | printf ("Assuming single logical CPU core available for this process.\n"); | ||
233 | num_proc_cpu_cores = sys_cpu_cores; | ||
234 | } | ||
235 | else | ||
236 | { | ||
237 | printf ("Detected %d logical CPU core%s available to run threads " | ||
238 | "of this process.\n", res, (1 == res) ? "" : "s"); | ||
239 | num_proc_cpu_cores = (unsigned int) res; | ||
240 | } | ||
241 | if (num_proc_cpu_cores > sys_cpu_cores) | ||
242 | { | ||
243 | fprintf (stderr, "WARNING: Detected number of CPU cores available " | ||
244 | "for this process (%u) is larger than detected number " | ||
245 | "of CPU cores on the system (%u).\n", | ||
246 | num_proc_cpu_cores, sys_cpu_cores); | ||
247 | num_proc_cpu_cores = sys_cpu_cores; | ||
248 | fprintf (stderr, "Using %u as the number of logical CPU cores available " | ||
249 | "for this process.\n", num_proc_cpu_cores); | ||
250 | } | ||
251 | return num_proc_cpu_cores; | ||
252 | } | ||
253 | |||
254 | |||
255 | static unsigned int | ||
256 | get_process_cpu_core_count (void) | ||
257 | { | ||
258 | static unsigned int proc_num_cpu_cores = 0; | ||
259 | if (0 == proc_num_cpu_cores) | ||
260 | proc_num_cpu_cores = detect_process_cpu_core_count (); | ||
261 | return proc_num_cpu_cores; | ||
262 | } | ||
263 | |||
264 | |||
205 | static unsigned int num_threads = 0; | 265 | static unsigned int num_threads = 0; |
206 | 266 | ||
207 | static unsigned int | 267 | static unsigned int |
208 | get_num_threads (void) | 268 | get_num_threads (void) |
209 | { | 269 | { |
210 | static const unsigned int max_threads = 32; | 270 | static const unsigned int max_threads = 32; |
271 | if (0 < num_threads) | ||
272 | return num_threads; | ||
273 | |||
274 | num_threads = get_cpu_core_count () / 2; | ||
211 | if (0 == num_threads) | 275 | if (0 == num_threads) |
276 | num_threads = 1; | ||
277 | else | ||
212 | { | 278 | { |
213 | num_threads = get_cpu_core_count () / 2; | 279 | unsigned int num_proc_cpus; |
214 | if (0 == num_threads) | 280 | num_proc_cpus = get_process_cpu_core_count (); |
215 | num_threads = 1; | 281 | if (num_proc_cpus >= num_threads) |
216 | else | 282 | { |
217 | printf ("Using half of all available CPU cores, assuming the other half " | 283 | printf ("Using half of all available CPU cores, assuming the other half " |
218 | "is used by client / requests generator.\n"); | 284 | "is used by client / requests generator.\n"); |
285 | } | ||
286 | else | ||
287 | { | ||
288 | printf ("Using all CPU cores available for this process as more than " | ||
289 | "half of CPU cores on this system are still available for use " | ||
290 | "by client / requests generator.\n"); | ||
291 | num_threads = num_proc_cpus; | ||
292 | } | ||
219 | } | 293 | } |
220 | if (max_threads < num_threads) | 294 | if (max_threads < num_threads) |
221 | { | 295 | { |
@@ -1059,9 +1133,10 @@ check_apply_param__all_cpus (void) | |||
1059 | if (! tool_params.all_cpus) | 1133 | if (! tool_params.all_cpus) |
1060 | return; | 1134 | return; |
1061 | 1135 | ||
1062 | num_threads = get_cpu_core_count (); | 1136 | num_threads = get_process_cpu_core_count (); |
1063 | printf ("Requested use of all available CPU cores for MHD threads.\n"); | 1137 | printf ("Requested use of all available CPU cores for MHD threads.\n"); |
1064 | print_all_cores_used (); | 1138 | if (get_cpu_core_count () == num_threads) |
1139 | print_all_cores_used (); | ||
1065 | } | 1140 | } |
1066 | 1141 | ||
1067 | 1142 | ||
@@ -1075,20 +1150,21 @@ check_apply_param__threads (void) | |||
1075 | return; | 1150 | return; |
1076 | 1151 | ||
1077 | num_threads = tool_params.threads; | 1152 | num_threads = tool_params.threads; |
1153 | |||
1154 | if (get_process_cpu_core_count () < num_threads) | ||
1155 | { | ||
1156 | fprintf (stderr, "WARNING: The requested number of threads (%u) is " | ||
1157 | "higher than the number of detected available CPU cores (%u).\n", | ||
1158 | num_threads, get_process_cpu_core_count ()); | ||
1159 | fprintf (stderr, "This decreases the performance. " | ||
1160 | "Consider using fewer threads.\n"); | ||
1161 | } | ||
1078 | if (get_cpu_core_count () == num_threads) | 1162 | if (get_cpu_core_count () == num_threads) |
1079 | { | 1163 | { |
1080 | printf ("The requested number of threads is equal to the number of " | 1164 | printf ("The requested number of threads is equal to the number of " |
1081 | "detected CPU cores.\n"); | 1165 | "detected CPU cores.\n"); |
1082 | print_all_cores_used (); | 1166 | print_all_cores_used (); |
1083 | } | 1167 | } |
1084 | else if (get_cpu_core_count () < num_threads) | ||
1085 | { | ||
1086 | fprintf (stderr, "WARNING: The requested number of threads (%u) is " | ||
1087 | "higher than the number of detected CPU cores (%u).\n", | ||
1088 | num_threads, get_cpu_core_count ()); | ||
1089 | fprintf (stderr, "This decreases the performance. " | ||
1090 | "Consider using fewer threads.\n"); | ||
1091 | } | ||
1092 | } | 1168 | } |
1093 | 1169 | ||
1094 | 1170 | ||
@@ -1228,7 +1304,7 @@ static struct MHD_Response *resp_single = NULL; | |||
1228 | The system will keep it in cache. */ | 1304 | The system will keep it in cache. */ |
1229 | static const char tiny_body[] = "Hi!"; | 1305 | static const char tiny_body[] = "Hi!"; |
1230 | static char *body_dyn = NULL; /* Non-static body data */ | 1306 | static char *body_dyn = NULL; /* Non-static body data */ |
1231 | size_t body_dyn_size; | 1307 | static size_t body_dyn_size; |
1232 | 1308 | ||
1233 | /* Non-zero - success, zero - failure */ | 1309 | /* Non-zero - success, zero - failure */ |
1234 | static int | 1310 | static int |