Whamcloud - gitweb
LU-12461 contrib: Add epython scripts for crash dump analysis
[fs/lustre-release.git] / contrib / debug_tools / epython_scripts / crashlib / input / enumtools.py
diff --git a/contrib/debug_tools/epython_scripts/crashlib/input/enumtools.py b/contrib/debug_tools/epython_scripts/crashlib/input/enumtools.py
new file mode 100644 (file)
index 0000000..f9373c9
--- /dev/null
@@ -0,0 +1,211 @@
+
+"""
+Routines for handling enums (or other symbolic names)
+Copyright 2015 Cray Inc.  All Rights Reserved
+"""
+
+import uflookup
+
+class NameSet:
+    """Two-way translation between int values (enums, #defines) and strings.
+    Also provides access to value by e.g.:
+    vms = NameSet()  # vmstat nameset
+    vms.AddName("NR_FILE_MAPPED", 8)
+    vms.NR_FILE_MAPPED == 8
+
+    The advantages over just using a dict include:
+
+    * Define the values once, and get value->string, string->value,
+      and python identifier ns.<name> as above.
+    * The auto-incrementing _next_value
+      """
+
+    def __init__(self, mapping=None):
+        """Create and initialize a NameSet object
+
+        Arguments:
+            mapping:    if specified, provides a mapping object, e.g. dict,
+                        that supplies the initial key(name)/value pairs.
+        """
+        self.value_to_name = {}
+        self.name_to_value = {}
+
+        self._next_value = 0
+#        self._sorted_values = []
+#        self._sorted_names = []
+
+        if mapping is not None:
+            self.addMap(mapping)
+
+    def addName(self, name, value=None):
+        """Add a single name, by default using the next value.
+
+        If two names end up with the same value, the value will map
+        only to the first of them.
+        """
+
+        if name in self.name_to_value.keys():
+            raise ValueError("Name {0} already defined (value {1})".format(
+                name, self.name_to_value[name]))
+        try:
+            getattr(self, name)
+        except AttributeError:
+            pass
+        else:
+            raise ValueError("Value {0} already used by NameSet object!".
+                             format(value))
+
+        if value is None:
+            value = self._next_value
+        self._next_value = value + 1
+
+        self.name_to_value[name] = value
+        if value not in self.value_to_name:
+            self.value_to_name[value] = name
+ #       self._sorted_values = []
+ #       self._sorted_names = []
+
+        setattr(self, name, value)
+
+    def addNames(self, *namelist):
+        """Add a list of names, each using the respective next value"""
+        map(self.addName, namelist)
+
+    def addMap(self, mapping):
+        """Add the key/value pairs from a mapping type"""
+        for k, v in mapping.items():
+            self.addName(k, v)
+
+    def UFLookup(self, key, **kwargs):
+        return uflookup.UFLookup(self.name_to_value, key, **kwargs)
+
+#    def somethingUsingSortedArrays:
+#        if not self._sorted_values:
+#            self._sorted_values = sorted(self.value_to_name.keys())
+#            self._sorted_names = sorted(self.name_to_value.keys())
+
+
+
+if __name__ == '__main__':
+    import unittest
+
+    class Test_NameSet(unittest.TestCase):
+        """Test the NameSet class"""
+
+        def VerifyName(self, name, value):
+            """Verify that self.ns has name <-> value"""
+            self.assertEqual(value, self.ns.name_to_value[name])
+            self.assertEqual(value, getattr(self.ns, name))
+            self.assertEqual(name, self.ns.value_to_name[value])
+
+    class Test_Empty(Test_NameSet):
+        """Test an empty NameSet"""
+        def setUp(self):
+            self.ns = NameSet()
+
+        def test_empty_vtn(self):
+            self.assertEqual(0, len(self.ns.value_to_name))
+        def test_empty_ntv(self):
+            self.assertEqual(0, len(self.ns.name_to_value))
+
+
+    class Test_addName(Test_NameSet):
+        """Test addName"""
+        def setUp(self):
+            self.ns = NameSet()
+
+        def test_add_one_name(self):
+            self.ns.addName("FOO")
+
+            self.VerifyName("FOO", 0)
+            self.assertEqual(0, self.ns.FOO)
+
+        def test_add_two_names(self):
+            self.ns.addName("BAR")
+            self.ns.addName("BAZ")
+
+            self.VerifyName("BAR", 0)
+            self.VerifyName("BAZ", 1)
+            self.assertEqual(0, self.ns.BAR)
+            self.assertEqual(1, self.ns.BAZ)
+
+
+        def test_add_namevalue(self):
+            self.ns.addName("FOO", 87)
+            self.VerifyName("FOO", 87)
+            self.assertEqual(87, self.ns.FOO)
+
+        def test_reuse_existing_value(self):
+            self.ns.addName("FOO", 2)
+            self.ns.addName("B0",0)
+            self.ns.addName("B1")
+            self.ns.addName("B2")
+            self.ns.addName("B3")
+
+            self.VerifyName("FOO", 2)
+            self.VerifyName("B0", 0)
+            self.VerifyName("B1", 1)
+            self.assertEqual(2, self.ns.name_to_value["B2"])
+            self.VerifyName("B3", 3)
+
+            self.assertEqual(2, self.ns.FOO)
+            self.assertEqual(0, self.ns.B0)
+            self.assertEqual(1, self.ns.B1)
+            self.assertEqual(3, self.ns.B3)
+
+        def test_addNames(self):
+            self.ns.addNames("FOO", "BAR", "BAZ")
+            self.VerifyName("FOO", 0)
+            self.VerifyName("BAR", 1)
+            self.VerifyName("BAZ", 2)
+
+            self.assertEqual(0, self.ns.FOO)
+            self.assertEqual(1, self.ns.BAR)
+            self.assertEqual(2, self.ns.BAZ)
+
+        def test_addDupName(self):
+            self.ns.addName("FOO", 1)
+            self.assertRaises(ValueError, self.ns.addName, "FOO", 2)
+
+        def test_addDupValue(self):
+            self.ns.addName("FOO")
+            self.ns.addName("BAR", 0)
+
+            self.VerifyName("FOO", 0)
+            self.assertEqual(0, self.ns.name_to_value["BAR"])
+
+        def test_addMoreDupValues(self):
+            self.ns.addName("FOO")
+            self.ns.addName("BAR", 0)
+            self.ns.addName("BAZ", 0)
+
+            self.VerifyName("FOO", 0)
+            self.assertEqual(0, self.ns.name_to_value["BAR"])
+            self.assertEqual(0, self.ns.name_to_value["BAZ"])
+
+
+        def test_addConflicting(self):
+            self.assertRaises(ValueError, self.ns.addName, "addName")
+
+
+    class Test_mapping(Test_NameSet):
+        """Test map handling"""
+        def setUp(self):
+            self.ns = NameSet(mapping={"SLEEPY":1, "GRUMPY": 0})
+
+        def test_constructor(self):
+            self.VerifyName("SLEEPY", 1)
+            self.VerifyName("GRUMPY", 0)
+
+        def test_addMap(self):
+            self.ns.addMap({"DOC": 9, "BASHFUL": 3})
+
+            self.VerifyName("SLEEPY", 1)
+            self.VerifyName("GRUMPY", 0)
+            self.VerifyName("DOC", 9)
+            self.VerifyName("BASHFUL", 3)
+
+
+    # Run all unit tests
+    unittest.main()
+