summaryrefslogtreecommitdiff
path: root/lib/spack/llnl/util/cpu/alias.py
blob: f52ecf7354ae401dc81a5a821bf3313153d6f9a9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# Copyright 2013-2019 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
#: Known predicates that can be used to construct feature aliases

from .schema import targets_json, LazyDictionary, properties

_feature_alias_predicate = {}


class FeatureAliasTest(object):
    """A test that must be passed for a feature alias to succeed.

    Args:
        rules (dict): dictionary of rules to be met. Each key must be a
            valid alias predicate
    """
    def __init__(self, rules):
        self.rules = rules
        self.predicates = []
        for name, args in rules.items():
            self.predicates.append(_feature_alias_predicate[name](args))

    def __call__(self, microarchitecture):
        return all(
            feature_test(microarchitecture) for feature_test in self.predicates
        )


def _feature_aliases():
    """Returns the dictionary of all defined feature aliases."""
    json_data = targets_json['feature_aliases']
    aliases = {}
    for alias, rules in json_data.items():
        aliases[alias] = FeatureAliasTest(rules)
    return aliases


feature_aliases = LazyDictionary(_feature_aliases)


def alias_predicate(predicate_schema):
    """Decorator to register a predicate that can be used to define
    feature aliases.

    Args:
        predicate_schema (dict): schema to be enforced in
            microarchitectures.json for the predicate
    """
    def decorator(func):
        name = func.__name__

        # Check we didn't register anything else with the same name
        if name in _feature_alias_predicate:
            msg = 'the alias predicate "{0}" already exists'.format(name)
            raise KeyError(msg)

        # Update the overall schema
        alias_schema = properties['feature_aliases']['patternProperties']
        alias_schema[r'([\w]*)']['properties'].update(
            {name: predicate_schema}
        )
        # Register the predicate
        _feature_alias_predicate[name] = func

        return func
    return decorator


@alias_predicate(predicate_schema={'type': 'string'})
def reason(motivation_for_the_alias):
    """This predicate returns always True and it's there to allow writing
    a documentation string in the JSON file to explain why an alias is needed.
    """
    return lambda x: True


@alias_predicate(predicate_schema={
    'type': 'array',
    'items': {'type': 'string'}
})
def any_of(list_of_features):
    """Returns a predicate that is True if any of the feature in the
    list is in the microarchitecture being tested, False otherwise.
    """
    def _impl(microarchitecture):
        return any(x in microarchitecture for x in list_of_features)
    return _impl


@alias_predicate(predicate_schema={
    'type': 'array',
    'items': {'type': 'string'}
})
def families(list_of_families):
    """Returns a predicate that is True if the architecture family of
    the microarchitecture being tested is in the list, False otherwise.
    """
    def _impl(microarchitecture):
        return str(microarchitecture.family) in list_of_families
    return _impl