diff --git a/pycpuid/__init__.py b/pycpuid/__init__.py index c5e4d5e..86bb0ee 100644 --- a/pycpuid/__init__.py +++ b/pycpuid/__init__.py @@ -27,7 +27,6 @@ 'Environment :: Console', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', - 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: Implementation :: CPython', diff --git a/pycpuid/_pycpuid.c b/pycpuid/_pycpuid.c index 757d1b8..1a81320 100644 --- a/pycpuid/_pycpuid.c +++ b/pycpuid/_pycpuid.c @@ -1,6 +1,7 @@ /* Copyright (c) Bram de Greve Copyright (c) Flight Data Services Ltd +Copyright (c) 2015 Michael Mohr http://www.flightdataservices.com See the file "LICENSE" for the full license governing this code. */ @@ -8,56 +9,102 @@ See the file "LICENSE" for the full license governing this code. #include #ifdef _MSC_VER -# include +#include +#elif defined(__i386__) || defined(__x86_64__) +#include +#include +#include +#include +#include #endif +static PyObject *_pycpuid_cpuid(PyObject* module, PyObject* args) { + #if defined(__i386__) || defined(__x86_64__) + pid_t pid; + cpu_set_t saved, target; + int affinity_ret, cpuid_ret; + #endif + int cpu_num = 0; + unsigned int level = 0; + unsigned int info[4] = { 0 }; + if(!PyArg_ParseTuple(args, "I|i", &level, &cpu_num)) + return NULL; -static PyObject* _pycpuid_cpuid(PyObject* module, PyObject* args) -{ - unsigned cpuinfo[4] = { 0 }; - unsigned infotype; - if (!PyArg_ParseTuple(args, "I:cpuid", &infotype)) - { - return 0; - } -#ifdef _MSC_VER - __cpuid(cpuinfo, infotype); -#else - // cpuid and PIC mode don't play nice. Push ebx before use! - // see http://www.technovelty.org/code/arch/pic-cas.html - - // Flight Data Services couldn't get this to build on 64-bit. - // See http://code.google.com/p/pycpuid/source/browse/release-0.1/cpuid/cpuid.c -# ifdef __x86_64__ - __asm__ __volatile__( - "cpuid;" - : "=a"(cpuinfo[0]), "=b"(cpuinfo[1]), "=c"(cpuinfo[2]), "=d"(cpuinfo[3]) - : "a"(infotype)); -# else - __asm__ __volatile__( - "pushl %%ebx;" - "cpuid;" - "movl %%ebx,%1;" - "pop %%ebx;" - : "=a"(cpuinfo[0]), "=m"(cpuinfo[1]), "=c"(cpuinfo[2]), "=d"(cpuinfo[3]) - : "a"(infotype)); -# endif -#endif - return Py_BuildValue("IIII", cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]); + #ifdef _MSC_VER + + /* Handling CPU affinity on Windows is not supported. Patches welcome. */ + __cpuid(info, level); + return Py_BuildValue("(IIII)", info[0], info[1], info[2], info[3]); + + #elif defined(__i386__) || defined(__x86_64__) + + pid = syscall(__NR_gettid); + if(sched_getaffinity(pid, sizeof(cpu_set_t), &saved) != 0) { + PyErr_SetString(PyExc_RuntimeError, "Unable to get CPU affinity"); + return NULL; + } + + CPU_ZERO(&target); + CPU_SET(cpu_num, &target); + if(sched_setaffinity(pid, sizeof(cpu_set_t), &target) != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + cpuid_ret = __get_cpuid(level, &info[0], &info[1], &info[2], &info[3]); + affinity_ret = sched_setaffinity(pid, sizeof(cpu_set_t), &saved); + + if(cpuid_ret != 1) { + PyErr_SetString(PyExc_RuntimeError, "CPUID level not supported"); + return NULL; + } + + if(affinity_ret != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + + return Py_BuildValue("(IIII)", info[0], info[1], info[2], info[3]); + #else + PyErr_SetString(PyExc_NotImplementedError, "CPUID is only supported on x86"); + return NULL; + #endif } +static PyMethodDef _pycpuid_methods[] = { + { "cpuid", _pycpuid_cpuid, METH_VARARGS, "cpuid(eax) -> (eax, ebx, ecx, edx)"}, + { NULL, NULL, 0, NULL}, +}; +#if PY_MAJOR_VERSION >= 3 -static PyMethodDef _pycpuid_methods[] = -{ - { "cpuid", _pycpuid_cpuid, METH_VARARGS, "cpuid(eax) -> (eax, ebx, ecx, edx)"}, - { 0, 0, 0, 0 }, +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "_pycpuid", /* m_name */ + "CPUID info", /* m_doc */ + -1, /* m_size */ + _pycpuid_methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ }; +PyMODINIT_FUNC PyInit__pycpuid(void) { + PyObject *m; + m = PyModule_Create(&moduledef); + if(m == NULL) + return NULL; + return m; +} -PyMODINIT_FUNC init_pycpuid(void) -{ - Py_InitModule("_pycpuid", _pycpuid_methods); +#else + +PyMODINIT_FUNC init_pycpuid(void) { + (void)Py_InitModule3("_pycpuid", _pycpuid_methods, "CPUID info"); } + +#endif + diff --git a/pycpuid/pycpuid.py b/pycpuid/pycpuid.py index 46f6f03..63b8a02 100644 --- a/pycpuid/pycpuid.py +++ b/pycpuid/pycpuid.py @@ -2,9 +2,12 @@ # -*- coding: utf-8 -*- # Copyright (c) Bram de Greve # Copyright (c) Flight Data Services Ltd +# Copyright (c) 2015 Michael Mohr # http://www.flightdataservices.com # See the file "LICENSE" for the full license governing this code. +from __future__ import print_function + import sys import _pycpuid import struct as _struct @@ -52,9 +55,10 @@ def brand_id(): def brand_string(): a = cpuid(EXTENDED_OFFSET) - assert a >= (EXTENDED_OFFSET | 0x4), "brand string is not supported by this CPU" - s = ''.join([_struct.pack("IIII", *cpuid(EXTENDED_OFFSET | k)) for k in 0x2, 0x3, 0x4]) - return s[:s.index('\0')] + if a[0] < (EXTENDED_OFFSET | 0x4): + raise NotImplementedError("Brand string is not supported by this CPU") + segments = [_struct.pack("IIII", *cpuid(EXTENDED_OFFSET | k)) for k in (0x2, 0x3, 0x4)] + return ''.join([s.decode('utf-8').strip('\0') for s in segments]) def features(): @@ -118,7 +122,7 @@ def features(): ("AES", 2, 25), ("XSAVE", 2, 26), ("OSXSAVE", 2, 27), - ] +] def _init(): @@ -134,11 +138,12 @@ def _init(): _init() if __name__ == "__main__": - print "Vendor:", vendor() - print "Stepping ID:", stepping_id() - print "Model:", hex(model()) - print "Family:", family() - print "Processor Type:", processor_type() - print "Brand ID:", hex(brand_id()) - print "Brand String:", brand_string() - print "Features:", features() + print("Vendor:", vendor()) + print("Stepping ID:", stepping_id()) + print("Model:", hex(model())) + print("Family:", family()) + print("Processor Type:", processor_type()) + print("Brand ID:", hex(brand_id())) + print("Brand String:", brand_string()) + print("Features:", features()) + diff --git a/requirements.py b/requirements.py index bf5a8a2..0ce6444 100644 --- a/requirements.py +++ b/requirements.py @@ -146,7 +146,7 @@ def _split_package(package): if not matches: return None components = list(matches.groups()) - components = map(lambda x: '' if x is None else x.strip(), components) + components = list(map(lambda x: '' if x is None else x.strip(), components)) if components[-1]: components[-1] = sorted(map(str.strip, components[-1].split(','))) else: @@ -310,7 +310,7 @@ def __init__(self, path='', name='requirements', extn='txt'): filename = _build_filename(path, '%s.%s', 'dependency_links', 'txt') if os.path.isfile(filename): lines = open(filename, 'r').read().splitlines() - self.links = map(str.strip, lines) + self.links = list(map(str.strip, lines)) paths = [] paths += [_build_filename(path, '%s.%s', name, extn)] @@ -352,7 +352,7 @@ def install_requires(self): data = self.data['*'] install_requires = [] install_requires += data.get('p', []) - install_requires += map(_extract_egg_names, data.get('e', [])) + install_requires += list(map(_extract_egg_names, data.get('e', []))) return sorted(list(set(install_requires))) @property @@ -368,7 +368,7 @@ def setup_requires(self): data = self.data['setup'] setup_requires = [] setup_requires += data.get('p', []) - setup_requires += map(_extract_egg_names, data.get('e', [])) + setup_requires += list(map(_extract_egg_names, data.get('e', []))) return sorted(list(set(setup_requires))) @property @@ -384,7 +384,7 @@ def tests_require(self): data = self.data['tests'] tests_require = [] tests_require += data.get('p', []) - tests_require += map(_extract_egg_names, data.get('e', [])) + tests_require += list(map(_extract_egg_names, data.get('e', []))) return sorted(list(set(tests_require))) @property @@ -396,12 +396,13 @@ def extras_require(self): :rtype: dict ''' extras_require = {} - for source, data in self.data.iteritems(): + for source in self.data.keys(): + data = self.data[source] if source == '*': continue packages = [] packages += data.get('p') - packages += map(_extract_egg_names, data.get('e', [])) + packages += list(map(_extract_egg_names, data.get('e', []))) packages = sorted(list(set(packages))) if packages: extras_require[source] = packages