// -*- C++ -*- /* Heap Layers: An Extensible Memory Allocation Infrastructure Copyright (C) 2000-2003 by Emery Berger http://www.cs.umass.edu/~emery emery@cs.umass.edu This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU 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 */ #ifndef HL_CPUINFO_H #define HL_CPUINFO_H #if defined(_WIN32) #include #include #else #include #endif #if !defined(_WIN32) #include #endif #if defined(__SVR4) // Solaris #include extern "C" unsigned int lwp_self(void); #include extern "C" int _thr_self(void); #endif #if defined(__linux) #include #include #include #include #include #endif #if defined(__APPLE__) #include #include #endif #if defined(__sgi) #include #include #include #endif #if defined(hpux) #include #endif #if defined(_WIN32) extern __declspec(thread) int localThreadId; #endif #if defined(__SVR4) && defined(MAP_ALIGN) extern volatile int anyThreadStackCreated; #endif namespace HL { /** * @class CPUInfo * @author Emery Berger * * @brief Architecture-independent wrapper to get number of CPUs. */ class CPUInfo { public: CPUInfo (void) {} inline static int getNumProcessors (void) { static int _numProcessors = computeNumProcessors(); return _numProcessors; } static inline unsigned long getThreadId (void); inline static int computeNumProcessors (void); }; int CPUInfo::computeNumProcessors (void) { static int np = 0; if (!np) { #if defined(__linux) || defined(__APPLE__) np = (int) sysconf(_SC_NPROCESSORS_ONLN); #elif defined(_WIN32) SYSTEM_INFO infoReturn[1]; GetSystemInfo (infoReturn); np = (int) (infoReturn->dwNumberOfProcessors); #elif defined(__sgi) np = (int) sysmp(MP_NAPROCS); #elif defined(hpux) np = mpctl(MPC_GETNUMSPUS, NULL, NULL); // or pthread_num_processors_np()? #elif defined(_SC_NPROCESSORS_ONLN) np = (int) (sysconf(_SC_NPROCESSORS_ONLN)); #else np = 2; // Unsupported platform. // Pretend we have at least two processors. This approach avoids the risk of assuming // we're on a uniprocessor, which might lead clever allocators to avoid using atomic // operations for all locks. #endif return np; } else { return np; } } // Note: when stacksize arg is NULL for pthread_attr_setstacksize [Solaris], // stack size is 1 MB for 32-bit arch, 2 MB for 64-bit arch. // pthread_attr_getstacksize // pthread_attr_setstackaddr // pthread_attr_getstackaddr // PTHREAD_STACK_SIZE is minimum. // or should we just assume we have __declspec(thread) or __thread? #if defined(USE_THREAD_KEYWORD) extern __thread int localThreadId; #endif // FIX ME FIXME //#include unsigned long CPUInfo::getThreadId (void) { #if defined(__SVR4) size_t THREAD_STACK_SIZE; if (sizeof(size_t) <= 4) { THREAD_STACK_SIZE = 1048576; } else { // 64-bits. THREAD_STACK_SIZE = 1048576 * 2; } if (0) { // !anyThreadStackCreated) { // We know a priori that all stack variables // are on different stacks. Since no one has created // a special one, we are in control, and thus all stacks // are 1 MB in size and on 1 MB boundaries. // (Actually: 1 MB for 32-bits, 2 MB for 64-bits.) char buf; return (((size_t) &buf) & ~(THREAD_STACK_SIZE-1)) >> 20; } else { return (int) pthread_self(); } #elif defined(_WIN32) // It looks like thread id's are always multiples of 4, so... return GetCurrentThreadId() >> 2; #elif defined(__APPLE__) // Consecutive thread id's in Mac OS are 4096 apart; // dividing off the 4096 gives us an appropriate thread id. int tid = (int) ((unsigned long) pthread_self()) >> 12; return tid; #elif defined(__BEOS__) return find_thread(0); #elif defined(USE_THREAD_KEYWORD) return localThreadId; #elif defined(__linux) || defined(PTHREAD_KEYS_MAX) // Consecutive thread id's in Linux are 1024 apart; // dividing off the 1024 gives us an appropriate thread id. return (unsigned long) pthread_self() >> 10; #elif defined(POSIX) return (unsigned long) pthread_self(); #elif USE_SPROC // This hairiness has the same effect as calling getpid(), // but it's MUCH faster since it avoids making a system call // and just accesses the sproc-local data directly. unsigned long pid = (unsigned long) PRDA->sys_prda.prda_sys.t_pid; return pid; #else return 0; #endif } } #endif