Use f2c mechanism used to convert handles to integers for fortran.
Warn when leaks are found at the end of the simulation.
Add option --cfg=smpi/list-leaks:n to display first n leaks to the user (we can only display pointer and type).
MPI_LB->add_f();
MPI_UB->add_f();
+ simgrid::smpi::F2C::finish_initialization();
}
}
private:
// We use a single lookup table for every type.
// Beware of collisions if id in mpif.h is not unique
- static std::unordered_map<int, F2C*>* f2c_lookup_;
+ static std::unordered_map<unsigned int, F2C*>* f2c_lookup_;
static int f2c_id_;
+ static std::unordered_map<unsigned int, F2C*>::size_type num_default_handles_;
int my_f2c_id_ = -1;
protected:
- static void set_f2c_lookup(std::unordered_map<int, F2C*>* map) { f2c_lookup_ = map; }
+ static void set_f2c_lookup(std::unordered_map<unsigned int, F2C*>* map) { f2c_lookup_ = map; }
static int f2c_id() { return f2c_id_; }
static void f2c_id_increment() { f2c_id_++; }
public:
- static void delete_lookup() { delete f2c_lookup_; }
- static std::unordered_map<int, F2C*>* lookup() { return f2c_lookup_; }
+ static void delete_lookup() { delete f2c_lookup_; f2c_lookup_ = nullptr ;}
+ static std::unordered_map<unsigned int, F2C*>* lookup() { return f2c_lookup_; }
F2C();
virtual ~F2C() = default;
// This method should be overridden in all subclasses to avoid casting the result when calling it.
// For the default one, the MPI_*_NULL returned is assumed to be NULL.
static F2C* f2c(int id);
+ static void finish_initialization() { num_default_handles_ = f2c_lookup_->size(); }
+ static std::unordered_map<unsigned int, F2C*>::size_type get_num_default_handles() { return num_default_handles_;}
};
}
bool is_predefined_;
public:
- Op(MPI_User_function* function, bool commutative, bool predefined=false) : func_(function), is_commutative_(commutative), is_predefined_(predefined) {}
+ Op(MPI_User_function* function, bool commutative, bool predefined=false) : func_(function), is_commutative_(commutative), is_predefined_(predefined) {if(not predefined) this->add_f();}
bool is_commutative() const { return is_commutative_; }
bool is_predefined() const { return is_predefined_; }
bool is_fortran_op() const { return is_fortran_op_; }
if(_smpi_options_initialized)
return;
simgrid::config::declare_flag<bool>("smpi/display-timing", "Whether we should display the timing after simulation.", false);
+ simgrid::config::declare_flag<int>("smpi/list-leaks", "Whether we should display the n first MPI handle leaks (addresses and type only) after simulation", 0);
simgrid::config::declare_flag<bool>("smpi/keep-temps", "Whether we should keep the generated temporary files.", false);
simgrid::config::declare_flag<std::string>("smpi/tmpdir", "tmp dir for dlopen files", "/tmp");
#include <array>
#include <boost/algorithm/string.hpp> /* split */
#include <boost/tokenizer.hpp>
+#include <boost/core/demangle.hpp>
#include <cerrno>
#include <cinttypes>
#include <cstdint> /* intmax_t */
if (smpi_cfg_privatization() == SmpiPrivStrategies::MMAP)
smpi_destroy_global_memory_segments();
- if (simgrid::smpi::F2C::lookup() != nullptr)
+ if (simgrid::smpi::F2C::lookup() != nullptr){
+ if (simgrid::smpi::F2C::lookup()->size() > simgrid::smpi::F2C::get_num_default_handles()){
+ XBT_WARN("Probable Leaks in your code: SMPI detected %zu unfreed MPI handles : "
+ "display types and addresses (n max) with --cfg=smpi/list-leaks:n.\n"
+ "Running smpirun with -wrapper \"valgrind --leak-check=full\" can provide more information",
+ simgrid::smpi::F2C::lookup()->size() - simgrid::smpi::F2C::get_num_default_handles());
+ int n = simgrid::config::get_value<int>("smpi/list-leaks");
+ if (n > 0) {
+ std::for_each(simgrid::smpi::F2C::lookup()->begin(),
+ simgrid::smpi::F2C::lookup()->end(),
+ [n](const std::pair<unsigned int, simgrid::smpi::F2C*> &p) {
+ if(p.first >= simgrid::smpi::F2C::get_num_default_handles() && p.first < simgrid::smpi::F2C::get_num_default_handles() + n)
+ XBT_WARN ("Leak %p of type %s", p.second, boost::core::demangle(typeid(*(p.second)).name()).c_str() );
+ });
+ }
+ }
simgrid::smpi::F2C::delete_lookup();
+ }
}
void smpi_mpi_init() {
errhandler_->ref();
//First creation of comm is done before SIMIX_run, so only do comms for others
if(in_id==MPI_UNDEFINED && smp==0 && this->rank()!=MPI_UNDEFINED ){
+ this->add_f();
+ group->add_f();
int id;
if(this->rank()==0){
static int global_id_ = 0;
Group::unref(comm->group_);
if(comm->refcount_==0){
+ if(simgrid::smpi::F2C::lookup() != nullptr)
+ F2C::free_f(comm->c2f());
comm->cleanup_smp();
comm->cleanup_attr<Comm>();
if (comm->info_ != MPI_INFO_NULL)
const MPI_Datatype name = &_XBT_CONCAT(mpi_, name);
// Predefined data types
+CREATE_MPI_DATATYPE_NULL(MPI_DATATYPE_NULL, -1)
+CREATE_MPI_DATATYPE(MPI_DOUBLE, 0, double)
+CREATE_MPI_DATATYPE(MPI_INT, 1, int)
CREATE_MPI_DATATYPE(MPI_CHAR, 2, char)
CREATE_MPI_DATATYPE(MPI_SHORT, 3, short)
-CREATE_MPI_DATATYPE(MPI_INT, 1, int)
CREATE_MPI_DATATYPE(MPI_LONG, 4, long)
+CREATE_MPI_DATATYPE(MPI_FLOAT, 5, float)
+CREATE_MPI_DATATYPE(MPI_BYTE, 6, int8_t)
CREATE_MPI_DATATYPE(MPI_LONG_LONG, 7, long long)
CREATE_MPI_DATATYPE(MPI_SIGNED_CHAR, 8, signed char)
CREATE_MPI_DATATYPE(MPI_UNSIGNED_CHAR, 9, unsigned char)
CREATE_MPI_DATATYPE(MPI_UNSIGNED, 11, unsigned int)
CREATE_MPI_DATATYPE(MPI_UNSIGNED_LONG, 12, unsigned long)
CREATE_MPI_DATATYPE(MPI_UNSIGNED_LONG_LONG, 13, unsigned long long)
-CREATE_MPI_DATATYPE(MPI_FLOAT, 5, float)
-CREATE_MPI_DATATYPE(MPI_DOUBLE, 0, double)
CREATE_MPI_DATATYPE(MPI_LONG_DOUBLE, 14, long double)
CREATE_MPI_DATATYPE(MPI_WCHAR, 15, wchar_t)
CREATE_MPI_DATATYPE(MPI_C_BOOL, 16, bool)
-CREATE_MPI_DATATYPE(MPI_BYTE, 6, int8_t)
CREATE_MPI_DATATYPE(MPI_INT8_T, 17, int8_t)
CREATE_MPI_DATATYPE(MPI_INT16_T, 18, int16_t)
CREATE_MPI_DATATYPE(MPI_INT32_T, 19, int32_t)
CREATE_MPI_DATATYPE(MPI_REAL4, 39, float)
CREATE_MPI_DATATYPE(MPI_REAL8, 40, double)
CREATE_MPI_DATATYPE(MPI_REAL16, 41, long double)
-CREATE_MPI_DATATYPE_NULL(MPI_DATATYPE_NULL, -1)
CREATE_MPI_DATATYPE(MPI_COMPLEX8, 42, float_float)
CREATE_MPI_DATATYPE(MPI_COMPLEX16, 43, double_double)
CREATE_MPI_DATATYPE(MPI_COMPLEX32, 44, double_double)
// Internal use only
CREATE_MPI_DATATYPE(MPI_PTR, 54, void*)
CREATE_MPI_DATATYPE(MPI_COUNT, 55, long long)
-
+#define NUM_BASIC_DATATYPES 57
namespace simgrid{
namespace smpi{
Datatype::Datatype(int size, MPI_Aint lb, MPI_Aint ub, int flags) : size_(size), lb_(lb), ub_(ub), flags_(flags)
{
+ this->add_f();
#if SIMGRID_HAVE_MC
if(MC_is_active())
MC_ignore(&(refcount_), sizeof(refcount_));
Datatype::Datatype(Datatype* datatype, int* ret)
: size_(datatype->size_), lb_(datatype->lb_), ub_(datatype->ub_), flags_(datatype->flags_)
{
+ this->add_f();
*ret = this->copy_attrs(datatype);
}
return;
//prevent further usage
flags_ &= ~ DT_FLAG_COMMITED;
+ F2C::free_f(this->c2f());
//if still used, mark for deletion
if(refcount_!=0){
flags_ |=DT_FLAG_DESTROYED;
return;
}
-
cleanup_attr<Datatype>();
delete contents_;
}
{
return static_cast<Datatype*>(F2C::f2c(id));
}
+
} // namespace smpi
} // namespace simgrid
namespace simgrid{
namespace smpi{
-std::unordered_map<int, F2C*>* F2C::f2c_lookup_ = nullptr;
+std::unordered_map<unsigned int, F2C*>* F2C::f2c_lookup_ = nullptr;
int F2C::f2c_id_ = 0;
+std::unordered_map<unsigned int, F2C*>::size_type F2C::num_default_handles_ = 0;
// Keep it non trivially-constructible, or it will break MC+smpi on FreeBSD with Clang (don't ask why)
F2C::F2C() = default;
int F2C::add_f()
{
if (f2c_lookup_ == nullptr)
- f2c_lookup_ = new std::unordered_map<int, F2C*>();
+ f2c_lookup_ = new std::unordered_map<unsigned int, F2C*>();
my_f2c_id_ = f2c_id();
(*f2c_lookup_)[my_f2c_id_] = this;
int F2C::c2f()
{
if (f2c_lookup_ == nullptr) {
- f2c_lookup_ = new std::unordered_map<int, F2C*>();
+ f2c_lookup_ = new std::unordered_map<unsigned int, F2C*>();
}
if(my_f2c_id_==-1)
F2C* F2C::f2c(int id)
{
if (f2c_lookup_ == nullptr)
- f2c_lookup_ = new std::unordered_map<int, F2C*>();
+ f2c_lookup_ = new std::unordered_map<unsigned int, F2C*>();
if(id >= 0){
auto comm = f2c_lookup_->find(id);
simgrid::smpi::colls::bcast(&shared_mutex_, 1, MPI_AINT, 0, comm);
if(comm_->rank() != 0)
intrusive_ptr_add_ref(&*shared_mutex_);
+ this->add_f();
}
File::~File(){
}
delete win_;
delete file_;
+ F2C::free_f(this->c2f());
if (info_ != MPI_INFO_NULL)
simgrid::smpi::Info::unref(info_);
if (errhandler_ != MPI_ERRHANDLER_NULL)
simgrid::smpi::Group mpi_MPI_GROUP_EMPTY;
MPI_Group MPI_GROUP_EMPTY=&mpi_MPI_GROUP_EMPTY;
+extern XBT_PRIVATE MPI_Comm MPI_COMM_UNINITIALIZED;
namespace simgrid{
namespace smpi{
{
group->refcount_--;
if (group->refcount_ <= 0) {
+ if (simgrid::smpi::F2C::lookup() != nullptr)
+ F2C::free_f(group->c2f());
delete group;
}
}
s4u::Actor* actor = this->actor(ranks[i]); // ranks[] was passed as a param!
(*newgroup)->set_mapping(actor, i);
}
+ (*newgroup)->add_f();
}
return MPI_SUCCESS;
}
s4u::Actor* actor = group2->actor(i - size2);
(*newgroup)->set_mapping(actor, i);
}
+ (*newgroup)->add_f();
}
return MPI_SUCCESS;
}
(*newgroup)->set_mapping(actor, j);
j++;
}
+ (*newgroup)->add_f();
}
}
return MPI_SUCCESS;
(*newgroup)->set_mapping(actor, i);
}
}
+ (*newgroup)->add_f();
}
return MPI_SUCCESS;
}
j++;
}
}
+ (*newgroup)->add_f();
return MPI_SUCCESS;
}
break;
}
}
+ (*newgroup)->add_f();
return MPI_SUCCESS;
}
oldrank++;
}
}
+ (*newgroup)->add_f();
return MPI_SUCCESS;
}
void Op::unref(MPI_Op* op){
if((*op)!=MPI_OP_NULL){
(*op)->refcount_--;
- if ((*op)->refcount_ == 0 && not (*op)->is_predefined_)
+ if ((*op)->refcount_ == 0 && not (*op)->is_predefined_){
+ F2C::free_f((*op)->c2f());
delete(*op);
+ }
}
}
nbc_requests_=nullptr;
nbc_requests_size_=0;
init_buffer(count);
+ this->add_f();
}
void Request::ref(){
Op::unref(&(*request)->op_);
(*request)->print_request("Destroying");
+ F2C::free_f((*request)->c2f());
delete *request;
*request = MPI_REQUEST_NULL;
}else{
colls::bcast(&(bar_), sizeof(s4u::Barrier*), MPI_BYTE, 0, comm);
colls::barrier(comm);
+ this->add_f();
}
Win::~Win(){
if(allocated_ !=0)
xbt_free(base_);
+ F2C::free_f(this->c2f());
cleanup_attr<Win>();
}