class Test_hbw_env_var(object): environ_err_threshold_test = "../environ_err_hbw_threshold_test" cmd_helper = CMD_helper() def run_test(self, threshold, kind): env = "MEMKIND_HBW_THRESHOLD=" + str(threshold) bin_path = self.cmd_helper.get_command_path( self.environ_err_threshold_test) command = " ".join([env, bin_path, kind]) output, retcode = self.cmd_helper.execute_cmd(command) print(output) fail_msg = (f"Test failed with error: \nExecution of: \'{command}\'" f" returns: {retcode} \noutput: {output}") assert retcode == 0, fail_msg @pytest.mark.parametrize("kind", ["MEMKIND_HBW", "MEMKIND_HBW_ALL"]) def test_TC_MEMKIND_hbw_threshold_default_value(self, kind): threshold = 204800 self.run_test(threshold, kind) @pytest.mark.parametrize("kind", ["MEMKIND_HBW", "MEMKIND_HBW_ALL"]) def test_TC_MEMKIND_hbw_threshold_negative_value(self, kind): threshold = -1 self.run_test(threshold, kind) @pytest.mark.parametrize("kind", ["MEMKIND_HBW", "MEMKIND_HBW_ALL"]) def test_TC_MEMKIND_hbw_threshold_low_value(self, kind): threshold = 1 self.run_test(threshold, kind) @pytest.mark.parametrize("kind", ["MEMKIND_HBW", "MEMKIND_HBW_ALL"]) def test_TC_MEMKIND_hbw_threshold_high_value(self, kind): threshold = 1024 * 1024 * 1024 self.run_test(threshold, kind)
class Test_trace_mechanism(object): binary = "../trace_mechanism_test_helper" fail_msg = "Test failed with:\n {0}" debug_env = "MEMKIND_DEBUG=1 " cmd_helper = CMD_helper() def test_TC_MEMKIND_logging_MEMKIND_HBW(self): # This test executes trace_mechanism_test_helper and # test if MEMKIND_INFO message occurs while calling MEMKIND_HBW command = self.debug_env \ + self.cmd_helper.get_command_path(self.binary) + " MEMKIND_HBW" print("Executing command: {0}".format(command)) output, retcode = self.cmd_helper.execute_cmd(command, sudo=False) assert retcode == 0, self.fail_msg.format( "\nError: trace_mechanism_test_helper", " returned {0} \noutput: {1}".format(retcode, output)) assert "MEMKIND_INFO: Initializing kind memkind_hbw." \ in output, self.fail_msg.format( "\nError: trace mechanism in memkind doesn't show", " MEMKIND_INFO message \noutput: {0}").format(output) def test_TC_MEMKIND_2MBPages_logging_MEMKIND_HUGETLB(self): # This test executes trace_mechanism_test_helper and test # if MEMKIND_INFO message occurs while calling MEMKIND_HUGETLB command = self.debug_env \ + self.cmd_helper.get_command_path(self.binary) \ + " MEMKIND_HUGETLB" print("Executing command: {0}".format(command)) output, retcode = self.cmd_helper.execute_cmd(command, sudo=False) assert retcode == 0, self.fail_msg.format( "\nError: trace_mechanism_test_helper", " returned {0} \noutput: {1}".format(retcode, output)) assert "MEMKIND_INFO: Number of" in output, self.fail_msg.format( "\nError: trace mechanism in memkind doesn't show", " MEMKIND_INFO message \noutput: {0}").format(output) assert "MEMKIND_INFO: Overcommit limit for" \ in output, self.fail_msg.format( "\nError: trace mechanism in memkind doesn't show", " MEMKIND_INFO message \n output: {0}").format(output) def test_TC_MEMKIND_logging_negative_MEMKIND_DEBUG_env(self): # This test executes trace_mechanism_test_helper and test # if setting MEMKIND_DEBUG to wrong value # causes MEMKIND_WARNING message command = "MEMKIND_DEBUG=-1 " \ + self.cmd_helper.get_command_path(self.binary) + " MEMKIND_HBW" print("Executing command: {0}".format(command)) output, retcode = self.cmd_helper.execute_cmd(command, sudo=False) assert retcode == 0, self.fail_msg.format( "\nError: trace_mechanism_test_helper", " returned {0} \noutput: {1}".format(retcode, output)) assert "MEMKIND_WARNING: debug option" in output, self.fail_msg.format( "\nError: setting wrong MEMKIND_DEBUG environment variable", " doesn't show MEMKIND_WARNING \noutput: {0})").format(output)
class Test_hbw_detection(object): os.environ["PATH"] += os.pathsep + os.path.dirname( os.path.dirname(__file__)) binary_path = find_executable("memkind-hbw-nodes") environ_err_test = "../environ_err_hbw_malloc_test" expected_libnuma_warning = "libnuma: Warning: node" \ " argument -1 is out of range\n\n" fail_msg = "Test failed with:\n {0}" cmd_helper = CMD_helper() def get_hbw_nodes(self, nodemask=None): """ This function executes memkind function 'get_mbind_nodemask' and returns its output - comma-separated HBW nodes """ command = self.binary_path if (nodemask): command = "MEMKIND_HBW_NODES={}".format(nodemask) + command output, retcode = self.cmd_helper.execute_cmd(command, sudo=False) assert retcode == 0, self.fail_msg.format( "\nError: Execution of: \'{0}\' returns: {1} \noutput: {2}".format( command, retcode, output)) print("\nExecution of {} returns output {}".format(command, output)) return output def test_TC_MEMKIND_hbw_detection_cmp_nodemask_default_and_env_var(self): """ This test checks whether hbw_nodemask_default and hbw_nodemask_env_variable has the same value """ hbw_nodemask_default = self.get_hbw_nodes() hbw_nodemask_env_variable = self.get_hbw_nodes(hbw_nodemask_default) assert hbw_nodemask_default == hbw_nodemask_env_variable, \ self.fail_msg.format( "Error: Nodemask hbw_nodemask_default ({0}) " "is not the same as nodemask " "hbw_nodemask_env_variable ({1})".format( hbw_nodemask_default, hbw_nodemask_env_variable)) def test_TC_MEMKIND_hbw_detection_negative_hbw_malloc(self): """ This test sets unsupported value of MEMKIND_HBW_NODES, then try to perform a successful allocation from DRAM using hbw_malloc() thanks to default HBW_POLICY_PREFERRED policy """ command = "MEMKIND_HBW_NODES=-1 " \ + self.cmd_helper.get_command_path(self.environ_err_test) output, retcode = self.cmd_helper.execute_cmd(command, sudo=False) assert retcode != 0, self.fail_msg.format( "\nError: Execution of: \'{0}\' returns: {1} \noutput: {2}".format( command, retcode, output)) assert self.expected_libnuma_warning == output, self.fail_msg.format( "Error: expected libnuma warning ({0}) " "was not found (output: {1})").format( self.expected_libnuma_warning, output)
class Huge_page_organizer(object): cmd_helper = CMD_helper() path = "/sys/devices/system/node/node{0}/hugepages/" \ "hugepages-2048kB/nr_hugepages" restore_values = [] def __restore(self): """Restore initial setup of hugepages.""" for node_id, restore_value in enumerate(self.restore_values): self.__set_nr_hugepages(node_id, restore_value) def __get_nr_hugepages(self, node_id): """Return number of hugepages on given node or None if given node is not configured.""" if not os.path.isfile(self.path.format(node_id)): return None with open(self.path.format(node_id), "r") as f: return int(f.read()) def __set_nr_hugepages(self, node_id, nr_hugepages): """Set hugepages on given node to given number. Return True on success, False otherwise.""" command = 'sh -c "echo {0} >> {1}"'.format(nr_hugepages, self.path.format(node_id)) output, retcode = self.cmd_helper.execute_cmd(command, sudo=True) if retcode: return False return self.__get_nr_hugepages(node_id) is nr_hugepages def __init__(self, nr_hugepages_per_node): """Save current hugepages setup and set hugepages per NUMA node.""" for node_id in itertools.count(): nr_hugepages = self.__get_nr_hugepages(node_id) if nr_hugepages is None: break self.restore_values.append(nr_hugepages) retcode = self.__set_nr_hugepages(node_id, nr_hugepages_per_node) if not retcode: self.__restore() assert retcode, "Error: Could not set the requested"\ " amount of hugepages." def __del__(self): """Call __restore() function.""" self.__restore()
class Test_malloc_stats_print(object): cmd_helper = CMD_helper() bin_path = cmd_helper.get_command_path("../stats_print_test_helper") fail_msg = "Test failed with:\n {0}" bin_param = "" error_msg = "Error: {0} option not parsed correctly." def run_test_binary(self): command = " ".join([self.bin_path, self.bin_param]) output, retcode = self.cmd_helper.execute_cmd(command) assert retcode == 0, \ self.fail_msg.format( f"\nError: Execution of \'{command}\'", f" returns {retcode}. Output: {output}") return output, retcode @pytest.mark.parametrize("bin_param", ["default", "stdout", "no_write_cb"]) def test_TC_MEMKIND_malloc_stats_print_check_output(self, bin_param): """ This test checks if there is output from malloc_stats_print() memkind API function """ self.bin_param = bin_param output, _ = self.run_test_binary() assert output.endswith("--- End jemalloc statistics ---\n"), \ "Error: Didn't get the expected output"\ " from the '{self.bin_path}' binary." def test_TC_MEMKIND_malloc_stats_print_multi_opt_test(self): """ This test checks output from malloc_stats_print() memkind API function when options "MEMKIND_STAT_PRINT_JSON_FORMAT | MEMKIND_STAT_PRINT_OMIT_PER_ARENA | MEMKIND_STAT_PRINT_OMIT_EXTENT" are passed to the function """ self.bin_param = "pass_opts" output, _ = self.run_test_binary() assert json.loads(output), \ self.error_msg.format("MEMKIND_STAT_PRINT_JSON_FORMAT") assert "arenas[" not in output, \ self.error_msg.format("MEMKIND_STAT_PRINT_OMIT_PER_ARENA") assert "extents:" not in output, \ self.error_msg.format("MEMKIND_STAT_PRINT_OMIT_EXTENT") def test_TC_MEMKIND_malloc_stats_print_all_opts_test(self): """ This test checks output from malloc_stats_print() memkind API function when all possible options are passed to the function """ self.bin_param = "all_opts" output, _ = self.run_test_binary() assert json.loads(output), \ self.error_msg.format("MEMKIND_STAT_PRINT_JSON_FORMAT") assert "version" not in output, \ self.error_msg.format("MEMKIND_STAT_PRINT_OMIT_GENERAL") assert "merged" not in output, \ self.error_msg.format("MEMKIND_STAT_PRINT_OMIT_MERGED_ARENA") assert "destroyed" not in output, \ self.error_msg.format( "MEMKIND_STAT_PRINT_OMIT_DESTROYED_MERGED_ARENA") assert re.search(re.compile(r'(\d+)": {'), output) is None, \ self.error_msg.format("MEMKIND_STAT_PRINT_OMIT_PER_ARENA") assert "\"bins\"" not in output, \ self.error_msg.format( "MEMKIND_STAT_PRINT_OMIT_PER_SIZE_CLASS_BINS") assert "lextents" not in output, \ self.error_msg.format( "MEMKIND_STAT_PRINT_OMIT_PER_SIZE_CLASS_LARGE") assert "mutex" not in output, \ self.error_msg.format("MEMKIND_STAT_PRINT_OMIT_MUTEX") assert "\"extents\"" not in output, \ self.error_msg.format("MEMKIND_STAT_PRINT_OMIT_EXTENT") def test_TC_MEMKIND_malloc_stats_print_negative_test(self): """ This test checks if there is no output from malloc_stats_print() memkind API function when wrong arguments are being passed to the function """ self.bin_param = "negative_test" output, _ = self.run_test_binary() assert len(output) == 0, \ "Error: There should be no output from"\ " the '{self.bin_path}' binary." def test_TC_MEMKIND_malloc_stats_print_opts_negative_test(self): """ This test checks if there is a failure in parsing opts in malloc_stats_print() memkind API function when wrong options string is passed to the function """ self.bin_param = "opts_negative_test" _, retcode = self.run_test_binary() assert retcode == 0, \ f"Error: '{self.bin_path}' binary should return 0" \ " indicating that parsing opts string failed."
class Test_autohbw(object): binary = "../autohbw_test_helper" fail_msg = "Test failed with:\n {0}" test_prefix = "AUTO_HBW_LOG=2 LD_PRELOAD=%s " % _get_libautohbw_path() memkind_malloc_log = "In my memkind malloc" memkind_calloc_log = "In my memkind calloc" memkind_realloc_log = "In my memkind realloc" memkind_posix_memalign_log = "In my memkind align" memkind_free_log = "In my memkind free" cmd_helper = CMD_helper() def test_TC_MEMKIND_autohbw_malloc_and_free(self): """ This test executes ./autohbw_test_helper with LD_PRELOAD that is overriding malloc() and free() to equivalent autohbw functions""" command = (self.test_prefix + self.cmd_helper.get_command_path(self.binary) + " malloc") print("Executing command: {0}".format(command)) output, retcode = self.cmd_helper.execute_cmd(command, sudo=False) assert retcode == 0, \ self.fail_msg.format("\nError: autohbw_test_helper", " returned {0} \noutput: {1}" .format(retcode, output)) assert self.memkind_malloc_log in output, self.fail_msg.format( "\nError: malloc was not overridden", " by autohbw equivalent \noutput: {0}").format(output) assert self.memkind_free_log in output, self.fail_msg.format( "\nError: free was not overridden", " by autohbw equivalent \noutput: {0}").format(output) def test_TC_MEMKIND_autohbw_calloc_and_free(self): """ This test executes ./autohbw_test_helper with LD_PRELOAD that is overriding calloc() and free() to equivalent autohbw functions""" command = (self.test_prefix + self.cmd_helper.get_command_path(self.binary) + " calloc") print("Executing command: {0}".format(command)) output, retcode = self.cmd_helper.execute_cmd(command, sudo=False) assert retcode == 0, \ self.fail_msg.format("\nError: autohbw_test_helper", " returned {0} \noutput: {1}" .format(retcode, output)) assert self.memkind_calloc_log in output, self.fail_msg.format( "\nError: calloc was not overridden by", " autohbw equivalent \noutput: {0}").format(output) assert self.memkind_free_log in output, self.fail_msg.format( "Error: free was not overridden by", " autohbw equivalent \noutput: {0}").format(output) def test_TC_MEMKIND_autohbw_realloc_and_free(self): """ This test executes ./autohbw_test_helper with LD_PRELOAD that is overriding realloc() and free() to equivalent autohbw functions""" command = (self.test_prefix + self.cmd_helper.get_command_path(self.binary) + " realloc") print("Executing command: {0}".format(command)) output, retcode = self.cmd_helper.execute_cmd(command, sudo=False) assert retcode == 0, self.fail_msg.format( "\nError: autohbw_test_helper returned {0} \noutput: {1}" .format(retcode, output)) assert self.memkind_realloc_log in output, self.fail_msg.format( "\nError: realloc was not overridden by", " autohbw equivalent \noutput: {0}").format(output) assert self.memkind_free_log in output, self.fail_msg.format( "\nError: free was not overridden by", " autohbw equivalent \noutput: {0}").format(output) def test_TC_MEMKIND_autohbw_posix_memalign_and_free(self): """ This test executes ./autohbw_test_helper with LD_PRELOAD that is overriding posix_memalign() and free() to equivalent autohbw functions""" command = (self.test_prefix + self.cmd_helper.get_command_path(self.binary) + " posix_memalign") print("Executing command: {0}".format(command)) output, retcode = self.cmd_helper.execute_cmd(command, sudo=False) assert retcode == 0, self.fail_msg.format( "\nError: autohbw_test_helper returned {0} \noutput: {1}" .format(retcode, output)) assert self.memkind_posix_memalign_log in output, self.fail_msg.format( "\nError: posix_memalign was not overridden by", " autohbw equivalent \noutput: {0}").format(output) assert self.memkind_free_log in output, self.fail_msg.format( "\nError: free was not overridden by", " autohbw equivalent \noutput: {0}").format(output)
class Test_dax_kmem_env_var(object): os.environ["PATH"] += (os.pathsep + os.path.dirname(os.path.dirname(__file__))) binary_path = find_executable("memkind-auto-dax-kmem-nodes") environ_err_test = "../environ_err_dax_kmem_malloc_test" environ_err_positive_test = "../environ_err_dax_kmem_malloc_positive_test" expected_libnuma_warning = ( "libnuma: Warning: node argument -1 is out of range\n\n") fail_msg = "Test failed with:\n {0}" cmd_helper = CMD_helper() def get_dax_kmem_nodes(self, nodemask=None): """ This function executes memkind function 'get_mbind_nodemask' and returns its output - comma-separated DAX_KMEM nodes """ command = self.binary_path if (nodemask): command = "MEMKIND_DAX_KMEM_NODES={}".format(nodemask) + command output, retcode = self.cmd_helper.execute_cmd(command) assert retcode == 0, self.fail_msg.format( "\nError: Execution of \'{0}\' returns {1}, \noutput: {2}".format( command, retcode, output)) print("\nExecution of {} returns output {}".format(command, output)) return output def test_TC_MEMKIND_dax_kmem_env_var_cmp_with_nodemask_default(self): """ This test checks whether dax_kmem_nodemask_default and dax_kmem_nodemask_env_variable have the same value """ dax_kmem_nodemask_default = self.get_dax_kmem_nodes() dax_kmem_nodemask_env_variable = self.get_dax_kmem_nodes( dax_kmem_nodemask_default) assert dax_kmem_nodemask_default == dax_kmem_nodemask_env_variable, \ self.fail_msg.format( "Error: Nodemask dax_kmem_nodemask_default ({0}) " "is not the same as nodemask " "dax_kmem_nodemask_env_variable ({1})".format( dax_kmem_nodemask_default, dax_kmem_nodemask_env_variable)) def test_TC_MEMKIND_dax_kmem_env_var_negative_memkind_malloc(self): """ This test sets unsupported value of MEMKIND_DAX_KMEM_NODES, then tries to perform a successful allocation from DRAM using memkind_malloc() """ command = ("MEMKIND_DAX_KMEM_NODES=-1 " + self.cmd_helper.get_command_path(self.environ_err_test)) output, retcode = self.cmd_helper.execute_cmd(command) assert retcode != 0, self.fail_msg.format( "\nError: Execution of: \'{0}\' returns: {1} \noutput: {2}".format( command, retcode, output)) assert self.expected_libnuma_warning == output, self.fail_msg.format( "Error: expected libnuma warning ({0}) " "was not found (output: {1})").format( self.expected_libnuma_warning, output) def test_TC_MEMKIND_dax_kmem_env_var_proper_memkind_malloc(self): """ This test checks if allocation is performed on persistent memory correctly """ dax_kmem_nodemask_default = self.get_dax_kmem_nodes().strip() command = "MEMKIND_DAX_KMEM_NODES={} ".format( dax_kmem_nodemask_default) + self.cmd_helper.get_command_path( self.environ_err_positive_test) output, retcode = self.cmd_helper.execute_cmd(command) assert retcode == 0, self.fail_msg.format( "\nError: Execution of: \'{0}\' returns: {1} \noutput: {2}".format( command, retcode, output))