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 Signed-off-by: Yiqiao Pu <[email protected]> Signed-off-by: Lucas Meneghel Rodrigues <[email protected]> --- client/virt/virt_test_setup.py | 187 +++++++++++++++++++++++++++++++++++++++- 1 files changed, 186 insertions(+), 1 deletions(-) diff --git a/client/virt/virt_test_setup.py b/client/virt/virt_test_setup.py index 3e1f5b5..70cf3c2 100644 --- a/client/virt/virt_test_setup.py +++ b/client/virt/virt_test_setup.py @@ -1,11 +1,196 @@ """ 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. + """ + def file_writeable(file_name): + """ + Check if the file is writeable + """ + o = utils.system_output("ls -l %s" % file_name) + if re.findall("w", o[0:10]): + return True + return False + + 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 = {} + file_list_str = [] + 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() + if file_writeable(f_dir): + if re.findall("\[(.*)\]", parameter): + original_config[f_dir] = re.findall("\[(.*)\]", + parameter)[0] + file_list_str.append(f_dir) + else: + original_config[f_dir] = int(parameter) + file_list_num.append(f_dir) + + self.test_config = test_cfg + self.original_config = original_config + self.file_list_str = file_list_str + self.file_list_num = file_list_num + + 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 can not set to" + "status %s" % a) + + file_list_str = self.file_list_str + file_list_num = self.file_list_num + for file_path in 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 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): """ -- 1.7.1 _______________________________________________ Autotest mailing list [email protected] http://test.kernel.org/cgi-bin/mailman/listinfo/autotest
