]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Added cpu_affinity_map configuration option to bind workers to CPU cores.
authorAlex Rousskov <rousskov@measurement-factory.com>
Thu, 23 Sep 2010 17:58:15 +0000 (11:58 -0600)
committerAlex Rousskov <rousskov@measurement-factory.com>
Thu, 23 Sep 2010 17:58:15 +0000 (11:58 -0600)
Allows the admin to place all workers on individual cores without writing a
lot of if-statements. For example,

    cpu_affinity_map process_numbers=1,2,3,4 cores=1,3,5,7

will have an effect for kids 1 through 4 only and will place them on even
cores starting with core #1.

If there are conflicts for a given process, the latest option wins and a
warning is printed. If the number of specified processes do not match the
number of specified cores, Squid quits with an error. Multiple
cpu_affinity_map options are merged.

Squid builds on systems without Linux CPU affinity calls, but setting affinity
only works if there are sched_getaffinity(2) and sched_setaffinity(2)
available. If there is no OS support but cpu_affinity options are configured,
Squid quits with an error. If there is OS support but calls fail, Squid prints
an error but does not quit.

17 files changed:
compat/Makefile.am
compat/cpu.h [new file with mode: 0644]
configure.in
src/CpuAffinity.cc [new file with mode: 0644]
src/CpuAffinity.h [new file with mode: 0644]
src/CpuAffinityMap.cc [new file with mode: 0644]
src/CpuAffinityMap.h [new file with mode: 0644]
src/CpuAffinitySet.cc [new file with mode: 0644]
src/CpuAffinitySet.h [new file with mode: 0644]
src/Makefile.am
src/cache_cf.cc
src/cf.data.depend
src/cf.data.pre
src/main.cc
src/protos.h
src/structs.h
src/tools.cc

index 55493e2369d230805f24c83dbe3495d877077270..5e244ca49e1d8325419c1f3904268b7ef953bcac 100644 (file)
@@ -14,6 +14,7 @@ libcompat_la_SOURCES = \
        assert.h \
        compat.h \
        compat_shared.h \
+       cpu.h \
        debug.h \
        drand48.h \
        eui64_aton.h \
diff --git a/compat/cpu.h b/compat/cpu.h
new file mode 100644 (file)
index 0000000..bd589d3
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * $Id$
+ */
+
+#ifndef SQUID_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef SQUID_COMPAT_CPU_H
+#define SQUID_COMPAT_CPU_H
+
+#if HAVE_CPU_AFFINITY
+
+#if HAVE_SCHED_H
+#include <sched.h>
+#endif
+
+// glibc prior to 2.6 lacks CPU_COUNT
+#ifndef CPU_COUNT
+#define CPU_COUNT(set) CpuCount(set)
+/// CPU_COUNT replacement
+inline int
+CpuCount(const cpu_set_t *set)
+{
+    int count = 0;
+    for (int i = 0; i < CPU_SETSIZE; ++i) {
+        if (CPU_ISSET(i, set))
+            ++count;
+    }
+    return count;
+}
+#endif /* CPU_COUNT */
+
+// glibc prior to 2.7 lacks CPU_AND
+#ifndef CPU_AND
+#define CPU_AND(destset, srcset1, srcset2) CpuAnd((destset), (srcset1), (srcset2))
+/// CPU_AND replacement
+inline void
+CpuAnd(cpu_set_t *destset, const cpu_set_t *srcset1, const cpu_set_t *srcset2)
+{
+    CPU_ZERO(destset);
+    for (int i = 0; i < CPU_SETSIZE; ++i) {
+        if (CPU_ISSET(i, srcset1) && CPU_ISSET(i, srcset2))
+            CPU_SET(i, destset);
+    }
+}
+#endif /* CPU_AND */
+
+#else /* HAVE_CPU_AFFINITY */
+
+#if HAVE_ERRNO_H
+#include <errno.h> /* for ENOTSUP */
+#endif
+
+/* failing replacements to minimize the number of if-HAVE_CPU_AFFINITYs */
+typedef struct
+{
+    int bits;
+} cpu_set_t;
+#define CPU_SETSIZE 0
+#define CPU_COUNT(set) 0
+#define CPU_AND(destset, srcset1, srcset2) (void)0
+#define CPU_ZERO(set) (void)0
+inline int sched_setaffinity(int, size_t, cpu_set_t *) { return ENOTSUP; }
+inline int sched_getaffinity(int, size_t, cpu_set_t *) { return ENOTSUP; }
+
+#endif /* HAVE_CPU_AFFINITY */
+
+#endif /* SQUID_COMPAT_CPU_H */
index 276da36e5ec12717111eeab2bb16e02984a0a9dd..98c8be27ba2b0b9a25c3a48b3ee5bbd9164019c6 100644 (file)
@@ -2934,6 +2934,8 @@ AC_CHECK_FUNCS(\
        __res_init \
        rint \
        sbrk \
+       sched_getaffinity \
+       sched_setaffinity \
        select \
        seteuid \
        setgroups \
@@ -3008,6 +3010,10 @@ case $squid_opt_io_loop_engine in
   select) AC_DEFINE(USE_SELECT,1,[Use select() for the IO loop]) ;;
 esac
 
+if test "x$ac_cv_func_sched_getaffinity" = "xyes" -a "x$ac_cv_func_sched_setaffinity" = "xyes" ; then
+  AC_DEFINE(HAVE_CPU_AFFINITY,1,[Support setting CPU affinity for workers])
+fi
+
 SQUID_CHECK_SETRESUID_WORKS
 if test "x$squid_cv_resuid_works" = "xyes" ; then
   AC_DEFINE(HAVE_SETRESUID,1,[Yay! Another Linux brokenness. Knowing that setresuid() exists is not enough, because RedHat 5.0 declares setresuid() but does not implement it.])
diff --git a/src/CpuAffinity.cc b/src/CpuAffinity.cc
new file mode 100644 (file)
index 0000000..ca061a8
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 54    Interprocess Communication
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "CpuAffinity.h"
+#include "CpuAffinityMap.h"
+#include "CpuAffinitySet.h"
+#include "structs.h"
+
+#include <algorithm>
+
+static CpuAffinitySet *TheCpuAffinitySet = NULL;
+
+
+void
+CpuAffinityInit()
+{
+    Must(!TheCpuAffinitySet);
+    if (Config.cpuAffinityMap) {
+        const int processNumber = InDaemonMode() ? KidIdentifier : 1;
+        TheCpuAffinitySet = Config.cpuAffinityMap->calculateSet(processNumber);
+        if (TheCpuAffinitySet)
+            TheCpuAffinitySet->apply();
+    }
+}
+
+void
+CpuAffinityReconfigure()
+{
+    if (TheCpuAffinitySet) {
+        TheCpuAffinitySet->undo();
+        delete TheCpuAffinitySet;
+        TheCpuAffinitySet = NULL;
+    }
+    CpuAffinityInit();
+}
+
+void
+CpuAffinityCheck()
+{
+    if (Config.cpuAffinityMap) {
+        Must(!Config.cpuAffinityMap->processes().empty());
+        const int maxProcess =
+            *std::max_element(Config.cpuAffinityMap->processes().begin(),
+                              Config.cpuAffinityMap->processes().end());
+
+        // in no-deamon mode, there is one process regardless of squid.conf
+        const int numberOfProcesses = InDaemonMode() ? NumberOfKids() : 1;
+
+        if (maxProcess > numberOfProcesses) {
+            debugs(54, DBG_IMPORTANT, "WARNING: 'cpu_affinity_map' has "
+                   "non-existing process number(s)");
+        }
+    }
+}
diff --git a/src/CpuAffinity.h b/src/CpuAffinity.h
new file mode 100644 (file)
index 0000000..0b6d39a
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * $Id$
+ *
+ */
+
+#ifndef SQUID_CPU_AFFINITY_H
+#define SQUID_CPU_AFFINITY_H
+
+#include "config.h"
+
+/// set CPU affinity for this process on startup
+SQUIDCEXTERN void CpuAffinityInit();
+
+/// reconfigure CPU affinity for this process
+SQUIDCEXTERN void CpuAffinityReconfigure();
+
+/// check CPU affinity configuration and print warnings if needed
+SQUIDCEXTERN void CpuAffinityCheck();
+
+
+#endif // SQUID_CPU_AFFINITY_H
diff --git a/src/CpuAffinityMap.cc b/src/CpuAffinityMap.cc
new file mode 100644 (file)
index 0000000..75666f7
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 54    Interprocess Communication
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "CpuAffinityMap.h"
+#include "CpuAffinitySet.h"
+#include "Debug.h"
+
+
+bool
+CpuAffinityMap::add(const Vector<int> &aProcesses, const Vector<int> &aCores)
+{
+    if (aProcesses.size() != aCores.size())
+        return false;
+
+    for (size_t i = 0; i < aProcesses.size(); ++i) {
+        const int process = aProcesses[i];
+        const int core = aCores[i];
+        if (process <= 0 || core <= 0)
+            return false;
+        theProcesses.push_back(process);
+        theCores.push_back(core);
+    }
+
+    return true;
+}
+
+CpuAffinitySet *
+CpuAffinityMap::calculateSet(const int targetProcess) const
+{
+    Must(theProcesses.size() == theCores.size());
+    int core = 0;
+    for (size_t i = 0; i < theProcesses.size(); ++i) {
+        const int process = theProcesses[i];
+        if (process == targetProcess)
+        {
+            if (core > 0) {
+                debugs(54, DBG_CRITICAL, "WARNING: conflicting "
+                       "'cpu_affinity_map' for process number " << process <<
+                       ", using the last core seen: " << theCores[i]);
+            }
+            core = theCores[i];
+        }
+    }
+    CpuAffinitySet *cpuAffinitySet = NULL;
+    if (core > 0) {
+        cpuAffinitySet = new CpuAffinitySet;
+        cpu_set_t cpuSet;
+        CPU_ZERO(&cpuSet);
+        CPU_SET(core - 1, &cpuSet);
+        cpuAffinitySet->set(cpuSet);
+    }
+    return cpuAffinitySet;
+}
diff --git a/src/CpuAffinityMap.h b/src/CpuAffinityMap.h
new file mode 100644 (file)
index 0000000..97c2d23
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * $Id$
+ *
+ */
+
+#ifndef SQUID_CPU_AFFINITY_MAP_H
+#define SQUID_CPU_AFFINITY_MAP_H
+
+#include "Array.h"
+
+class CpuAffinitySet;
+
+
+/// stores cpu_affinity_map configuration
+class CpuAffinityMap
+{
+public:
+    /// append cpu_affinity_map option
+    bool add(const Vector<int> &aProcesses, const Vector<int> &aCores);
+
+    /// calculate CPU set for this process
+    CpuAffinitySet *calculateSet(const int targetProcess) const;
+
+    /// returns list of process numbers
+    const Vector<int> &processes() const { return theProcesses; }
+
+    /// returns list of cores
+    const Vector<int> &cores() const { return theCores; }
+
+private:
+    Vector<int> theProcesses; ///< list of process numbers
+    Vector<int> theCores; ///< list of cores
+};
+
+#endif // SQUID_CPU_AFFINITY_MAP_H
diff --git a/src/CpuAffinitySet.cc b/src/CpuAffinitySet.cc
new file mode 100644 (file)
index 0000000..593ae7a
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 54    Interprocess Communication
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "CpuAffinitySet.h"
+#include "Debug.h"
+#include "util.h"
+
+#if HAVE_STRING_H
+#include <string.h> /* for memcpy() */
+#endif
+
+
+CpuAffinitySet::CpuAffinitySet()
+{
+    CPU_ZERO(&theCpuSet);
+    CPU_ZERO(&theOrigCpuSet);
+}
+
+void
+CpuAffinitySet::apply()
+{
+    Must(CPU_COUNT(&theCpuSet) > 0); // CPU affinity mask set
+    Must(!applied());
+
+    bool success = false;
+    if (sched_getaffinity(0, sizeof(theOrigCpuSet), &theOrigCpuSet)) {
+        debugs(54, DBG_IMPORTANT, "ERROR: failed to get CPU affinity for "
+               "process PID " << getpid() << ", ignoring CPU affinity for "
+               "this process: " << xstrerror());
+    } else {
+        cpu_set_t cpuSet;
+        xmemcpy(&cpuSet, &theCpuSet, sizeof(cpuSet));
+        CPU_AND(&cpuSet, &cpuSet, &theOrigCpuSet);
+        if (CPU_COUNT(&cpuSet) <= 0) {
+            debugs(54, DBG_IMPORTANT, "ERROR: invalid CPU affinity for process "
+                   "PID " << getpid() << ", may be caused by an invalid core in "
+                   "'cpu_affinity_map' or by external affinity restrictions");
+        } else if (sched_setaffinity(0, sizeof(cpuSet), &cpuSet)) {
+            debugs(54, DBG_IMPORTANT, "ERROR: failed to set CPU affinity for "
+                   "process PID " << getpid() << ": " << xstrerror());
+        } else
+            success = true;
+    }
+    if (!success)
+        CPU_ZERO(&theOrigCpuSet);
+}
+
+void
+CpuAffinitySet::undo()
+{
+    if (applied()) {
+        if (sched_setaffinity(0, sizeof(theOrigCpuSet), &theOrigCpuSet)) {
+            debugs(54, DBG_IMPORTANT, "ERROR: failed to restore original CPU "
+                   "affinity for process PID " << getpid() << ": " <<
+                   xstrerror());
+        }
+        CPU_ZERO(&theOrigCpuSet);
+    }
+}
+
+bool
+CpuAffinitySet::applied() const
+{
+    return (CPU_COUNT(&theOrigCpuSet) > 0);
+}
+
+void
+CpuAffinitySet::set(const cpu_set_t &aCpuSet)
+{
+    xmemcpy(&theCpuSet, &aCpuSet, sizeof(theCpuSet));
+}
diff --git a/src/CpuAffinitySet.h b/src/CpuAffinitySet.h
new file mode 100644 (file)
index 0000000..cec1119
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * $Id$
+ *
+ */
+
+#ifndef SQUID_CPU_AFFINITY_SET_H
+#define SQUID_CPU_AFFINITY_SET_H
+
+#include "config.h"
+#include "compat/cpu.h"
+
+/// cpu affinity management for a single process
+class CpuAffinitySet
+{
+public:
+    CpuAffinitySet();
+
+    /// set CPU affinity for this process
+    void apply();
+
+    /// undo CPU affinity changes for this process
+    void undo();
+
+    /// whether apply() was called and was not undone
+    bool applied() const;
+
+    /// set CPU affinity mask
+    void set(const cpu_set_t &aCpuSet);
+
+private:
+    cpu_set_t theCpuSet; ///< configured CPU affinity for this process
+    cpu_set_t theOrigCpuSet; ///< CPU affinity for this process before apply()
+};
+
+#endif // SQUID_CPU_AFFINITY_SET_H
index c453474830f52f2fb2962c4b2e0ecad000c3c19b..f80b7c169589725982c1943b1a4d0b5f7a2b7d94 100644 (file)
@@ -291,6 +291,12 @@ squid_SOURCES = \
        ConfigParser.cc \
        ConfigParser.h \
        ConnectionDetail.h \
+       CpuAffinity.cc \
+       CpuAffinity.h \
+       CpuAffinityMap.cc \
+       CpuAffinityMap.h \
+       CpuAffinitySet.cc \
+       CpuAffinitySet.h \
        debug.cc \
        Debug.h \
        defines.h \
@@ -1135,6 +1141,10 @@ tests_testCacheManager_SOURCES = \
        $(squid_COMMSOURCES) \
        ConfigOption.cc \
        ConfigParser.cc \
+       CpuAffinityMap.cc \
+       CpuAffinityMap.h \
+       CpuAffinitySet.cc \
+       CpuAffinitySet.h \
        $(DELAY_POOL_SOURCE) \
        disk.cc \
        dlink.h \
@@ -1320,6 +1330,10 @@ tests_testEvent_SOURCES = \
        $(squid_COMMSOURCES) \
        ConfigOption.cc \
        ConfigParser.cc \
+       CpuAffinityMap.cc \
+       CpuAffinityMap.h \
+       CpuAffinitySet.cc \
+       CpuAffinitySet.h \
        $(DELAY_POOL_SOURCE) \
        disk.cc \
        dlink.h \
@@ -1476,6 +1490,10 @@ tests_testEventLoop_SOURCES = \
        $(squid_COMMSOURCES) \
        ConfigOption.cc \
        ConfigParser.cc \
+       CpuAffinityMap.cc \
+       CpuAffinityMap.h \
+       CpuAffinitySet.cc \
+       CpuAffinitySet.h \
        $(DELAY_POOL_SOURCE) \
        disk.cc \
        dlink.h \
@@ -1619,6 +1637,10 @@ tests_test_http_range_SOURCES = \
        $(squid_COMMSOURCES) \
        ConfigOption.cc \
        ConfigParser.cc \
+       CpuAffinityMap.cc \
+       CpuAffinityMap.h \
+       CpuAffinitySet.cc \
+       CpuAffinitySet.h \
        tests/stub_main_cc.cc \
        debug.cc \
        $(DELAY_POOL_SOURCE) \
@@ -1782,6 +1804,10 @@ tests_testHttpRequest_SOURCES = \
        $(squid_COMMSOURCES) \
        ConfigOption.cc \
        ConfigParser.cc \
+       CpuAffinityMap.cc \
+       CpuAffinityMap.h \
+       CpuAffinitySet.cc \
+       CpuAffinitySet.h \
        $(DELAY_POOL_SOURCE) \
        disk.cc \
        dlink.h \
@@ -2158,6 +2184,10 @@ tests_testURL_SOURCES = \
        $(squid_COMMSOURCES) \
        ConfigOption.cc \
        ConfigParser.cc \
+       CpuAffinityMap.cc \
+       CpuAffinityMap.h \
+       CpuAffinitySet.cc \
+       CpuAffinitySet.h \
        $(DELAY_POOL_SOURCE) \
        disk.cc \
        dlink.h \
index 463573e046b5cbe7cb2f1f6b496e6f225ca328ce..edb0ac4d961e3b2528ed7428785a7c8c5fa6e266 100644 (file)
@@ -50,6 +50,7 @@
 #include "auth/Scheme.h"
 #include "CacheManager.h"
 #include "ConfigParser.h"
+#include "CpuAffinityMap.h"
 #include "eui/Config.h"
 #if USE_SQUID_ESI
 #include "esi/Parser.h"
@@ -181,6 +182,12 @@ static int check_null_https_port_list(const https_port_list *);
 static void parse_b_size_t(size_t * var);
 static void parse_b_int64_t(int64_t * var);
 
+static bool parseNamedIntList(const char *data, const String &name, Vector<int> &list);
+
+static void parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
+static void dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap);
+static void free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
+
 static int parseOneConfigFile(const char *file_name, unsigned int depth);
 
 /*
@@ -3842,6 +3849,80 @@ free_access_log(customlog ** definitions)
     }
 }
 
+/// parses list of integers form name=N1,N2,N3,...
+static bool
+parseNamedIntList(const char *data, const String &name, Vector<int> &list)
+{
+    if (data && (strncmp(data, name.rawBuf(), name.size()) == 0)) {
+        data += name.size();
+        if (*data == '=') {
+            while (true) {
+                ++data;
+                int value = 0;
+                if (!StringToInt(data, value, &data, 10))
+                    break;
+                list.push_back(value);
+                if (*data == '\0' || *data != ',')
+                    break;
+            }
+        }
+    }
+    return *data == '\0';
+}
+
+static void
+parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap) {
+#if !HAVE_CPU_AFFINITY
+    debugs(3, DBG_CRITICAL, "FATAL: Squid built with no CPU affinity " <<
+           "support, do not set 'cpu_affinity_map'");
+    self_destruct();
+#endif /* HAVE_CPU_AFFINITY */
+
+    if (!*cpuAffinityMap)
+        *cpuAffinityMap = new CpuAffinityMap;
+
+    const char *const pToken = strtok(NULL, w_space);
+    const char *const cToken = strtok(NULL, w_space);
+    Vector<int> processes, cores;
+    if (!parseNamedIntList(pToken, "process_numbers", processes)) {
+        debugs(3, DBG_CRITICAL, "FATAL: bad 'process_numbers' parameter " <<
+               "in 'cpu_affinity_map'");
+        self_destruct();
+    } else if (!parseNamedIntList(cToken, "cores", cores)) {
+        debugs(3, DBG_CRITICAL, "FATAL: bad 'cores' parameter in " <<
+               "'cpu_affinity_map'");
+        self_destruct();
+    } else if (!(*cpuAffinityMap)->add(processes, cores)) {
+        debugs(3, DBG_CRITICAL, "FATAL: bad 'cpu_affinity_map'; " <<
+               "process_numbers and cores lists differ in length or " <<
+               "contain numbers <= 0");
+        self_destruct();
+    }
+}
+
+static void
+dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap) {
+    if (cpuAffinityMap) {
+        storeAppendPrintf(entry, "%s process_numbers=", name);
+        for (size_t i = 0; i < cpuAffinityMap->processes().size(); ++i) {
+            storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
+                              cpuAffinityMap->processes()[i]);
+        }
+        storeAppendPrintf(entry, " cores=");
+        for (size_t i = 0; i < cpuAffinityMap->processes().size(); ++i) {
+            storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
+                              cpuAffinityMap->cores()[i]);
+        }
+        storeAppendPrintf(entry, "\n");
+    }
+}
+
+static void
+free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap) {
+    delete *cpuAffinityMap;
+    *cpuAffinityMap = NULL;
+}
+
 #if USE_ADAPTATION
 
 static void
index a3b62464957fc47c22515804f2b5c5a2c0924a6f..25e48df6ff522ca63356dca3ccef273d055af347 100644 (file)
@@ -11,6 +11,7 @@ b_int64_t
 b_size_t
 cachedir               cache_replacement_policy
 cachemgrpasswd
+CpuAffinityMap
 debug
 delay_pool_access      acl     delay_class
 delay_pool_class       delay_pools
index 7e76f90e5ec2b0371b337929309f4d6bb2c4ca06..a0ac4c2042a4f2ee538213a3b9518644f09081e9 100644 (file)
@@ -7072,4 +7072,26 @@ DOC_START
        does (e.g., listen on http_port and forward HTTP requests).
 DOC_END
 
+NAME: cpu_affinity_map
+TYPE: CpuAffinityMap
+LOC: Config.cpuAffinityMap
+DEFAULT: none
+DOC_START
+       Usage: cpu_affinity_map process_numbers=P1,P2,... cores=C1,C2,...
+
+       Sets 1:1 mapping between Squid processes and CPU cores. For example,
+
+           cpu_affinity_map process_numbers=1,2,3,4 cores=1,3,5,7
+
+       affects processes 1 through 4 only and places them on the first
+       four even cores, starting with core #1.
+
+       CPU cores are numbered starting from 1. Requires support for
+       sched_getaffinity(2) and sched_setaffinity(2) system calls.
+
+       Multiple cpu_affinity_map options are merged.
+
+       See also: workers
+DOC_END
+
 EOF
index 476752fe90dfaba36e91b7da4ba1445c8783704a..0865e3c7855a4159d3a66df8af2d6097a2e7d24a 100644 (file)
@@ -40,6 +40,7 @@
 #include "auth/Gadgets.h"
 #include "base/TextException.h"
 #include "ConfigParser.h"
+#include "CpuAffinity.h"
 #include "errorpage.h"
 #include "event.h"
 #include "EventLoop.h"
@@ -770,6 +771,10 @@ mainReconfigureFinish(void *)
         Config.workers = oldWorkers;
     }
 
+    if (IamPrimaryProcess())
+        CpuAffinityCheck();
+    CpuAffinityReconfigure();
+
     setUmask(Config.umask);
     Mem::Report();
     setEffectiveUser();
@@ -1410,6 +1415,10 @@ SquidMain(int argc, char **argv)
         return 0;
     }
 
+    if (IamPrimaryProcess())
+        CpuAffinityCheck();
+    CpuAffinityInit();
+
     if (!opt_no_daemon && Config.workers > 0)
         watch_child(argv);
 
index 572eba10caa0449493a0589f284d3332c1396a0b..d212b54fc2efef09e16792632e27809afd03edc5 100644 (file)
@@ -583,8 +583,12 @@ SQUIDCEXTERN bool IamPrimaryProcess();
 SQUIDCEXTERN bool IamCoordinatorProcess();
 /// whether the current process handles HTTP transactions and such
 SQUIDCEXTERN bool IamWorkerProcess();
+/// Whether we are running in daemon mode
+SQUIDCEXTERN bool InDaemonMode(); // try using specific Iam*() checks above first
 /// Whether there should be more than one worker process running
 SQUIDCEXTERN bool UsingSmp(); // try using specific Iam*() checks above first
+/// number of Kid processes as defined in src/ipc/Kid.h
+SQUIDCEXTERN int NumberOfKids();
 SQUIDCEXTERN int DebugSignal;
 
 /* AYJ debugs function to show locations being reset with memset() */
index 2e83590908b6103634e20d70a187bd31e6bd429c..7c08d0563671f3ec35b4fc3a30268dbda3983136 100644 (file)
@@ -130,6 +130,7 @@ struct relist {
 
 /* forward decl for SquidConfig, see RemovalPolicy.h */
 
+class CpuAffinityMap;
 class RemovalPolicySettings;
 class external_acl;
 class Store;
@@ -611,6 +612,7 @@ struct SquidConfig {
     int umask;
     int max_filedescriptors;
     int workers;
+    CpuAffinityMap *cpuAffinityMap;
 
 #if USE_LOADABLE_MODULES
     wordlist *loadable_module_names;
index 6743604fe449b6920157ecf053568a15cbc989c0..7558c9f9e2e78a0c6ebfd457e96931b589744ba6 100644 (file)
@@ -823,6 +823,12 @@ IamWorkerProcess()
     return 0 < KidIdentifier && KidIdentifier <= Config.workers;
 }
 
+bool
+InDaemonMode()
+{
+    return !opt_no_daemon && Config.workers > 0;
+}
+
 bool
 UsingSmp()
 {
@@ -851,6 +857,20 @@ IamPrimaryProcess()
     return IamCoordinatorProcess();
 }
 
+int
+NumberOfKids()
+{
+    // no kids in no-daemon mode
+    if (!InDaemonMode())
+        return 0;
+
+    // workers + the coordinator process
+    if (UsingSmp())
+        return Config.workers + 1;
+
+    return Config.workers;
+}
+
 void
 writePidFile(void)
 {