@@ -30,8 +30,8 @@ def command_line():
3030 # Random prefixes to validate command line argument parsing
3131 prefix = (
3232 'd17weqroeg' , 'riabfodkj5' , 'fir8o3lsak' ,
33- 'zwejklqn25' , 'qtr2vfvwiu' )
34-
33+ 'zwejklqn25' , 'qtr2vfvwiu'
34+ )
3535 petsc_option = (
3636 ('ksp_rtol' ,),
3737 ('ksp_rtol' , 'ksp_atol' ),
@@ -52,6 +52,9 @@ def command_line():
5252 for o , v in zip (opt , val , strict = True ):
5353 argv .extend ([f'-{ p } _{ o } ' , str (v )])
5454 expected [p ] = zip (opt , val )
55+
56+ if os .environ .get ('DEVITO_PYTEST_FLAG' , '0' ) == '2' :
57+ argv .extend (['-malloc_dump' ])
5558 return argv , expected
5659
5760
@@ -1696,7 +1699,8 @@ def setup_class(self):
16961699 self .eq2 = Eq (self .g .laplace , self .h )
16971700
16981701 @skipif ('petsc' )
1699- def test_different_solver_params (self ):
1702+ @pytest .mark .parallel (mode = [1 , 2 , 4 , 6 , 8 ])
1703+ def test_different_solver_params (self , mode ):
17001704 # Explicitly set the solver parameters
17011705 solver1 = petscsolve (
17021706 self .eq1 , target = self .e , solver_parameters = {'ksp_rtol' : '1e-10' }
@@ -1717,7 +1721,8 @@ def test_different_solver_params(self):
17171721 in str (op ._func_table ['SetPetscOptions1' ].root )
17181722
17191723 @skipif ('petsc' )
1720- def test_options_prefix (self ):
1724+ @pytest .mark .parallel (mode = [1 , 2 , 4 , 6 , 8 ])
1725+ def test_options_prefix (self , mode ):
17211726 solver1 = petscsolve (self .eq1 , self .e ,
17221727 solver_parameters = {'ksp_rtol' : '1e-10' },
17231728 options_prefix = 'poisson1' )
@@ -1740,7 +1745,8 @@ def test_options_prefix(self):
17401745 in str (op ._func_table ['SetPetscOptions1' ].root )
17411746
17421747 @skipif ('petsc' )
1743- def test_options_no_value (self ):
1748+ @pytest .mark .parallel (mode = [1 , 2 , 4 , 6 , 8 ])
1749+ def test_options_no_value (self , mode ):
17441750 """
17451751 Test solver parameters that do not require a value, such as
17461752 `snes_view` and `ksp_view`.
@@ -1929,84 +1935,84 @@ def test_command_line_priority_tols3(self, command_line, log_level):
19291935 for opt , val in expected [prefix ]:
19301936 assert entry .KSPGetTolerances [opt .removeprefix ('ksp_' )] == val
19311937
1932- # @skipif('petsc')
1933- # @pytest.mark.parametrize('log_level', ['PERF', 'DEBUG'])
1934- # def test_command_line_priority_ksp_type(self, command_line, log_level):
1935- # """
1936- # Test the solver parameter 'ksp_type' specified via the command line
1937- # take precedence over the one specified in the `solver_parameters` dict.
1938- # """
1939- # prefix = 'zwejklqn25'
1940- # _, expected = command_line
1941-
1942- # # Set `ksp_type`` in the solver parameters, which should be overridden
1943- # # by the command line value (which is set to `cg` -
1944- # # see the `command_line` fixture).
1945- # params = {'ksp_type': 'richardson'}
1946-
1947- # solver1 = petscsolve(
1948- # self.eq1, target=self.e,
1949- # solver_parameters=params,
1950- # options_prefix=prefix
1951- # )
1952- # with switchconfig(language='petsc', log_level=log_level):
1953- # op = Operator(solver1)
1954- # summary = op.apply()
1955-
1956- # petsc_summary = summary.petsc
1957- # entry = petsc_summary.get_entry('section0', prefix)
1958- # for _, val in expected[prefix]:
1959- # assert entry.KSPGetType == val
1960- # assert not entry.KSPGetType == params['ksp_type']
1961-
1962- # @skipif('petsc')
1963- # def test_command_line_priority_ccode(self, command_line):
1964- # """
1965- # Verify that if an option is set via the command line,
1966- # the corresponding entry in `linear_solve_defaults` or `solver_parameters`
1967- # is not set or cleared in the generated code. (The command line option
1968- # will have already been set in the global PetscOptions database
1969- # during PetscInitialize().)
1970- # """
1971- # prefix = 'qtr2vfvwiu'
1972-
1973- # solver = petscsolve(
1974- # self.eq1, target=self.e,
1975- # # Specify a solver parameter that is not set via the
1976- # # command line (see the `command_line` fixture for this prefix).
1977- # solver_parameters={'ksp_rtol': '1e-10'},
1978- # options_prefix=prefix
1979- # )
1980- # with switchconfig(language='petsc'):
1981- # op = Operator(solver)
1982-
1983- # set_options_callback = str(op._func_table['SetPetscOptions0'].root)
1984- # clear_options_callback = str(op._func_table['ClearPetscOptions0'].root)
1985-
1986- # # Check that the `ksp_rtol` option IS set and cleared explicitly
1987- # # since it is NOT set via the command line.
1988- # assert f'PetscOptionsSetValue(NULL,"-{prefix}_ksp_rtol","1e-10")' \
1989- # in set_options_callback
1990- # assert f'PetscOptionsClearValue(NULL,"-{prefix}_ksp_rtol")' \
1991- # in clear_options_callback
1992-
1993- # # Check that the `ksp_divtol` and `ksp_type` options are NOT set
1994- # # or cleared explicitly since they ARE set via the command line.
1995- # assert f'PetscOptionsSetValue(NULL,"-{prefix}_div_tol",' \
1996- # not in set_options_callback
1997- # assert f'PetscOptionsSetValue(NULL,"-{prefix}_ksp_type",' \
1998- # not in set_options_callback
1999- # assert f'PetscOptionsClearValue(NULL,"-{prefix}_div_tol"));' \
2000- # not in clear_options_callback
2001- # assert f'PetscOptionsClearValue(NULL,"-{prefix}_ksp_type"));' \
2002- # not in clear_options_callback
2003-
2004- # # Check that options specifed by the `linear_solver_defaults`
2005- # # are still set and cleared
2006- # assert f'PetscOptionsSetValue(NULL,"-{prefix}_ksp_atol",' \
2007- # in set_options_callback
2008- # assert f'PetscOptionsClearValue(NULL,"-{prefix}_ksp_atol"));' \
2009- # in clear_options_callback
1938+ @skipif ('petsc' )
1939+ @pytest .mark .parametrize ('log_level' , ['PERF' , 'DEBUG' ])
1940+ def test_command_line_priority_ksp_type (self , command_line , log_level ):
1941+ """
1942+ Test the solver parameter 'ksp_type' specified via the command line
1943+ take precedence over the one specified in the `solver_parameters` dict.
1944+ """
1945+ prefix = 'zwejklqn25'
1946+ _ , expected = command_line
1947+
1948+ # Set `ksp_type`` in the solver parameters, which should be overridden
1949+ # by the command line value (which is set to `cg` -
1950+ # see the `command_line` fixture).
1951+ params = {'ksp_type' : 'richardson' }
1952+
1953+ solver1 = petscsolve (
1954+ self .eq1 , target = self .e ,
1955+ solver_parameters = params ,
1956+ options_prefix = prefix
1957+ )
1958+ with switchconfig (language = 'petsc' , log_level = log_level ):
1959+ op = Operator (solver1 )
1960+ summary = op .apply ()
1961+
1962+ petsc_summary = summary .petsc
1963+ entry = petsc_summary .get_entry ('section0' , prefix )
1964+ for _ , val in expected [prefix ]:
1965+ assert entry .KSPGetType == val
1966+ assert not entry .KSPGetType == params ['ksp_type' ]
1967+
1968+ @skipif ('petsc' )
1969+ def test_command_line_priority_ccode (self , command_line ):
1970+ """
1971+ Verify that if an option is set via the command line,
1972+ the corresponding entry in `linear_solve_defaults` or `solver_parameters`
1973+ is not set or cleared in the generated code. (The command line option
1974+ will have already been set in the global PetscOptions database
1975+ during PetscInitialize().)
1976+ """
1977+ prefix = 'qtr2vfvwiu'
1978+
1979+ solver = petscsolve (
1980+ self .eq1 , target = self .e ,
1981+ # Specify a solver parameter that is not set via the
1982+ # command line (see the `command_line` fixture for this prefix).
1983+ solver_parameters = {'ksp_rtol' : '1e-10' },
1984+ options_prefix = prefix
1985+ )
1986+ with switchconfig (language = 'petsc' ):
1987+ op = Operator (solver )
1988+
1989+ set_options_callback = str (op ._func_table ['SetPetscOptions0' ].root )
1990+ clear_options_callback = str (op ._func_table ['ClearPetscOptions0' ].root )
1991+
1992+ # Check that the `ksp_rtol` option IS set and cleared explicitly
1993+ # since it is NOT set via the command line.
1994+ assert f'PetscOptionsSetValue(NULL,"-{ prefix } _ksp_rtol","1e-10")' \
1995+ in set_options_callback
1996+ assert f'PetscOptionsClearValue(NULL,"-{ prefix } _ksp_rtol")' \
1997+ in clear_options_callback
1998+
1999+ # Check that the `ksp_divtol` and `ksp_type` options are NOT set
2000+ # or cleared explicitly since they ARE set via the command line.
2001+ assert f'PetscOptionsSetValue(NULL,"-{ prefix } _div_tol",' \
2002+ not in set_options_callback
2003+ assert f'PetscOptionsSetValue(NULL,"-{ prefix } _ksp_type",' \
2004+ not in set_options_callback
2005+ assert f'PetscOptionsClearValue(NULL,"-{ prefix } _div_tol"));' \
2006+ not in clear_options_callback
2007+ assert f'PetscOptionsClearValue(NULL,"-{ prefix } _ksp_type"));' \
2008+ not in clear_options_callback
2009+
2010+ # Check that options specifed by the `linear_solver_defaults`
2011+ # are still set and cleared
2012+ assert f'PetscOptionsSetValue(NULL,"-{ prefix } _ksp_atol",' \
2013+ in set_options_callback
2014+ assert f'PetscOptionsClearValue(NULL,"-{ prefix } _ksp_atol"));' \
2015+ in clear_options_callback
20102016
20112017
20122018class TestHashing :
@@ -2197,6 +2203,34 @@ def test_get_ksp_type(self):
21972203 assert entry2 ['KSPGetType' ] == 'cg'
21982204 assert entry2 ['kspgettype' ] == 'cg'
21992205
2206+ @skipif ('petsc' )
2207+ def test_get_ksp_type_large_grid (self ):
2208+ """
2209+ Test for a dangling-pointer segfault when reading KSPGetType
2210+ after op.apply(). KSPType is ``const char*`` into KSP-owned memory;
2211+ after SNESDestroy that pointer is invalid. The crash only appeared
2212+ reliably on large grids (n=257) because the freed KSP memory must be
2213+ reclaimed by the heap before Python reads the profiler struct.
2214+ """
2215+ get_info = ['kspgettype' ]
2216+ grid = Grid (shape = (257 , 257 ), dtype = np .float64 )
2217+ e = Function (name = 'e' , grid = grid , space_order = 2 )
2218+ f = Function (name = 'f' , grid = grid , space_order = 2 )
2219+ eq = Eq (e .laplace , f )
2220+
2221+ solver = petscsolve (
2222+ eq , target = e ,
2223+ solver_parameters = {'ksp_type' : 'cg' },
2224+ options_prefix = 'test_ksp_type' ,
2225+ get_info = get_info
2226+ )
2227+ with switchconfig (language = 'petsc' ):
2228+ op = Operator (solver )
2229+ summary = op .apply ()
2230+
2231+ entry = summary .petsc .get_entry ('section0' , 'test_ksp_type' )
2232+ assert entry .KSPGetType == 'cg'
2233+
22002234
22012235class TestPrinter :
22022236
@@ -2781,3 +2815,25 @@ def define(self, dimensions):
27812815 f"rank { rank } : expected { expected [rank ]} , got { actual } "
27822816
27832817 # TODO: add 2d and 3d tests
2818+
2819+
2820+ # @skipif('petsc')
2821+ # def test_apply_memory():
2822+
2823+ # nx = 81
2824+ # ny = 81
2825+
2826+ # grid = Grid(shape=(nx, ny), extent=(2., 2.), dtype=np.float64)
2827+
2828+ # u = Function(name='u', grid=grid, dtype=np.float64, space_order=2)
2829+ # v = Function(name='v', grid=grid, dtype=np.float64, space_order=2)
2830+
2831+ # v.data[:] = 5.0
2832+
2833+ # eq = Eq(v, u.laplace, subdomain=grid.interior)
2834+
2835+ # petsc = petscsolve([eq], u)
2836+
2837+ # with switchconfig(language='petsc'):
2838+ # op = Operator(petsc)
2839+ # op.apply()
0 commit comments