Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

edgify / py-cpuinfo   python

Repository URL to install this package:

/ cpuinfo.py

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# Copyright (c) 2014-2020 Matthew Brennan Jones <matthew.brennan.jones@gmail.com>
# Py-cpuinfo gets CPU info with pure Python 2 & 3
# It uses the MIT License
# It is hosted at: https://github.com/workhorsy/py-cpuinfo
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

CPUINFO_VERSION = (7, 0, 0)
CPUINFO_VERSION_STRING = '.'.join([str(n) for n in CPUINFO_VERSION])

import os, sys
import platform
import multiprocessing
import ctypes


IS_PY2 = sys.version_info[0] == 2
CAN_CALL_CPUID_IN_SUBPROCESS = True


class DataSource(object):
	bits = platform.architecture()[0]
	cpu_count = multiprocessing.cpu_count()
	is_windows = platform.system().lower() == 'windows'
	arch_string_raw = platform.machine()
	uname_string_raw = platform.uname()[5]
	can_cpuid = True

	@staticmethod
	def has_proc_cpuinfo():
		return os.path.exists('/proc/cpuinfo')

	@staticmethod
	def has_dmesg():
		return len(_program_paths('dmesg')) > 0

	@staticmethod
	def has_var_run_dmesg_boot():
		uname = platform.system().strip().strip('"').strip("'").strip().lower()
		return 'linux' in uname and os.path.exists('/var/run/dmesg.boot')

	@staticmethod
	def has_cpufreq_info():
		return len(_program_paths('cpufreq-info')) > 0

	@staticmethod
	def has_sestatus():
		return len(_program_paths('sestatus')) > 0

	@staticmethod
	def has_sysctl():
		return len(_program_paths('sysctl')) > 0

	@staticmethod
	def has_isainfo():
		return len(_program_paths('isainfo')) > 0

	@staticmethod
	def has_kstat():
		return len(_program_paths('kstat')) > 0

	@staticmethod
	def has_sysinfo():
		uname = platform.system().strip().strip('"').strip("'").strip().lower()
		is_beos = 'beos' in uname or 'haiku' in uname
		return is_beos and len(_program_paths('sysinfo')) > 0

	@staticmethod
	def has_lscpu():
		return len(_program_paths('lscpu')) > 0

	@staticmethod
	def has_ibm_pa_features():
		return len(_program_paths('lsprop')) > 0

	@staticmethod
	def has_wmic():
		returncode, output = _run_and_get_stdout(['wmic', 'os', 'get', 'Version'])
		return returncode == 0 and len(output) > 0

	@staticmethod
	def cat_proc_cpuinfo():
		return _run_and_get_stdout(['cat', '/proc/cpuinfo'])

	@staticmethod
	def cpufreq_info():
		return _run_and_get_stdout(['cpufreq-info'])

	@staticmethod
	def sestatus_b():
		return _run_and_get_stdout(['sestatus', '-b'])

	@staticmethod
	def dmesg_a():
		return _run_and_get_stdout(['dmesg', '-a'])

	@staticmethod
	def cat_var_run_dmesg_boot():
		return _run_and_get_stdout(['cat', '/var/run/dmesg.boot'])

	@staticmethod
	def sysctl_machdep_cpu_hw_cpufrequency():
		return _run_and_get_stdout(['sysctl', 'machdep.cpu', 'hw.cpufrequency'])

	@staticmethod
	def isainfo_vb():
		return _run_and_get_stdout(['isainfo', '-vb'])

	@staticmethod
	def kstat_m_cpu_info():
		return _run_and_get_stdout(['kstat', '-m', 'cpu_info'])

	@staticmethod
	def sysinfo_cpu():
		return _run_and_get_stdout(['sysinfo', '-cpu'])

	@staticmethod
	def lscpu():
		return _run_and_get_stdout(['lscpu'])

	@staticmethod
	def ibm_pa_features():
		import glob

		ibm_features = glob.glob('/proc/device-tree/cpus/*/ibm,pa-features')
		if ibm_features:
			return _run_and_get_stdout(['lsprop', ibm_features[0]])

	@staticmethod
	def wmic_cpu():
		return _run_and_get_stdout(['wmic', 'cpu', 'get', 'Name,CurrentClockSpeed,L2CacheSize,L3CacheSize,Description,Caption,Manufacturer', '/format:list'])

	@staticmethod
	def winreg_processor_brand():
		processor_brand = _read_windows_registry_key(r"Hardware\Description\System\CentralProcessor\0", "ProcessorNameString")
		return processor_brand.strip()

	@staticmethod
	def winreg_vendor_id_raw():
		vendor_id_raw = _read_windows_registry_key(r"Hardware\Description\System\CentralProcessor\0", "VendorIdentifier")
		return vendor_id_raw

	@staticmethod
	def winreg_arch_string_raw():
		arch_string_raw = _read_windows_registry_key(r"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", "PROCESSOR_ARCHITECTURE")
		return arch_string_raw

	@staticmethod
	def winreg_hz_actual():
		hz_actual = _read_windows_registry_key(r"Hardware\Description\System\CentralProcessor\0", "~Mhz")
		hz_actual = _to_decimal_string(hz_actual)
		return hz_actual

	@staticmethod
	def winreg_feature_bits():
		feature_bits = _read_windows_registry_key(r"Hardware\Description\System\CentralProcessor\0", "FeatureSet")
		return feature_bits


def _program_paths(program_name):
	paths = []
	exts = filter(None, os.environ.get('PATHEXT', '').split(os.pathsep))
	path = os.environ['PATH']
	for p in os.environ['PATH'].split(os.pathsep):
		p = os.path.join(p, program_name)
		if os.access(p, os.X_OK):
			paths.append(p)
		for e in exts:
			pext = p + e
			if os.access(pext, os.X_OK):
				paths.append(pext)
	return paths

def _run_and_get_stdout(command, pipe_command=None):
	from subprocess import Popen, PIPE

	if not pipe_command:
		p1 = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
		output = p1.communicate()[0]
		if not IS_PY2:
			output = output.decode(encoding='UTF-8')
		return p1.returncode, output
	else:
		p1 = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
		p2 = Popen(pipe_command, stdin=p1.stdout, stdout=PIPE, stderr=PIPE)
		p1.stdout.close()
		output = p2.communicate()[0]
		if not IS_PY2:
			output = output.decode(encoding='UTF-8')
		return p2.returncode, output

def _read_windows_registry_key(key_name, field_name):
	try:
		import _winreg as winreg
	except ImportError as err:
		try:
			import winreg
		except ImportError as err:
			pass

	key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key_name)
	value = winreg.QueryValueEx(key, field_name)[0]
	winreg.CloseKey(key)
	return value

# Make sure we are running on a supported system
def _check_arch():
	arch, bits = _parse_arch(DataSource.arch_string_raw)
	if not arch in ['X86_32', 'X86_64', 'ARM_7', 'ARM_8', 'PPC_64', 'S390X']:
		raise Exception("py-cpuinfo currently only works on X86 and some ARM/PPC/S390X CPUs.")

def _obj_to_b64(thing):
	import pickle
	import base64

	a = thing
	b = pickle.dumps(a)
	c = base64.b64encode(b)
	d = c.decode('utf8')
	return d

def _b64_to_obj(thing):
	import pickle
	import base64

	try:
		a = base64.b64decode(thing)
		b = pickle.loads(a)
		return b
	except:
		return {}

def _utf_to_str(input):
	if IS_PY2 and isinstance(input, unicode):
		return input.encode('utf-8')
	elif isinstance(input, list):
		return [_utf_to_str(element) for element in input]
	elif isinstance(input, dict):
		return {_utf_to_str(key): _utf_to_str(value)
			for key, value in input.items()}
	else:
		return input

def _copy_new_fields(info, new_info):
	keys = [
		'vendor_id_raw', 'hardware_raw', 'brand_raw', 'hz_advertised_friendly', 'hz_actual_friendly',
		'hz_advertised', 'hz_actual', 'arch', 'bits', 'count',
		'arch_string_raw', 'uname_string_raw',
		'l2_cache_size', 'l2_cache_line_size', 'l2_cache_associativity',
		'stepping', 'model', 'family',
		'processor_type', 'flags',
		'l3_cache_size', 'l1_data_cache_size', 'l1_instruction_cache_size'
	]

	for key in keys:
		if new_info.get(key, None) and not info.get(key, None):
			info[key] = new_info[key]
		elif key == 'flags' and new_info.get('flags'):
			for f in new_info['flags']:
				if f not in info['flags']: info['flags'].append(f)
			info['flags'].sort()

def _get_field_actual(cant_be_number, raw_string, field_names):
	for line in raw_string.splitlines():
		for field_name in field_names:
			field_name = field_name.lower()
			if ':' in line:
				left, right = line.split(':', 1)
				left = left.strip().lower()
				right = right.strip()
				if left == field_name and len(right) > 0:
					if cant_be_number:
						if not right.isdigit():
							return right
					else:
						return right

	return None

def _get_field(cant_be_number, raw_string, convert_to, default_value, *field_names):
	retval = _get_field_actual(cant_be_number, raw_string, field_names)

	# Convert the return value
	if retval and convert_to:
		try:
			retval = convert_to(retval)
		except:
			retval = default_value

	# Return the default if there is no return value
	if retval is None:
		retval = default_value

	return retval

def _to_decimal_string(ticks):
	try:
		# Convert to string
		ticks = '{0}'.format(ticks)

		# Strip off non numbers and decimal places
		ticks = "".join(n for n in ticks if n.isdigit() or n=='.').strip()
		if ticks == '':
			ticks = '0'

		# Add decimal if missing
		if '.' not in ticks:
			ticks = '{0}.0'.format(ticks)

		# Remove trailing zeros
		ticks = ticks.rstrip('0')

		# Add one trailing zero for empty right side
		if ticks.endswith('.'):
			ticks = '{0}0'.format(ticks)

		# Make sure the number can be converted to a float
		ticks = float(ticks)
		ticks = '{0}'.format(ticks)
		return ticks
	except:
		return '0.0'

def _hz_short_to_full(ticks, scale):
	try:
Loading ...