/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /*! * * \file mapping_utils.hpp * \ingroup aux_classes * * \brief This file contains utilities for plaform inspection and thread pinning * * Platform dependent code. Not really possible currently port it to plain C++11 * */ /* *************************************************************************** * FastFlow is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * Starting from version 3.0.1 FastFlow is dual licensed under the GNU LGPLv3 * or MIT License (https://github.com/ParaGroup/WindFlow/blob/vers3.x/LICENSE.MIT) * * This program 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 program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * **************************************************************************** */ /* * * Author: Marco Aldinucci, Massimo Torquati * Date: Oct 5, 2010: basic linux and apple * Date: Mar 27, 2011: some win platform support * */ #ifndef FF_MAPPING_UTILS_HPP #define FF_MAPPING_UTILS_HPP #include #include #include #include #include #include #include #if defined(__linux__) #include #include #include #include #include #include static inline int ff_gettid() { return syscall(__NR_gettid);} #if defined(MAMMUT) #include #endif #elif defined(__APPLE__) #include #include #include #include #include #include // If you don't include mach/mach.h, it doesn't work. // In theory mach/thread_policy.h should be enough #elif defined(_WIN32) #include #endif #if defined(__APPLE__) && MAC_OS_X_HAS_AFFINITY #include #endif /** * \brief Returns the ID of the calling thread * * It returns the ID of the calling thread. It works on Linux OS, Apple OS, * Windows. * * \return if successful the identifier of the thread is returned. Otherwise a * negative vlue is returned. * */ static inline size_t ff_getThreadID() { #if (defined(__GNUC__) && defined(__linux)) return ff_gettid(); #elif defined(__APPLE__) && MAC_OS_X_HAS_AFFINITY //uint64_t tid; // pthread_getthreadid_np(NULL, &tid); // MA: for some reasons does nto works (it was working) //return (long) tid; // > 10.6 only #elif defined(_WIN32) return GetCurrentThreadId(); #endif return -1; } /** * \brief Returnes the frequency of the CPU * * It returns the frequency of the CPUs (On a shared memory system, all cores * have the same frequency). It works on Linux OS and Apple OS. * * \return An integer value showing the frequency of the core. */ static inline unsigned long ff_getCpuFreq() { unsigned long t = 0; #if defined(__linux__) FILE *f; float mhz; f = popen("cat /proc/cpuinfo |grep MHz |head -1|sed 's/^.*: //'", "r"); if (fscanf(f, "%f", &mhz) == EOF) {pclose(f); return t;} t = (unsigned long)(mhz * 1000000); pclose(f); #elif defined(__APPLE__) && MAC_OS_X_HAS_AFFINITY size_t len = 8; if (sysctlbyname("hw.cpufrequency", &t, &len, NULL, 0) != 0) { perror("sysctl"); } #elif defined(_WIN32) //SYSTEM_POWER_CAPABILITIES pow; //GetPwrCapabilities(&pow); #else //#warning "Cannot detect CPU frequency" #endif return (t); } /** * \brief Returns the number of cores in the system * * It returns the number of cores present in the system. (Note that it does * take into account hyperthreading). It works on Linux OS, Apple OS and * Windows. * * \return An integer value showing the number of cores. */ static inline ssize_t ff_numCores() { if (FF_NUM_CORES != -1) return FF_NUM_CORES; ssize_t n=-1; #if defined(__linux__) #if defined(MAMMUT) mammut::Mammut m; std::vector cpus = m.getInstanceTopology()->getCpus(); if (cpus.size()>0 && cpus[0]->getPhysicalCores().size()>0) { n = 0; for(size_t i = 0; i < cpus.size(); i++){ std::vector phyCores = cpus.at(i)->getPhysicalCores(); std::vector virtCores = phyCores.at(0)->getVirtualCores(); n+= phyCores.size()*virtCores.size(); } } #else #if defined(HAVE_PTHREAD_SETAFFINITY_NP) // trying to understand which are the cores on which the thread can be executed // so that we obtain only the cores that are currently online cpu_set_t cpuset; CPU_ZERO(&cpuset); do { if (pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) != 0) break; #if defined(CPU_COUNT_S) n = CPU_COUNT_S(sizeof(cpu_set_t), &cpuset); #elif defined(CPU_COUNT) n = CPU_COUNT(&cpuset); #else n=0; for(size_t i=0;i cpus = m.getInstanceTopology()->getCpus(); if (cpus.size()>0 && cpus[0]->getPhysicalCores().size()>0) { n = 0; for(size_t i = 0; i < cpus.size(); i++){ std::vector phyCores = cpus.at(i)->getPhysicalCores(); n+= phyCores.size(); } } return n; #else // MAMMUT #if defined(HAVE_PTHREAD_SETAFFINITY_NP) // trying to understand which are the cores on which the thread can be executed // so that we obtain only the cores that are currently online cpu_set_t cpuset; CPU_ZERO(&cpuset); int cnt=-1; do { if (pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset) != 0) break; #if defined(CPU_COUNT_S) cnt = CPU_COUNT_S(sizeof(cpu_set_t), &cpuset); #elif defined(CPU_COUNT) cnt = CPU_COUNT(&cpuset); #endif std::set S; for(size_t i=0;i cpus = m.getInstanceTopology()->getCpus(); if (cpus.size()>0) n = cpus.size(); return n; #endif // MAMMUT #elif defined (__APPLE__) char inspect[]="sysctl hw.packages | awk '{print $2}'"; #else char inspect[]=""; n=1; #pragma message ("ff_realNumCores not supported on this platform") #endif FILE *f; f = popen(inspect, "r"); if (f) { if (fscanf(f, "%ld", &n) == EOF) { perror("fscanf"); } pclose(f); } else perror("popen"); #endif // _WIN32 return n; } /** * \brief Sets the scheduling priority * * It sets the scheduling priority of the process (or thread). The * priority_level is a value in the range -20 to 19. The default priority is 0, * lower priorities cause more favorable scheduling. * * MA: This should be redesigned since it might have different behaviours in * different systems. * * \parm priority_level defines the level of the priority. Default is set to * 0. * * \return An integer value showing the priority of the scheduling policy. * */ static inline ssize_t ff_setPriority(ssize_t priority_level=0) { ssize_t ret=0; #if (defined(__GNUC__) && defined(__linux)) //if (priority_level) { if (setpriority(PRIO_PROCESS, ff_gettid(), priority_level) != 0) { perror("setpriority:"); ret = EINVAL; } //} #elif defined(__APPLE__) if (setpriority(PRIO_PROCESS, 0 /*myself */ ,priority_level) != 0) { perror("setpriority:"); ret = EINVAL; } #elif defined(_WIN32) ssize_t pri = (priority_level + 20)/10; ssize_t subpri = ((priority_level + 20)%10)/2; switch (pri) { case 0: ret = !(SetPriorityClass(GetCurrentThread(),HIGH_PRIORITY_CLASS)); break; case 1: ret = !(SetPriorityClass(GetCurrentThread(),ABOVE_NORMAL_PRIORITY_CLASS)); break; case 2: ret = !(SetPriorityClass(GetCurrentThread(),NORMAL_PRIORITY_CLASS)); break; case 3: ret = !(SetPriorityClass(GetCurrentThread(),BELOW_NORMAL_PRIORITY_CLASS)); break; default: ret = EINVAL; } switch (pri) { case 0: ret |= !(SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_HIGHEST)); break; case 1: ret |= !(SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL)); break; case 2: ret |= !(SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL)); break; case 3: ret |= !(SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_BELOW_NORMAL)); break; case 4: ret |= !(SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_LOWEST)); break; default: ret = EINVAL; } #else // do nothing #endif if (ret!=0) perror("ff_setPriority"); return ret; } /** * \brief Returns the ID of the core * * It returns the ID of the core where the calling thread is running. It works * on Linux OS and Apple OS. * * \return An integer value showing the ID of the core. If the ID of the core * is not found, then -1 is returned. */ static inline ssize_t ff_getMyCore() { #if defined(__linux__) && defined(CPU_SET) cpu_set_t mask; CPU_ZERO(&mask); if (sched_getaffinity(ff_gettid(), sizeof(mask), &mask) != 0) { perror("sched_getaffinity"); return EINVAL; } for(int i=0;i cacheconfig(len); if (sysctlbyname("hw.cacheconfig", &cacheconfig[0], &len, NULL, 0) != 0) perror("sysctl: unable to get hw.cacheconfig"); else { /* for (size_t i=0;i #if defined(__APPLE__) //#include /** * \brief Gets cache line size in Apple systems * * It returns the size of the cache line only in Apple Systems * * \return A \size_t value, showing the size of the cache line. */ static inline size_t cache_line_size() { u_int64_t line_size = 0; size_t sizeof_line_size = sizeof(line_size); if (sysctlbyname("hw.cachelinesize", &line_size, &sizeof_line_size, NULL, 0) !=0) { perror("cachelinesize:"); line_size=0; } return line_size; } #elif defined(_WIN32) //#include //#include /** * \brief Gets cache line size in Windows systems * * It returns the size of the cache line only in Windows Systems * * \return A \size_t value, showing the size of the cache line. */ static inline size_t cache_line_size() { size_t line_size = 0; DWORD buffer_size = 0; DWORD i = 0; SYSTEM_LOGICAL_PROCESSOR_INFORMATION * buffer = 0; GetLogicalProcessorInformation(0, &buffer_size); buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)malloc(buffer_size); GetLogicalProcessorInformation(&buffer[0], &buffer_size); for (i = 0; i != buffer_size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ++i) { if (buffer[i].Relationship == RelationCache && buffer[i].Cache.Level == 1) { line_size = buffer[i].Cache.LineSize; break; } } free(buffer); return line_size; } #elif defined(__linux__) //#include /** * \brief Gets cache line size in Linux systems * * It returns the size of the cache line only in Linux Systems * * \return A \size_t value, showing the size of the cache line. */ static inline size_t cache_line_size() { FILE * p = 0; p = fopen("/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", "r"); unsigned int i = 0; if (p) { if (fscanf(p, "%ud", &i) == EOF) { perror("fscanf"); if (fclose(p) != 0) perror("fclose"); return 0; } if (fclose(p) != 0) { perror("fclose"); return 0; } } return i; } #else #error Unrecognized platform #endif #endif /* FF_MAPPING_UTILS_HPP */