diff mbox

[1/3] virt: Add Transparent Hugepages setup

Message ID 1309192003-5456-2-git-send-email-lookkas@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Lucas Meneghel Rodrigues June 27, 2011, 4:26 p.m. UTC
From: Yiqiao Pu <ypu@redhat.com>

This class configures khugepaged to active mode, with
functions to restore original guest configuration.

Changes from v1:
* Rather than a pre/post script, config is now part of
the framework
* No need to store configuration in files anymore to restore
host khugepaged original behavior

Changes from v2:
* Walk through  the thp config directory. And test khugepaged
with the default value in system.
* Add 5s sleep time in khugepaged test

Changes from v3:
* Replace custom function is_writeable with trying to open
  the file for writing.
* Remove some intermediate assignmentes of class attributes.

Signed-off-by: Yiqiao Pu <ypu@redhat.com>
Signed-off-by: Lucas Meneghel Rodrigues <lmr@redhat.com>
---
 client/virt/virt_test_setup.py |  186 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 185 insertions(+), 1 deletions(-)
diff mbox

Patch

diff --git a/client/virt/virt_test_setup.py b/client/virt/virt_test_setup.py
index 3e1f5b5..2717014 100644
--- a/client/virt/virt_test_setup.py
+++ b/client/virt/virt_test_setup.py
@@ -1,11 +1,195 @@ 
 """
 Library to perform pre/post test setup for KVM autotest.
 """
-import os, logging
+import os, logging, time, re, sre, random
 from autotest_lib.client.common_lib import error
 from autotest_lib.client.bin import utils
 
 
+class THPError(Exception):
+    """
+    Base exception for Transparent Hugepage setup.
+    """
+    pass
+
+
+class THPNotSupportedError(THPError):
+    """
+    Thrown when host does not support tansparent hugepages.
+    """
+    pass
+
+
+class THPWriteConfigError(THPError):
+    """
+    Thrown when host does not support tansparent hugepages.
+    """
+    pass
+
+
+class THPKhugepagedError(THPError):
+    """
+    Thrown when khugepaged is not behaving as expected.
+    """
+    pass
+
+
+class TransparentHugePageConfig(object):
+    def __init__(self, test, params):
+        """
+        Find paths for transparent hugepages and kugepaged configuration. Also,
+        back up original host configuration so it can be restored during
+        cleanup.
+        """
+        self.params = params
+
+        RH_THP_PATH = "/sys/kernel/mm/redhat_transparent_hugepage"
+        UPSTREAM_THP_PATH = "/sys/kernel/mm/transparent_hugepage"
+        if os.path.isdir(RH_THP_PATH):
+            self.thp_path = RH_THP_PATH
+        elif os.path.isdir(UPSTREAM_THP_PATH):
+            self.thp_path = UPSTREAM_THP_PATH
+        else:
+            raise THPNotSupportedError("System doesn't support transparent "
+                                       "hugepages")
+
+        tmp_list = []
+        test_cfg = {}
+        test_config = self.params.get("test_config", None)
+        if test_config is not None:
+            tmp_list = re.split(';', test_config)
+        while len(tmp_list) > 0:
+            tmp_cfg = tmp_list.pop()
+            test_cfg[re.split(":", tmp_cfg)[0]] = sre.split(":", tmp_cfg)[1]
+        # Save host current config, so we can restore it during cleanup
+        # We will only save the writeable part of the config files
+        original_config = {}
+        # List of files that contain string config values
+        self.file_list_str = []
+        # List of files that contain integer config values
+        self.file_list_num = []
+        for f in os.walk(self.thp_path):
+            base_dir = f[0]
+            if f[2]:
+                for name in f[2]:
+                    f_dir = os.path.join(base_dir, name)
+                    parameter = file(f_dir, 'r').read()
+                    try:
+                        # Verify if the path in question is writable
+                        f = open(f_dir, 'w')
+                        f.close()
+                        if re.findall("\[(.*)\]", parameter):
+                            original_config[f_dir] = re.findall("\[(.*)\]",
+                                                           parameter)[0]
+                            self.file_list_str.append(f_dir)
+                        else:
+                            original_config[f_dir] = int(parameter)
+                            self.file_list_num.append(f_dir)
+                    except IOError:
+                        pass
+
+        self.test_config = test_cfg
+        self.original_config = original_config
+
+
+    def set_env(self):
+        """
+        Applies test configuration on the host.
+        """
+        if self.test_config:
+            for path in self.test_config.keys():
+                file(path, 'w').write(self.test_config[path])
+
+
+    def value_listed(self, value):
+        """
+        Get a parameters list from a string
+        """
+        value_list = []
+        for i in re.split("\[|\]|\n+|\s+", value):
+            if i:
+                value_list.append(i)
+        return value_list
+
+
+    def khugepaged_test(self):
+        """
+        Start, stop and frequency change test for khugepaged.
+        """
+        def check_status_with_value(action_list, file_name):
+            """
+            Check the status of khugepaged when set value to specify file.
+            """
+            for (a, r) in action_list:
+                open(file_name, "w").write(a)
+                time.sleep(5)
+                try:
+                    utils.run('pgrep khugepaged')
+                    if r != 0:
+                        raise THPKhugepagedError("Khugepaged still alive when"
+                                                 "transparent huge page is "
+                                                 "disabled")
+                except error.CmdError:
+                    if r == 0:
+                        raise THPKhugepagedError("Khugepaged could not be set to"
+                                                 "status %s" % a)
+
+
+        for file_path in self.file_list_str:
+            action_list = []
+            if re.findall("enabled", file_path):
+                # Start and stop test for khugepaged
+                value_list = self.value_listed(open(file_path,"r").read())
+                for i in value_list:
+                    if re.match("n", i, re.I):
+                        action_stop = (i, 256)
+                for i in value_list:
+                    if re.match("[^n]", i, re.I):
+                        action = (i, 0)
+                        action_list += [action_stop, action, action_stop]
+                action_list += [action]
+
+                check_status_with_value(action_list, file_path)
+            else:
+                value_list = self.value_listed(open(file_path,"r").read())
+                for i in value_list:
+                    action = (i, 0)
+                    action_list.append(action)
+                check_status_with_value(action_list, file_path)
+
+        for file_path in self.file_list_num:
+            action_list = []
+            value = int(open(file_path, "r").read())
+            if value != 0 and value != 1:
+                new_value = random.random()
+                action_list.append((str(int(value * new_value)),0))
+                action_list.append((str(int(value * ( new_value + 1))),0))
+            else:
+                action_list.append(("0", 0))
+                action_list.append(("1", 0))
+
+            check_status_with_value(action_list, file_path)
+
+
+    def setup(self):
+        """
+        Configure host for testing. Also, check that khugepaged is working as
+        expected.
+        """
+        self.set_env()
+        self.khugepaged_test()
+
+
+    def cleanup(self):
+        """:
+        Restore the host's original configuration after test
+        """
+        for path in self.original_config:
+            p_file = open(path, 'w')
+            p_file.write(str(self.original_config[path]))
+            p_file.close()
+
+
 class HugePageConfig(object):
     def __init__(self, params):
         """