Skip to content
1 change: 0 additions & 1 deletion pycpuid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
127 changes: 87 additions & 40 deletions pycpuid/_pycpuid.c
Original file line number Diff line number Diff line change
@@ -1,63 +1,110 @@
/*
Copyright (c) Bram de Greve <bram.degreve@bramz.net>
Copyright (c) Flight Data Services Ltd
Copyright (c) 2015 Michael Mohr <akihana@gmail.com>
http://www.flightdataservices.com
See the file "LICENSE" for the full license governing this code.
*/

#include <Python.h>

#ifdef _MSC_VER
# include <intrin.h>
#include <intrin.h>
#elif defined(__i386__) || defined(__x86_64__)
#include <stdio.h>
#include <sched.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <cpuid.h>
#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

29 changes: 17 additions & 12 deletions pycpuid/pycpuid.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
# -*- coding: utf-8 -*-
# Copyright (c) Bram de Greve <bram.degreve@bramz.net>
# Copyright (c) Flight Data Services Ltd
# Copyright (c) 2015 Michael Mohr <akihana@gmail.com>
# 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
Expand Down Expand Up @@ -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():
Expand Down Expand Up @@ -118,7 +122,7 @@ def features():
("AES", 2, 25),
("XSAVE", 2, 26),
("OSXSAVE", 2, 27),
]
]


def _init():
Expand All @@ -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())

15 changes: 8 additions & 7 deletions requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down