-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve multithread support #188
Changes from all commits
558fb82
d98affc
46e08f3
e066555
bb86bcc
ab5bf1d
f34704a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,9 @@ | |
#include <mfmg/common/instantiation.hpp> | ||
#include <mfmg/common/operator.hpp> | ||
#include <mfmg/dealii/amge_host.hpp> | ||
// Needed for MatrixFreeAgglomerateOperator, the definition should be moved | ||
// elsewhere. | ||
#include <mfmg/dealii/amge_host.templates.hpp> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment it is included for |
||
#include <mfmg/dealii/dealii_matrix_free_hierarchy_helpers.hpp> | ||
#include <mfmg/dealii/dealii_matrix_free_mesh_evaluator.hpp> | ||
#include <mfmg/dealii/dealii_matrix_free_operator.hpp> | ||
|
@@ -83,6 +86,7 @@ DealIIMatrixFreeHierarchyHelpers<dim, VectorType>::build_restrictor( | |
std::unique_ptr<dealii::TrilinosWrappers::SparseMatrix> eigenvector_matrix; | ||
std::unique_ptr<dealii::TrilinosWrappers::SparseMatrix> | ||
delta_eigenvector_matrix; | ||
|
||
amge.setup_restrictor(agglomerate_params, n_eigenvectors, tolerance, | ||
*dealii_mesh_evaluator, locally_relevant_global_diag, | ||
restrictor_matrix, eigenvector_matrix, | ||
|
@@ -125,91 +129,91 @@ DealIIMatrixFreeHierarchyHelpers<dim, VectorType>::build_restrictor( | |
std::vector<std::vector<dealii::TrilinosScalar>> values_per_row; | ||
} copy_data; | ||
|
||
auto worker = | ||
[&](const std::vector<std::vector<unsigned int>>::const_iterator | ||
&agglomerate_it, | ||
ScratchData &, CopyData &local_copy_data) { | ||
dealii::Triangulation<dim> agglomerate_triangulation; | ||
std::map<typename dealii::Triangulation<dim>::active_cell_iterator, | ||
typename dealii::DoFHandler<dim>::active_cell_iterator> | ||
patch_to_global_map; | ||
amge.build_agglomerate_triangulation(*agglomerate_it, | ||
agglomerate_triangulation, | ||
patch_to_global_map); | ||
if (patch_to_global_map.empty()) | ||
auto worker = [&](const std::vector<std::vector<unsigned int>>:: | ||
const_iterator &agglomerate_it, | ||
ScratchData &, CopyData &local_copy_data) { | ||
dealii::Triangulation<dim> agglomerate_triangulation; | ||
std::map<typename dealii::Triangulation<dim>::active_cell_iterator, | ||
typename dealii::DoFHandler<dim>::active_cell_iterator> | ||
patch_to_global_map; | ||
amge.build_agglomerate_triangulation( | ||
*agglomerate_it, agglomerate_triangulation, patch_to_global_map); | ||
if (patch_to_global_map.empty()) | ||
{ | ||
return; | ||
} | ||
|
||
// Now that we have the triangulation, we can do the evaluation on | ||
// the agglomerate | ||
dealii::DoFHandler<dim> agglomerate_dof_handler( | ||
agglomerate_triangulation); | ||
agglomerate_dof_handler.distribute_dofs( | ||
dealii_mesh_evaluator->get_dof_handler().get_fe()); | ||
|
||
// Put the result in the matrix | ||
// Compute the map between the local and the global dof indices. | ||
local_copy_data.rows.resize(n_local_eigenvectors); | ||
|
||
local_copy_data.cols = amge.compute_dof_index_map( | ||
patch_to_global_map, agglomerate_dof_handler); | ||
auto const &dof_indices_map = local_copy_data.cols; | ||
unsigned int const n_elem = dof_indices_map.size(); | ||
|
||
// We need a clean reset for the values we are going to store. | ||
// Otherwise, we would accumulate values across patches | ||
// corresponding to different degrees of freedom. | ||
local_copy_data.values_per_row.resize(n_local_eigenvectors); | ||
std::fill(local_copy_data.values_per_row.begin(), | ||
local_copy_data.values_per_row.end(), | ||
std::vector<dealii::TrilinosScalar>(n_elem)); | ||
|
||
unsigned int const i = agglomerate_it - agglomerates_vector.begin(); | ||
|
||
for (unsigned int j = 0; j < n_local_eigenvectors; ++j) | ||
{ | ||
unsigned int const local_row = i * n_local_eigenvectors + j; | ||
unsigned int const global_row = | ||
eigenvector_matrix->locally_owned_range_indices() | ||
.nth_index_in_set(local_row); | ||
// Get the vector used for the matrix-vector multiplication | ||
dealii::Vector<ScalarType> delta_eig(n_elem); | ||
if (is_halo_agglomerate) | ||
{ | ||
for (unsigned int k = 0; k < n_elem; ++k) | ||
{ | ||
return; | ||
delta_eig[k] = | ||
delta_eigenvector_matrix->el(global_row, dof_indices_map[k]) + | ||
eigenvector_matrix->el(global_row, dof_indices_map[k]); | ||
} | ||
|
||
// Now that we have the triangulation, we can do the evaluation on | ||
// the agglomerate | ||
dealii::DoFHandler<dim> agglomerate_dof_handler( | ||
agglomerate_triangulation); | ||
agglomerate_dof_handler.distribute_dofs( | ||
dealii_mesh_evaluator->get_dof_handler().get_fe()); | ||
|
||
// Put the result in the matrix | ||
// Compute the map between the local and the global dof indices. | ||
local_copy_data.rows.resize(n_local_eigenvectors); | ||
|
||
local_copy_data.cols = amge.compute_dof_index_map( | ||
patch_to_global_map, agglomerate_dof_handler); | ||
auto const &dof_indices_map = local_copy_data.cols; | ||
unsigned int const n_elem = dof_indices_map.size(); | ||
|
||
// We need a clean reset for the values we are going to store. | ||
// Otherwise, we would accumulate values across patches | ||
// corresponding to different degrees of freedom. | ||
local_copy_data.values_per_row.resize(n_local_eigenvectors); | ||
std::fill(local_copy_data.values_per_row.begin(), | ||
local_copy_data.values_per_row.end(), | ||
std::vector<dealii::TrilinosScalar>(n_elem)); | ||
|
||
unsigned int const i = agglomerate_it - agglomerates_vector.begin(); | ||
|
||
for (unsigned int j = 0; j < n_local_eigenvectors; ++j) | ||
} | ||
else | ||
{ | ||
for (unsigned int k = 0; k < n_elem; ++k) | ||
{ | ||
unsigned int const local_row = i * n_local_eigenvectors + j; | ||
unsigned int const global_row = | ||
eigenvector_matrix->locally_owned_range_indices() | ||
.nth_index_in_set(local_row); | ||
// Get the vector used for the matrix-vector multiplication | ||
dealii::Vector<ScalarType> delta_eig(n_elem); | ||
if (is_halo_agglomerate) | ||
{ | ||
for (unsigned int k = 0; k < n_elem; ++k) | ||
{ | ||
delta_eig[k] = | ||
delta_eigenvector_matrix->el(global_row, | ||
dof_indices_map[k]) + | ||
eigenvector_matrix->el(global_row, dof_indices_map[k]); | ||
} | ||
} | ||
else | ||
{ | ||
for (unsigned int k = 0; k < n_elem; ++k) | ||
{ | ||
delta_eig[k] = delta_eigenvector_matrix->el( | ||
global_row, dof_indices_map[k]); | ||
} | ||
} | ||
|
||
// Perform the matrix-vector multiplication | ||
dealii::Vector<ScalarType> correction(n_elem); | ||
dealii_mesh_evaluator->matrix_free_initialize_agglomerate( | ||
agglomerate_dof_handler); | ||
dealii_mesh_evaluator->matrix_free_evaluate_agglomerate( | ||
delta_eig, correction); | ||
|
||
// Store the values the delta correction matrix is to be filled | ||
// with. | ||
local_copy_data.rows[j] = global_row; | ||
std::transform(correction.begin(), correction.end(), | ||
local_copy_data.values_per_row[j].begin(), | ||
local_copy_data.values_per_row[j].begin(), | ||
std::plus<double>()); | ||
delta_eig[k] = | ||
delta_eigenvector_matrix->el(global_row, dof_indices_map[k]); | ||
} | ||
}; | ||
} | ||
|
||
// Perform the matrix-vector multiplication | ||
dealii::Vector<ScalarType> correction(n_elem); | ||
dealii::AffineConstraints<double> agglomerate_constraints; | ||
using AgglomerateOperator = | ||
MatrixFreeAgglomerateOperator<DealIIMatrixFreeMeshEvaluator<dim>>; | ||
AgglomerateOperator agglomerate_operator(*dealii_mesh_evaluator, | ||
agglomerate_dof_handler, | ||
agglomerate_constraints); | ||
agglomerate_operator.vmult(correction, delta_eig); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These changes look reasonable but are lost in all the code formatting mess. |
||
|
||
// Store the values the delta correction matrix is to be filled | ||
// with. | ||
local_copy_data.rows[j] = global_row; | ||
std::transform(correction.begin(), correction.end(), | ||
local_copy_data.values_per_row[j].begin(), | ||
local_copy_data.values_per_row[j].begin(), | ||
std::plus<double>()); | ||
} | ||
}; | ||
|
||
auto copier = [&](const CopyData &local_copy_data) { | ||
for (unsigned int i = 0; i < local_copy_data.rows.size(); ++i) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -217,8 +217,7 @@ int main(int argc, char *argv[]) | |
{ | ||
namespace boost_po = boost::program_options; | ||
|
||
MPI_Init(&argc, &argv); | ||
dealii::MultithreadInfo::set_thread_limit(1); | ||
dealii::Utilities::MPI::MPI_InitFinalize mpi_init(argc, argv); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed that deal.II does not assert that the level of thread support available is sufficient (does not assert I have nothing against the change you suggest, even more so since this line is the only direct call to edit @masterleinad I realized I had pasted the wrong link There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For requesting explicit thread support we need to call
In the end, I was just seeing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated link to deal.II code |
||
|
||
boost_po::options_description cmd("Available options"); | ||
cmd.add_options()("help,h", "produce help message"); | ||
|
@@ -250,7 +249,7 @@ int main(int argc, char *argv[]) | |
dim = vm["dim"].as<int>(); | ||
mfmg::ASSERT(dim == 2 || dim == 3, "Dimension must be 2 or 3"); | ||
|
||
bool matrix_free = false; | ||
bool matrix_free = true; | ||
if (vm.count("matrix_free")) | ||
matrix_free = vm["matrix_free"].as<bool>(); | ||
|
||
|
@@ -275,7 +274,6 @@ int main(int argc, char *argv[]) | |
if (matrix_free) | ||
{ | ||
params->put("smoother.type", "Chebyshev"); | ||
|
||
if (dim == 2) | ||
{ | ||
switch (fe_degree) | ||
|
@@ -419,13 +417,12 @@ int main(int argc, char *argv[]) | |
} | ||
else | ||
{ | ||
dealii::MultithreadInfo::set_thread_limit(1); | ||
if (dim == 2) | ||
matrix_based_two_grids<2>(params); | ||
else | ||
matrix_based_two_grids<3>(params); | ||
} | ||
|
||
MPI_Finalize(); | ||
|
||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remind me why this cannot be pure virtual.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to discuss why this is OK.
My objections are: we force the user to implement to boiler plate code, we have no way of knowing how much data he stuffed into his derived class and this could be costly.
Also I would like to understand where the race condition happen :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be much easier if we have a uniform interface for global/agglomerate initialization and evaluation or separate user classes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if we need to modify the matrix-based version as well.