aboutsummaryrefslogblamecommitdiffstats
path: root/library/cpp/netliba/v6/cpu_affinity.cpp
blob: 55b4c98b71345253d2bb53b333ab3df7fb0bbc58 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15













                                              
                                            
























































































































                                                                                                                      
#include "stdafx.h"
#include "cpu_affinity.h"

#if defined(__FreeBSD__) && (__FreeBSD__ >= 7)
#include <sys/param.h>
#include <sys/cpuset.h>
#elif defined(_linux_)
#include <pthread.h>
#include <util/stream/file.h>
#include <util/string/printf.h>
#endif

namespace NNetliba {
    class TCPUSet {
    public:
        static constexpr int MAX_SIZE = 128;

    private:
#if defined(__FreeBSD__) && (__FreeBSD__ >= 7)
#define NUMCPU ((CPU_MAXSIZE > MAX_SIZE) ? 1 : (MAX_SIZE / CPU_MAXSIZE))
        cpuset_t CpuInfo[NUMCPU];

    public:
        bool GetAffinity() {
            int error = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(CpuInfo), CpuInfo);
            return error == 0;
        }
        bool SetAffinity() {
            int error = cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(CpuInfo), CpuInfo);
            return error == 0;
        }
        bool IsSet(size_t i) {
            return CPU_ISSET(i, CpuInfo);
        }
        void Set(size_t i) {
            CPU_SET(i, CpuInfo);
        }
#elif defined(_linux_)
    public:
#define NUMCPU ((CPU_SETSIZE > MAX_SIZE) ? 1 : (MAX_SIZE / CPU_SETSIZE))
        cpu_set_t CpuInfo[NUMCPU];

    public:
        bool GetAffinity() {
            int error = pthread_getaffinity_np(pthread_self(), sizeof(CpuInfo), CpuInfo);
            return error == 0;
        }
        bool SetAffinity() {
            int error = pthread_setaffinity_np(pthread_self(), sizeof(CpuInfo), CpuInfo);
            return error == 0;
        }
        bool IsSet(size_t i) {
            return CPU_ISSET(i, CpuInfo);
        }
        void Set(size_t i) {
            CPU_SET(i, CpuInfo);
        }
#else
    public:
        bool GetAffinity() {
            return true;
        }
        bool SetAffinity() {
            return true;
        }
        bool IsSet(size_t i) {
            Y_UNUSED(i);
            return true;
        }
        void Set(size_t i) {
            Y_UNUSED(i);
        }
#endif

        TCPUSet() {
            Clear();
        }
        void Clear() {
            memset(this, 0, sizeof(*this));
        }
    };

    static TMutex CPUSetsLock;
    struct TCPUSetInfo {
        TCPUSet CPUSet;
        bool IsOk;

        TCPUSetInfo()
            : IsOk(false)
        {
        }
    };
    static THashMap<int, TCPUSetInfo> CPUSets;

    void BindToSocket(int n) {
        TGuard<TMutex> gg(CPUSetsLock);
        if (CPUSets.find(n) == CPUSets.end()) {
            TCPUSetInfo& res = CPUSets[n];

            bool foundCPU = false;
#ifdef _linux_
            for (int cpuId = 0; cpuId < TCPUSet::MAX_SIZE; ++cpuId) {
                try { // I just wanna check if file exists, I don't want your stinking exceptions :/
                    TIFStream f(Sprintf("/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpuId).c_str());
                    TString s;
                    if (f.ReadLine(s) && !s.empty()) {
                        //printf("cpu%d - %s\n", cpuId, s.c_str());
                        int physCPU = atoi(s.c_str());
                        if (physCPU == 0) {
                            res.IsOk = true;
                            res.CPUSet.Set(cpuId);
                            foundCPU = true;
                        }
                    } else {
                        break;
                    }
                } catch (const TFileError&) {
                    break;
                }
            }
#endif
            if (!foundCPU && n == 0) {
                for (int i = 0; i < 6; ++i) {
                    res.CPUSet.Set(i);
                }
                res.IsOk = true;
                foundCPU = true;
            }
        }
        {
            TCPUSetInfo& cc = CPUSets[n];
            if (cc.IsOk) {
                cc.CPUSet.SetAffinity();
            }
        }
    }

}