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_compare_nodemask_default_and_env_variable(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 usupported value of MEMKIND_HBW_NODES, then try to perform a successfull 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 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("Error: trace_mechanism_test_helper returned {0} with output: {1}".format(retcode,output)) assert "MEMKIND_INFO: NUMA node" in output, self.fail_msg.format("Error: trace mechanism in memkind doesn't show MEMKIND_INFO message (output: {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("Error: trace_mechanism_test_helper returned {0} with output: {1}".format(retcode,output)) assert "MEMKIND_INFO: Number of" in output, self.fail_msg.format("Error: trace mechanism in memkind doesn't show MEMKIND_INFO message (output: {0})").format(output) assert "MEMKIND_INFO: Overcommit limit for" in output, self.fail_msg.format("Error: trace mechanism in memkind doesn't show MEMKIND_INFO message (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("Error: trace_mechanism_test_helper returned {0} with output: {1}".format(retcode,output)) assert "MEMKIND_WARNING: debug option" in output, self.fail_msg.format("Error: setting wrong MEMKIND_DEBUG environment variable doesn't show MEMKIND_WARNING (output: {0})").format(output)
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}\' 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_max_bg_threads_env_var(): cmd_helper = CMD_helper() fail_msg = "Test failed with:\n {0}" MAIN_THREAD = 1 threads_limit = 0 @property def min_threads(self): return self.MAIN_THREAD + self.threads_limit def run_test_binary(self): cmd_path = self.cmd_helper.get_command_path( '../environ_max_bg_threads_test') command = "MEMKIND_BACKGROUND_THREAD_LIMIT=" \ f"{self.threads_limit} {cmd_path}" output, retcode = self.cmd_helper.execute_cmd(command) assert retcode != 1, \ self.fail_msg.format( f"\nError: Execution of \'{command}\'" f" returns {retcode}. Output: {output}") return output, retcode def test_TC_MEMKIND_max_bg_threads_env_var_min(self): """This test checks if MEMKIND_BACKGROUND_THREAD_LIMIT environment variable limits the number of background threads spawned correctly.""" self.threads_limit = 1 output, retcode = self.run_test_binary() assert int(output) == self.min_threads, \ self.fail_msg.format( f"Error: There should be {self.min_threads} threads running. " f"Counted threads: {output}.") @pytest.mark.parametrize("threads_limit", [0, 10]) def test_TC_MEMKIND_max_bg_threads_env_var_multiple_threads( self, threads_limit): """This test checks if MEMKIND_BACKGROUND_THREAD_LIMIT environment variable allows spawning of multiple threads.""" output, threads_count = self.run_test_binary() assert int(output) > self.min_threads, \ self.fail_msg.format( f"Error: There should be more than" f" {self.min_threads} threads running. " f"Counted threads: {output}.") def test_TC_MEMKIND_max_bg_threads_env_var_err(self): """This test checks if a negative value MEMKIND_BACKGROUND_THREAD_LIMIT environment variable is handled correctly.""" self.threads_limit = -1 output, retcode, threads_count = self.run_test_binary() assert retcode == 134, \ self.fail_msg.format( "Error: Negative value of MEMKIND_BACKGROUND_THREAD_LIMIT" " should not be handled. " f"Counted threads: {threads_count}. Output: {output}")
class Test_hbw_detection(object): 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_nodemask_default(self): """ This function executes memkind function 'get_mbind_nodemask' and returns its output """ hbw_nodemask_default = None command = self.cmd_helper.get_command_path(self.binary_path) output, retcode = self.cmd_helper.execute_cmd(command, sudo=False) if retcode == 0: hbw_nodemask_default = output print "Nodemask detected in test_hbw_detection_default: {0}".format(hbw_nodemask_default) assert retcode == 0, self.fail_msg.format("Error: hbw_nodemask returned {0}".format(retcode)) return hbw_nodemask_default def get_nodemask_env_variable(self): """ This function overrides environment variable MEMKIND_HBW_NODES with values returned from 'memkind-hbw-nodes', executes memkind function 'get_mbind_nodemask' and returns its output """ hbw_nodemask_env_variable = None command = "MEMKIND_HBW_NODES=`memkind-hbw-nodes` " + self.cmd_helper.get_command_path(self.binary_path) output, retcode = self.cmd_helper.execute_cmd(command, sudo=False) if retcode == 0: hbw_nodemask_env_variable = output print "Nodemask detected in test_hbw_detection_env_variable: {0}".format(hbw_nodemask_env_variable) assert retcode == 0, self.fail_msg.format("Error: hbw_nodemask returned {0}".format(retcode)) return hbw_nodemask_env_variable def test_TC_MEMKIND_hbw_detection_default(self): """ This test checks whether hbw_nodemask_default is not None """ assert self.get_nodemask_default() is not None, self.fail_msg.format("Error: hbw_nodemask_default is None") def test_TC_MEMKIND_hbw_detection_env_variable(self): """ This test checks whether hbw_nodemask_env_variable is not None """ assert self.get_nodemask_env_variable() is not None, self.fail_msg.format("Error: hbw_nodemask_env_variable is None") def test_TC_MEMKIND_hbw_detection_compare_nodemask_default_and_env_variable(self): """ This test checks whether hbw_nodemask_default and hbw_nodemask_env_variable has the same value """ hbw_nodemask_default = self.get_nodemask_default() hbw_nodemask_env_variable = self.get_nodemask_env_variable() 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 usupported value of MEMKIND_HBW_NODES, then try to perform a successfull 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("Error: hbw_nodemask returned {0} with output {1}".format(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 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_compare_nodemask_default_and_env_variable( 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))
class Test_autohbw(object): binary = "../autohbw_test_helper" fail_msg = "Test failed with:\n {0}" test_prefix = "AUTO_HBW_LOG=2 LD_PRELOAD=%s/libautohbw.so.0 " % _get_lib_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_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}\' 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"), \ f"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, \ f"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."