gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libmicrohttpd] 03/03: Implemented proper detection of number of availab


From: gnunet
Subject: [libmicrohttpd] 03/03: Implemented proper detection of number of available CPU cores
Date: Sat, 29 Jul 2023 22:39:08 +0200

This is an automated email from the git hooks/post-receive script.

karlson2k pushed a commit to branch master
in repository libmicrohttpd.

commit e87d26c42902db03560ef2e71e7e656bfd32b5a7
Author: Evgeny Grin (Karlson2k) <k2k@narod.ru>
AuthorDate: Wed Jul 12 21:29:45 2023 +0300

    Implemented proper detection of number of available CPU cores
---
 configure.ac                       | 337 +++++++++++++++++++
 src/include/mhd_options.h          |  76 +++++
 src/tools/Makefile.am              |   3 +-
 src/tools/mhd_tool_get_cpu_count.c | 658 +++++++++++++++++++++++++++++++++++++
 src/tools/mhd_tool_get_cpu_count.h |  55 ++++
 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"],
         )
       ]
     )
+    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])
+          ]
+        )
+      ]
+    )
   ]
 )
 
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 @@
 #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 */
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
 
 
 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
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 @@
+/*
+ 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 */
+}
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 @@
+/*
+ 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_ */
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 @@
 #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

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]