organize os_traits for the future
Sean Mooney had a good idea that for future-proofing the os-traits library and ensuring that we don't have to deal with one giant const.py file, that we break the library into various modules corresponding to the higher-level namespaces. This patch adds some symbol-registration foo into a utils module and allows the os_traits module and "leaf modules" to be called in the following way: import os_traits from os_traits.hw.cpu import x86 assert os_traits.HW_CPU_X86_SSE42 == x86.SSE42 assert x86.SSE42 == 'HW_CPU_X86_SSE42' Change-Id: I0e8f50822ab67cb3be85ed3b935dd6cdb4436dbf
This commit is contained in:
parent
9e6b7c1aba
commit
23d81d4451
@ -20,8 +20,12 @@ import six
|
|||||||
__version__ = pbr.version.VersionInfo(
|
__version__ = pbr.version.VersionInfo(
|
||||||
'os_traits').version_string()
|
'os_traits').version_string()
|
||||||
|
|
||||||
# Conveniently import all the constants into the main module "namespace"
|
# Any user-specified feature/trait is prefixed with the custom namespace
|
||||||
from os_traits.const import * # noqa
|
CUSTOM_NAMESPACE = 'CUSTOM_'
|
||||||
|
|
||||||
|
# Each submodule registers its symbols with the os_traits module namespace
|
||||||
|
from os_traits.hw.cpu import x86 # noqa
|
||||||
|
from os_traits.storage import disk # noqa
|
||||||
|
|
||||||
|
|
||||||
def get_symbol_names(prefix=None):
|
def get_symbol_names(prefix=None):
|
||||||
@ -30,15 +34,10 @@ def get_symbol_names(prefix=None):
|
|||||||
|
|
||||||
:param prefix: Optional string prefix to filter by. e.g. 'HW_'
|
:param prefix: Optional string prefix to filter by. e.g. 'HW_'
|
||||||
"""
|
"""
|
||||||
excluded_keys = ('NAMESPACES',)
|
|
||||||
excluded_values = NAMESPACES.values()
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
k for k, v in sys.modules[__name__].__dict__.items()
|
k for k, v in sys.modules[__name__].__dict__.items()
|
||||||
if isinstance(v, six.string_types) and
|
if isinstance(v, six.string_types) and
|
||||||
not k.startswith('_') and
|
not k.startswith('_') and
|
||||||
k not in excluded_keys and
|
|
||||||
v not in excluded_values and
|
|
||||||
(prefix is None or v.startswith(prefix))
|
(prefix is None or v.startswith(prefix))
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -49,15 +48,10 @@ def get_traits(prefix=None):
|
|||||||
|
|
||||||
:param prefix: Optional string prefix to filter by. e.g. 'HW_'
|
:param prefix: Optional string prefix to filter by. e.g. 'HW_'
|
||||||
"""
|
"""
|
||||||
excluded_keys = ('NAMESPACES',)
|
|
||||||
excluded_values = NAMESPACES.values()
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
v for k, v in sys.modules[__name__].__dict__.items()
|
v for k, v in sys.modules[__name__].__dict__.items()
|
||||||
if isinstance(v, six.string_types) and
|
if isinstance(v, six.string_types) and
|
||||||
not k.startswith('_') and
|
not k.startswith('_') and
|
||||||
k not in excluded_keys and
|
|
||||||
v not in excluded_values and
|
|
||||||
(prefix is None or v.startswith(prefix))
|
(prefix is None or v.startswith(prefix))
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -82,4 +76,4 @@ def is_custom(trait):
|
|||||||
|
|
||||||
:param trait: String name of the trait
|
:param trait: String name of the trait
|
||||||
"""
|
"""
|
||||||
return trait.startswith(NAMESPACES['CUSTOM'])
|
return trait.startswith(CUSTOM_NAMESPACE)
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
# Any user-specified feature/trait is prefixed with the custom namespace
|
|
||||||
_CUSTOM_NS = 'CUSTOM_'
|
|
||||||
|
|
||||||
# All hardware-specific features are prefixed with this namespace
|
|
||||||
_HW_NS = 'HW_'
|
|
||||||
|
|
||||||
# All CPU-specific features are prefixed with this namespace
|
|
||||||
_CPU_NS = _HW_NS + 'CPU_'
|
|
||||||
|
|
||||||
_CPU_X86_NS = _CPU_NS + 'X86_'
|
|
||||||
|
|
||||||
# ref: https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions
|
|
||||||
HW_CPU_X86_AVX = _CPU_X86_NS + 'AVX'
|
|
||||||
HW_CPU_X86_AVX2 = _CPU_X86_NS + 'AVX2'
|
|
||||||
HW_CPU_X86_CLMUL = _CPU_X86_NS + 'CLMUL'
|
|
||||||
HW_CPU_X86_FMA3 = _CPU_X86_NS + 'FMA3'
|
|
||||||
HW_CPU_X86_FMA4 = _CPU_X86_NS + 'FMA4'
|
|
||||||
HW_CPU_X86_F16C = _CPU_X86_NS + 'F16C'
|
|
||||||
HW_CPU_X86_MMX = _CPU_X86_NS + 'MMX'
|
|
||||||
HW_CPU_X86_SSE = _CPU_X86_NS + 'SSE'
|
|
||||||
HW_CPU_X86_SSE2 = _CPU_X86_NS + 'SSE2'
|
|
||||||
HW_CPU_X86_SSE3 = _CPU_X86_NS + 'SSE3'
|
|
||||||
HW_CPU_X86_SSSE3 = _CPU_X86_NS + 'SSSE3'
|
|
||||||
HW_CPU_X86_SSE41 = _CPU_X86_NS + 'SSE41'
|
|
||||||
HW_CPU_X86_SSE42 = _CPU_X86_NS + 'SSE42'
|
|
||||||
HW_CPU_X86_SSE4A = _CPU_X86_NS + 'SSE4A'
|
|
||||||
HW_CPU_X86_XOP = _CPU_X86_NS + 'XOP'
|
|
||||||
HW_CPU_X86_3DNOW = _CPU_X86_NS + '3DNOW'
|
|
||||||
# ref: https://en.wikipedia.org/wiki/AVX-512
|
|
||||||
HW_CPU_X86_AVX512F = _CPU_X86_NS + 'AVX512F' # foundation
|
|
||||||
HW_CPU_X86_AVX512CD = _CPU_X86_NS + 'AVX512CD' # conflict detection
|
|
||||||
HW_CPU_X86_AVX512PF = _CPU_X86_NS + 'AVX512PF' # prefetch
|
|
||||||
HW_CPU_X86_AVX512ER = _CPU_X86_NS + 'AVX512ER' # exponential + reciprocal
|
|
||||||
HW_CPU_X86_AVX512VL = _CPU_X86_NS + 'AVX512VL' # vector length extensions
|
|
||||||
HW_CPU_X86_AVX512BW = _CPU_X86_NS + 'AVX512BW' # byte + word
|
|
||||||
HW_CPU_X86_AVX512DQ = _CPU_X86_NS + 'AVX512DQ' # double word + quad word
|
|
||||||
# ref: https://en.wikipedia.org/wiki/Bit_Manipulation_Instruction_Sets
|
|
||||||
HW_CPU_X86_ABM = _CPU_X86_NS + 'ABM'
|
|
||||||
HW_CPU_X86_BMI = _CPU_X86_NS + 'BMI'
|
|
||||||
HW_CPU_X86_BMI2 = _CPU_X86_NS + 'BMI2'
|
|
||||||
HW_CPU_X86_TBM = _CPU_X86_NS + 'TBM'
|
|
||||||
# ref: https://en.wikipedia.org/wiki/AES_instruction_set
|
|
||||||
HW_CPU_X86_AESNI = _CPU_X86_NS + 'AES-NI'
|
|
||||||
# ref: https://en.wikipedia.org/wiki/Intel_SHA_extensions
|
|
||||||
HW_CPU_X86_SHA = _CPU_X86_NS + 'SHA'
|
|
||||||
# ref: https://en.wikipedia.org/wiki/Intel_MPX
|
|
||||||
HW_CPU_X86_MPX = _CPU_X86_NS + 'MPX'
|
|
||||||
# ref: https://en.wikipedia.org/wiki/Software_Guard_Extensions
|
|
||||||
HW_CPU_X86_SGX = _CPU_X86_NS + 'SGX'
|
|
||||||
# ref: https://en.wikipedia.org/wiki/Transactional_Synchronization_Extensions
|
|
||||||
HW_CPU_X86_TSX = _CPU_X86_NS + 'TSX'
|
|
||||||
# ref: https://en.wikipedia.org/wiki/Advanced_Synchronization_Facility
|
|
||||||
HW_CPU_X86_ASF = _CPU_X86_NS + 'ASF'
|
|
||||||
# ref: https://en.wikipedia.org/wiki/VT-x
|
|
||||||
HW_CPU_X86_VMX = _CPU_X86_NS + 'VMX'
|
|
||||||
# ref: https://en.wikipedia.org/wiki/AMD-V
|
|
||||||
HW_CPU_X86_SVM = _CPU_X86_NS + 'SVM'
|
|
||||||
|
|
||||||
# All storage-specific features are prefixed with this namespace
|
|
||||||
_STORAGE_NS = 'STORAGE_'
|
|
||||||
|
|
||||||
# All disk storage-specific features are prefixed with this namespace (as
|
|
||||||
# opposed to object storage)
|
|
||||||
_DISK_NS = _STORAGE_NS + 'DISK_'
|
|
||||||
|
|
||||||
STORAGE_DISK_HDD = _DISK_NS + 'HDD' # spinning oxide
|
|
||||||
STORAGE_DISK_SSD = _DISK_NS + 'SSD' # solid-state disks
|
|
||||||
|
|
||||||
NAMESPACES = {
|
|
||||||
'CUSTOM': _CUSTOM_NS,
|
|
||||||
'HARDWARE': _HW_NS,
|
|
||||||
'HW': _HW_NS,
|
|
||||||
'CPU': _CPU_NS,
|
|
||||||
'X86': _CPU_X86_NS,
|
|
||||||
'STORAGE': _STORAGE_NS,
|
|
||||||
'DISK': _DISK_NS,
|
|
||||||
}
|
|
0
os_traits/hw/__init__.py
Normal file
0
os_traits/hw/__init__.py
Normal file
0
os_traits/hw/cpu/__init__.py
Normal file
0
os_traits/hw/cpu/__init__.py
Normal file
64
os_traits/hw/cpu/x86.py
Normal file
64
os_traits/hw/cpu/x86.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from os_traits import utils
|
||||||
|
|
||||||
|
register = utils.register_fn(__name__)
|
||||||
|
|
||||||
|
# ref: https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions
|
||||||
|
register('AVX')
|
||||||
|
register('AVX2')
|
||||||
|
register('CLMUL')
|
||||||
|
register('FMA3')
|
||||||
|
register('FMA4')
|
||||||
|
register('F16C')
|
||||||
|
register('MMX')
|
||||||
|
register('SSE')
|
||||||
|
register('SSE2')
|
||||||
|
register('SSE3')
|
||||||
|
register('SSSE3')
|
||||||
|
register('SSE41')
|
||||||
|
register('SSE42')
|
||||||
|
register('SSE4A')
|
||||||
|
register('XOP')
|
||||||
|
register('3DNOW')
|
||||||
|
# ref: https://en.wikipedia.org/wiki/AVX-512
|
||||||
|
register('AVX512F') # foundation
|
||||||
|
register('AVX512CD') # conflict detection
|
||||||
|
register('AVX512PF') # prefetch
|
||||||
|
register('AVX512ER') # exponential + reciprocal
|
||||||
|
register('AVX512VL') # vector length extensions
|
||||||
|
register('AVX512BW') # byte + word
|
||||||
|
register('AVX512DQ') # double word + quad word
|
||||||
|
# ref: https://en.wikipedia.org/wiki/Bit_Manipulation_Instruction_Sets
|
||||||
|
register('ABM')
|
||||||
|
register('BMI')
|
||||||
|
register('BMI2')
|
||||||
|
register('TBM')
|
||||||
|
# ref: https://en.wikipedia.org/wiki/AES_instruction_set
|
||||||
|
register('AES-NI')
|
||||||
|
# ref: https://en.wikipedia.org/wiki/Intel_SHA_extensions
|
||||||
|
register('SHA')
|
||||||
|
# ref: https://en.wikipedia.org/wiki/Intel_MPX
|
||||||
|
register('MPX')
|
||||||
|
# ref: https://en.wikipedia.org/wiki/Software_Guard_Extensions
|
||||||
|
register('SGX')
|
||||||
|
# ref: https://en.wikipedia.org/wiki/Transactional_Synchronization_Extensions
|
||||||
|
register('TSX')
|
||||||
|
# ref: https://en.wikipedia.org/wiki/Advanced_Synchronization_Facility
|
||||||
|
register('ASF')
|
||||||
|
# ref: https://en.wikipedia.org/wiki/VT-x
|
||||||
|
register('VMX')
|
||||||
|
# ref: https://en.wikipedia.org/wiki/AMD-V
|
||||||
|
register('SVM')
|
0
os_traits/storage/__init__.py
Normal file
0
os_traits/storage/__init__.py
Normal file
21
os_traits/storage/disk.py
Normal file
21
os_traits/storage/disk.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
from os_traits import utils
|
||||||
|
|
||||||
|
register = utils.register_fn(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
register('HDD') # spinning oxide
|
||||||
|
register('SSD') # solid-state disks
|
@ -12,37 +12,33 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
"""
|
|
||||||
test_os_traits
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
Tests for `os_traits` module.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os_traits as ot
|
import os_traits as ot
|
||||||
|
from os_traits.hw.cpu import x86
|
||||||
from os_traits.tests import base
|
from os_traits.tests import base
|
||||||
|
|
||||||
|
|
||||||
class TestOs_traits(base.TestCase):
|
class TestSymbols(base.TestCase):
|
||||||
|
|
||||||
def test_trait(self):
|
def test_trait(self):
|
||||||
|
"""Simply tests that the constants from submodules are imported into
|
||||||
|
the primary os_traits module space.
|
||||||
|
"""
|
||||||
trait = ot.HW_CPU_X86_SSE42
|
trait = ot.HW_CPU_X86_SSE42
|
||||||
self.assertEqual("HW_CPU_X86_SSE42", trait)
|
self.assertEqual("HW_CPU_X86_SSE42", trait)
|
||||||
|
|
||||||
|
# And the "leaf-module" namespace...
|
||||||
|
self.assertEqual(x86.SSE42, ot.HW_CPU_X86_SSE42)
|
||||||
|
|
||||||
def test_get_symbol_names(self):
|
def test_get_symbol_names(self):
|
||||||
names = ot.get_symbol_names()
|
names = ot.get_symbol_names()
|
||||||
self.assertIn("HW_CPU_X86_AVX2", names)
|
self.assertIn("HW_CPU_X86_AVX2", names)
|
||||||
self.assertIn("STORAGE_DISK_SSD", names)
|
self.assertIn("STORAGE_DISK_SSD", names)
|
||||||
|
|
||||||
def test_namespaces(self):
|
|
||||||
namespaces = ot.NAMESPACES
|
|
||||||
self.assertIn(("HARDWARE", "HW_"), namespaces.items())
|
|
||||||
self.assertEqual(7, len(namespaces))
|
|
||||||
|
|
||||||
def test_get_traits(self):
|
def test_get_traits(self):
|
||||||
traits = ot.get_traits(ot.NAMESPACES['X86'])
|
traits = ot.get_traits('HW_CPU')
|
||||||
self.assertIn("HW_CPU_X86_SSE42", traits)
|
self.assertIn("HW_CPU_X86_SSE42", traits)
|
||||||
self.assertEqual(35, len(traits))
|
self.assertIn(ot.HW_CPU_X86_AVX2, traits)
|
||||||
|
self.assertNotIn(ot.STORAGE_DISK_SSD, traits)
|
||||||
|
|
||||||
def test_check_traits(self):
|
def test_check_traits(self):
|
||||||
traits = set(["HW_CPU_X86_SSE42", "HW_CPU_X86_XOP"])
|
traits = set(["HW_CPU_X86_SSE42", "HW_CPU_X86_XOP"])
|
||||||
|
56
os_traits/utils.py
Normal file
56
os_traits/utils.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import os_traits
|
||||||
|
|
||||||
|
|
||||||
|
def symbolize(mod_name, name):
|
||||||
|
"""Given a reference to a Python module object and a short string name for
|
||||||
|
a trait, registers a symbol in the module that corresponds to the full
|
||||||
|
namespaced trait name.
|
||||||
|
|
||||||
|
For example, if called like so:
|
||||||
|
|
||||||
|
:code:
|
||||||
|
|
||||||
|
# In file /os_traits/hw/cpu/x86.py
|
||||||
|
|
||||||
|
import functools
|
||||||
|
|
||||||
|
from os_traits import utils
|
||||||
|
|
||||||
|
mod_register = functools.partial(utils.symbolize, __name__)
|
||||||
|
|
||||||
|
mod_register('AVX2')
|
||||||
|
mod_register('SSE')
|
||||||
|
|
||||||
|
Would end up creating the following symbols:
|
||||||
|
|
||||||
|
os_traits.hw.cpu.x86.AVX2 with the value of 'HW_CPU_X86_AVX2'
|
||||||
|
os_traits.hw.cpu.x86.SSE with the value of 'HW_CPU_X86_SSE'
|
||||||
|
os_traits.HW_CPU_X86_AVX2 with the value of 'HW_CPU_X86_AVX2'
|
||||||
|
os_traits.HW_CPU_X86_SSE with the value of 'HW_CPU_X86_SSE'
|
||||||
|
"""
|
||||||
|
leaf_mod = sys.modules[mod_name]
|
||||||
|
value_base = '_'.join([m.upper() for m in mod_name.split('.')[1:]])
|
||||||
|
value = value_base + '_' + name.upper()
|
||||||
|
setattr(os_traits, value, value) # os_traits.HW_CPU_X86_SSE
|
||||||
|
setattr(leaf_mod, name.upper(), value) # os_traits.hw.cpu.x86.SSE
|
||||||
|
|
||||||
|
|
||||||
|
def register_fn(mod_name):
|
||||||
|
return functools.partial(symbolize, mod_name)
|
Loading…
Reference in New Issue
Block a user