1
1
and https://svn.open-mpi.org/trac/ompi/ticket/1853, mallopt() hints do
not always work -- it is possible for memory to be returned to the OS
and therefore OMPI's registration cache becomes invalid.

This commit removes all use of mallopt() and uses a different way to
integrate ptmalloc2 than we have done in the past.  In particular, we
use almost exactly the same technique as MX:

 * Remove all uses of mallopt, to include the opal/memory mallopt
   component.
 * Name-shift all of OMPI's internal ptmalloc2 public symbols (e.g.,
   malloc -> opal_memory_ptmalloc2_malloc).
 * At run-time, use the existing glibc allocator malloc hook function
   pointers to fully hijack the glibc allocator with our own
   name-shifted ptmalloc2.
 * Make the decision whether to hijack the glibc allocator ''at run
   time'' (vs. at link time, as previous ptmalloc2 integration
   attempts have done).  Look at the OMPI_MCA_mpi_leave_pinned
   and OMPI_MCA_mpi_leave_pinned_pipeline environment variables and
   the existence of /sys/class/infiniband to determine if we should
   install the hooks or not.
 * As an added bonus, we can now tell if libopen-pal is linked
   statically or dynamically, and if we're linked statically, we
   assume that munmap intercept support doesn't work.

See the opal/mca/memory/ptmalloc2/README-open-mpi.txt file for all the
gory details about the implementation.

Fixes trac:1853.

This commit was SVN r20921.

The following Trac tickets were found above:
  Ticket 1853 --> https://svn.open-mpi.org/trac/ompi/ticket/1853
Этот коммит содержится в:
Jeff Squyres 2009-04-01 17:52:16 +00:00
родитель b7a052a81d
Коммит 0d52271cd6
17 изменённых файлов: 595 добавлений и 180 удалений

Просмотреть файл

@ -10,7 +10,7 @@
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2006-2008 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2006-2009 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2006-2009 Mellanox Technologies. All rights reserved.
* Copyright (c) 2006-2007 Los Alamos National Security, LLC. All rights
* reserved.
@ -1723,8 +1723,8 @@ static int init_one_device(opal_list_t *btl_list, struct ibv_device* ib_dev)
mca_mpool_base_module_create(mca_btl_openib_component.ib_mpool_name,
device, &mpool_resources);
if(NULL == device->mpool){
BTL_ERROR(("error creating IB memory pool for %s errno says %s",
ibv_get_device_name(device->ib_dev), strerror(errno)));
/* Don't print an error message here -- we'll get one from
mpool_create anyway (OPAL_SOS would be good here...) */
goto error;
}
@ -2099,13 +2099,10 @@ btl_openib_component_init(int *num_btl_modules,
mpi_leave_pinned==-1, then unless the user explicitly set
mpi_leave_pinned_pipeline==0, then set mpi_leave_pinned to 1.
We have a memory manager if:
- we have both FREE and MUNMAP support
- we have MUNMAP support and the linux mallopt */
if (((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) ==
((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) & value)) ||
(0 != (OPAL_MEMORY_MUNMAP_SUPPORT & value) &&
OMPI_MPOOL_BASE_HAVE_LINUX_MALLOPT)) {
We have a memory manager if we have both FREE and MUNMAP
support */
if ((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) ==
((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) & value)) {
ret = 0;
index = mca_base_param_find("mpi", NULL, "leave_pinned");
if (index >= 0) {

Просмотреть файл

@ -224,9 +224,13 @@ You may need to consult with your system administrator to get this
problem fixed.
#
[no active ports found]
WARNING: There is at least one OpenFabrics device found on host '%s',
but there are no active ports detected. This is most certainly not
what you wanted. Check your cables, SM configuration, etc.
WARNING: There is at least one OpenFabrics device found but there are
no active ports detected (or Open MPI was unable to use them). This
is most certainly not what you wanted. Check your cables, subnet
manager configuration, etc. The openib BTL will be ignored for this
job.
Local host: %s
#
[error in device init]
WARNING: There was an error initializing an OpenFabrics device.

Просмотреть файл

@ -11,6 +11,7 @@
* All rights reserved.
* Copyright (c) 2008 Myricom. All rights reserved.
* Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) 2009 Cisco systems, Inc. All rights reserved.
*
* $COPYRIGHT$
*
@ -65,10 +66,8 @@ ompi_common_mx_initialize(void)
- we have both FREE and MUNMAP support
- we have MUNMAP support and the linux mallopt */
value = opal_mem_hooks_support_level();
if (((value & (OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT))
== (OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT))
|| ((value & OPAL_MEMORY_MUNMAP_SUPPORT) &&
OMPI_MPOOL_BASE_HAVE_LINUX_MALLOPT)) {
if ((value & (OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT))
== (OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT)) {
index = mca_base_param_find("mpi", NULL, "leave_pinned");
if (index >= 0)
if ((mca_base_param_lookup_int(index, &value) == OPAL_SUCCESS)

Просмотреть файл

@ -9,7 +9,7 @@
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2008 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
@ -30,15 +30,7 @@
#include "ompi/mca/mpool/mpool.h"
#include "opal/threads/mutex.h"
#if defined(HAVE_MALLOPT) && defined(M_TRIM_THRESHOLD) && defined(M_MMAP_MAX)
#define OMPI_MPOOL_BASE_HAVE_LINUX_MALLOPT 1
#else
#define OMPI_MPOOL_BASE_HAVE_LINUX_MALLOPT 0
#endif
#if defined(c_plusplus) || defined(__cplusplus)
extern "C" {
#endif
BEGIN_C_DECLS
static inline unsigned int my_log2(unsigned long val) {
unsigned int count = 0;
@ -97,11 +89,7 @@ OMPI_DECLSPEC extern uint32_t mca_mpool_base_page_size_log;
/* only used within base -- no need to DECLSPEC */
extern int mca_mpool_base_used_mem_hooks;
extern int mca_mpool_base_use_mem_hooks_index;
extern int mca_mpool_base_disable_mallopt_index;
#if defined(c_plusplus) || defined(__cplusplus)
}
#endif
END_C_DECLS
#endif /* MCA_MEM_BASE_H */

Просмотреть файл

@ -1,6 +1,6 @@
# -*- text -*-
#
# Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2007-2009 Cisco Systems, Inc. All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
@ -30,8 +30,20 @@ PID: %d
%d additional leak%s recorded but %s not displayed here. Set the MCA
parameter mpi_show_mpi_alloc_mem_leaks to a larger number to see that
many leaks, or set it to a negative number to see all leaks.
#
[leave pinned failed]
Process %s on host %s attempted to use the leave pinned
feature, but no memory registration hooks were found. To solve this
problem, either link in the libopenmpi-malloc library or (on Linux)
do not set the MCA parameter base_disable_mallopt.
A process attempted to use the "leave pinned" MPI feature, but no
memory registration hooks were found on the system at run time. This
may be the result of running on a system that does not support memory
hooks or having some other software subvert Open MPI's use of the
memory hooks. You can disable Open MPI's use of memory hooks by
setting both the mpi_leave_pinned and mpi_leave_pinned_pipeline MCA
parameters to 0.
Open MPI will disable any transports that are attempting to use the
leave pinned functionality; your job may still run, but may fall back
to a slower network transport (such as TCP).
Mpool name: %s
Process: %s
Local host: %s

Просмотреть файл

@ -11,7 +11,7 @@
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2006-2007 Mellanox Technologies. All rights reserved.
* Copyright (c) 2008 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
@ -71,7 +71,6 @@ mca_mpool_base_module_t* mca_mpool_base_module_create(
mca_mpool_base_module_t* module = NULL;
opal_list_item_t* item;
mca_mpool_base_selected_module_t *sm;
int use_mem_hooks, disable_mallopt;
for (item = opal_list_get_first(&mca_mpool_base_components);
item != opal_list_get_end(&mca_mpool_base_components);
@ -99,45 +98,30 @@ mca_mpool_base_module_t* mca_mpool_base_module_create(
sm->mpool_resources = resources;
opal_list_append(&mca_mpool_base_modules, (opal_list_item_t*) sm);
/* on the very first creation of a module we init the memory
callback and (if needed) disable free() returning memory to the
OS. Note that even when we disable free() with mallopt, we
still need to register a callback to handle the case of the
user calling mmap/munmap on his own. */
callback */
if (opal_list_get_size(&mca_mpool_base_modules) == 1) {
/* Default to not using memory hooks */
int use_mem_hooks = 0;
/* Lookup the current value of the MCA params and see if any
other entity in the code base requested mem hooks */
mca_base_param_lookup_int(mca_mpool_base_use_mem_hooks_index,
&use_mem_hooks);
mca_base_param_lookup_int(mca_mpool_base_disable_mallopt_index,
&disable_mallopt);
/* force mem hooks if leave_pinned or leave_pinned_pipeline is
enabled (note that either of these leave_pinned variables
may have been set by a user MCA param or elsewhere in the
code base) */
if (1 == ompi_mpi_leave_pinned || ompi_mpi_leave_pinned_pipeline) {
/* Use the memory hooks if leave_pinned or
leave_pinned_pipeline is enabled (note that either of these
leave_pinned variables may have been set by a user MCA
param or elsewhere in the code base). Yes, we could have
coded this more succinctly, but this is more clear. */
if (ompi_mpi_leave_pinned || ompi_mpi_leave_pinned_pipeline) {
use_mem_hooks = 1;
}
if (use_mem_hooks) {
if (0 != (OPAL_MEMORY_FREE_SUPPORT & opal_mem_hooks_support_level())) {
if ((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) ==
((OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_MUNMAP_SUPPORT) &
opal_mem_hooks_support_level())) {
opal_mem_hooks_register_release(mca_mpool_base_mem_cb, NULL);
OBJ_CONSTRUCT(&mca_mpool_base_mem_cb_array, opal_pointer_array_t);
} else if (!disable_mallopt &&
0 != (OPAL_MEMORY_MUNMAP_SUPPORT & opal_mem_hooks_support_level())) {
opal_mem_hooks_register_release(mca_mpool_base_mem_cb, NULL);
OBJ_CONSTRUCT(&mca_mpool_base_mem_cb_array, opal_pointer_array_t);
/* mallopt_disable_free will only be set to 1 if
HAVE_LINUX_MALLOPT, so this is safe */
#if OMPI_MPOOL_BASE_HAVE_LINUX_MALLOPT
mallopt(M_TRIM_THRESHOLD, -1);
mallopt(M_MMAP_MAX, 0);
#endif
} else {
orte_show_help("help-mpool-base.txt", "leave pinned failed",
true, ORTE_NAME_PRINT(ORTE_PROC_MY_NAME),
orte_process_info.nodename);
orte_process_info.nodename, name);
return NULL;
}

Просмотреть файл

@ -9,7 +9,7 @@
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2007-2009 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
@ -50,11 +50,6 @@ int mca_mpool_base_output = -1;
/* whether we actually used the mem hooks or not */
int mca_mpool_base_used_mem_hooks = 0;
/* should we attempt to use the available memory hooks */
int mca_mpool_base_use_mem_hooks_index;
/* should we attempt to use mallopt to disable free() returning memory
to OS? */
int mca_mpool_base_disable_mallopt_index;
uint32_t mca_mpool_base_page_size;
uint32_t mca_mpool_base_page_size_log;
@ -82,37 +77,6 @@ int mca_mpool_base_open(void)
OBJ_CONSTRUCT(&mca_mpool_base_modules, opal_list_t);
/*
* check for use_mem_hooks (for diagnostics/testing)
* however if leave_pinned is set we force this to be enabled
*/
mca_mpool_base_use_mem_hooks_index =
mca_base_param_reg_int_name("mpool",
"base_use_mem_hooks",
"Use memory hooks for deregistering freed memory",
false,
false,
0,
NULL);
mca_base_param_reg_syn_name(mca_mpool_base_use_mem_hooks_index,
"mpool", "use_mem_hooks", true);
mca_mpool_base_disable_mallopt_index =
mca_base_param_reg_int_name("mpool",
"base_disable_mallopt",
"Do not use mallopt to disable returning memory to "
"the OS when leave_pinned is active and no memory "
"components are found (this value is only changable on Linux systems that support mallopt()).",
false,
#if OMPI_MPOOL_BASE_HAVE_LINUX_MALLOPT
false,
0,
#else
true,
1,
#endif
NULL);
/* get the page size for this architecture*/
mca_mpool_base_page_size = sysconf(_SC_PAGESIZE);
mca_mpool_base_page_size_log = my_log2(mca_mpool_base_page_size);

Просмотреть файл

@ -38,30 +38,29 @@ AM_CPPFLAGS += -I$(srcdir)/sysdeps/generic
docdir = $(datadir)/openmpi/doc
doc_DATA = ptmalloc2-COPYRIGHT
noinst_LTLIBRARIES = libmca_memory_ptmalloc2.la
# These are the files from ptmalloc2 that we care about
ptmalloc2_sources = \
malloc.c \
malloc-stats.c \
malloc.h
# This component is only ever built statically (i.e., slurped into
# libopen-pal) -- it is never built as a DSO.
noinst_LTLIBRARIES = libmca_memory_ptmalloc2.la
libmca_memory_ptmalloc2_la_SOURCES = \
opal_ptmalloc2_component.c \
opal_ptmalloc2_munmap.c
if OMPI_WANT_EXTERNAL_PTMALLOC2
lib_LTLIBRARIES = libopenmpi-malloc.la
libopenmpi_malloc_la_SOURCES = \
malloc.c \
malloc-stats.c \
malloc.h
else
libmca_memory_ptmalloc2_la_SOURCES += \
malloc.c \
malloc-stats.c \
malloc.h
endif
libmca_memory_ptmalloc2_la_LDFLAGS = -module -avoid-version $(memory_ptmalloc2_LDFLAGS)
opal_ptmalloc2_munmap.c \
rename.h \
$(ptmalloc2_sources)
libmca_memory_ptmalloc2_la_LDFLAGS = \
-module -avoid-version $(memory_ptmalloc2_LDFLAGS)
libmca_memory_ptmalloc2_la_LIBADD = $(memory_ptmalloc2_LIBS)
# For hysterical raisins, we create a dummy libopenmpi_malloc.la. See
# README-open-mpi.txt for details
lib_LTLIBRARIES = libopenmpi_malloc.la
libopenmpi_malloc_la_SOURCES = dummy.c
# these are included directly and shouldn't be built solo
EXTRA_libmca_memory_ptmalloc2_la_SOURCES = \
arena.c \

150
opal/mca/memory/ptmalloc2/README-open-mpi.txt Обычный файл
Просмотреть файл

@ -0,0 +1,150 @@
30 March 2009
This file documents Open MPI's usage of ptmalloc2. This is perhaps
our 7,208,499th iteration of ptmalloc2 support, so let's document it
here so that some future developer might spend *slightly* less time
understanding what the heck is going on.
See glibc documentation about malloc hooks before continuing. This is
pretty much required reading before reading the rest of this file /
having a hope of understanding what's going on here:
http://www.gnu.org/software/libc/manual/html_mono/libc.html#Hooks-for-Malloc
The overall goal is that we're using the Linux glibc hooks to wholly
replace the underlying allocator. We *used* to use horrid linker
tricks to interpose OMPI's ptmalloc2 symbols with the glibc ones --
meaning that user apps would call our symbols and not the glibc ones.
But that scheme is fraught with problems, not the least of which is
that *all* MPI applications will be forced to use our overridden
allocator (not just the ones that need it, such as the ones running on
OpenFabrics-based networks). Instead, what we do here is, frankly,
quite similar to what is done in MX: we use the 4 glibc hooks to
assert our own malloc, realloc, free, and memalign functions. This
allows the decision as to whether to use this internal ptmalloc2
allocate to be a run-time decision. This is quite important; using
this internal allocator has both benefits (allowing using
mpi_leave_pinned=1 behavior) and drawbacks (breaking some debuggers,
being unnecessary for non-OpenFabrics-based networks, etc.).
Here's how it works...
This component *must* be linked statically as part of libopen-pal; it
*cannot* be a DSO. Specifically, this library must be present during
pre-main() initialization phases so that its __malloc_initialize_hook
can be found and executed. Loading it as a DSO during MPI_INIT is far
too late. In configure.m4, we define the M4 macro
MCA_memory_ptmalloc2_COMPILE_MODE to always compile this component in
static mode. Yay flexible build system.
This component provides an munmap() function that will intercept calls
to munmap() and do the Right Thing. That is fairly straightforward to
do. Intercepting the malloc/free/etc. allocator is much more
complicated.
All the ptmalloc2 public symbols in this component have been name
shifted via the rename.h file. Hence, what used to be "malloc" is now
opal_memory_ptmalloc2_malloc. Since all the public symbols are
name-shifted, we can safely link this component in all MPI
applications. Specifically: just because this ptmalloc2 allocator is
present in all OMPI executables and user-level applications, it won't
necessarily be used -- it's a separate/run-time decision as to whether
it will be used.
For hysterical raisins (v1.3.0 and v1.3.1), an empty
libopenmpi_malloc.la is created. This library *used* to be the whole
ptmalloc2 allocator, but since we're now name-shifting all the
ptmalloc2 symbols, it's no longer necessary to make it a separate
library. Having an empty/dummy library of this name ensures that
users who added -lopenmpi_malloc to their compile/link lines won't
fail linking. They may get a linker warning about no symbols being
used in this library -- but that's a Good Thing; it'll encourage users
to stop linking in this library.
We set the __malloc_initialize_hook variable to point to
opal_memory_ptmalloc2_malloc_init_hook (in hooks.c). This function is
called by the underlying glibc allocator before any allocations occur
and before the memory allocation subsystem is setup. As such, this
function is *extremely* restricted in what it can do. It cannot call
any form of malloc, for example (which seems fairly obvious, but it's
worth mentioning :-) ). This function is one of the determining
steps as to whether we'll use the internal ptmalloc2 allocator or
not. It performs checks including (but not limited to; see hooks.c
for the most up-to-date set of tests):
- see if the OMPI_MCA_mpi_leave_pinned environment variable is set.
Yes, I know this is a horrid abstraction violation, but this
function may be invoked pre-main -- it's certainly before MCA
parameters have been setup. So just getenv() and see if it has been
set.
- look for the hard-coded filename /sys/class/infiniband.
- if the env variable was not set, but the file is there, enable our
ptmalloc2.
- if the env variable was set to 0, disable our ptmalloc2
- if the env variable is set to -1, enable our ptmalloc2 if the file
was found
- if the env variable is any other value, enable our ptmalloc2
- if the file is a static library, then override all of the above and
disable our ptmalloc2
- if we're enabling our ptmalloc2, initialize ptmalloc (via
ptmalloc_init()) and then set the 4 hooks to point to our
name-shifted ptmalloc2 functions
Hence, sometime during process startup, this function will definitely
be called. It will either set the 4 hook functions to point to our
name-shifted ptmalloc2 functions, or it won't. If the 4 hook
functions are set, then the underlying glibc allocator will always
call our 4 functions in all the relevant places instead of calling its
own functions. Specifically: the process is calling the underlying
glibc allocator, but that underlying glibc allocator will make
function pointer callbacks to our name-shifted ptmalloc2 functions to
actually do the work.
Note that because we know our ptmalloc will not be providing all 5
hook variables (because we want to use the underlying glibc hook
variables), they are #if 0'ed out in our malloc.c. This has the
direct consequence that the *_hook_ini() in hooks.c are never used.
So to avoid compiler/linker warnings, I #if 0'ed those out as well.
All the public functions in malloc.c that call hook functions were
modified to #if 0 the hook function invocations. After all, that's
something that we want the *underlying* glibc allocator to do -- but
we are putting these functions as the hooks, so we don't want to
invoke ourselves in an infinite loop!
The next thing that happens in the startup sequence is that the
ptmalloc2 memory component's "open" function is called during
MPI_INIT. As stated above, we always intercept munmap() -- this is
acceptable in all environments. But we need to test to see if the
glibc memory hooks have been overridden before MPI_INIT was invoked.
If so, we need to signal that our allocator support may not be
complete.
Patrick Geofray/MX suggests a simple test: malloc() 4MB and then free
it. Watch to see if our name-shifted ptmalloc2 free() function was
invoked. If it was, then all of our hooks are probably in place and
we can proceed. If not, then set flags indicating that this memory
allocator only supports MUNMAP (not FREE/CHUNK).
NOTE: we *used* to simply set the FREE/CHUNK support flags during our
ptmalloc2's internal ptmalloc_init() function. This is not a good
idea becaus eeven after our ptmalloc_init() function has been invoked,
someone may come in an override our memory hooks. Doing a malloc/free
test during the ptmalloc2 memory component's open function seems to be
the safest way to test whether we *actually* support FREE/CHUNK (this
is what MX does, too).
Much later in the init sequence during MPI_INIT, components indicate
whether they want to use mpi_leave_pinned[_pipeline] support or not.
For example, the openib BTL queries the opal_mem_hooks_support_level()
function to see if FREE and MUNMAP are supported. If they are, then
the openib BTL sets mpi_leave_pinned = 1.
Finally, the mpool base does a final check. If
mpi_leave_pinned[_pipeline] is set to 1 and/or use_mem_hooks is set,
if FREE/MUNMAP are not set in the supported flags, then a warning is
printed. Otherwise, life continues (assumedly using
mpi_leave_pinned[_pipeline] support).
Simple, right?

Просмотреть файл

@ -465,15 +465,6 @@ ptmalloc_init __MALLOC_P((void))
if(__malloc_initialize_hook != NULL)
(*__malloc_initialize_hook)();
/********************** BEGIN OMPI CHANGES *****************************/
/* don't use __hook for this, as someone might want to use those
features */
opal_mem_hooks_set_support(OPAL_MEMORY_FREE_SUPPORT |
OPAL_MEMORY_MUNMAP_SUPPORT |
OPAL_MEMORY_CHUNK_SUPPORT);
/********************* BEGIN OMPI CHANGES ******************************/
__malloc_initialized = 1;
}

Просмотреть файл

@ -10,7 +10,7 @@
# University of Stuttgart. All rights reserved.
# Copyright (c) 2004-2005 The Regents of the University of California.
# All rights reserved.
# Copyright (c) 2008 Cisco Systems, Inc. All rights reserved.
# Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
@ -25,27 +25,10 @@ AC_DEFUN([MCA_memory_ptmalloc2_COMPILE_MODE], [
])
AC_DEFUN([MCA_memory_ptmalloc2_POST_CONFIG],[
AM_CONDITIONAL([OMPI_WANT_EXTERNAL_PTMALLOC2],
[test "$enable_ptmalloc2_internal" != "yes"])
])
# MCA_memory_ptmalloc2_CONFIG(action-if-can-compile,
# [action-if-cant-compile])
# ------------------------------------------------
AC_DEFUN([MCA_memory_ptmalloc2_CONFIG],[
AC_ARG_ENABLE([ptmalloc2-internal],
[AC_HELP_STRING([--enable-ptmalloc2-internal],
[Build ptmalloc2 memory manager into libopen-pal,
instead of as separate library. Only has meaning
if ptmalloc2 memory component exists])])
AC_MSG_CHECKING([if ptmalloc2 should be part of libopen-pal])
AS_IF([test "$enable_ptmalloc2_internal" = "yes"],
[AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])
AS_IF([test "$with_memory_manager" = "ptmalloc2"],
[if test "`echo $host | grep apple-darwin`" != "" ; then
AC_MSG_WARN([*** Using ptmalloc with OS X will result in failure.])
@ -90,6 +73,12 @@ AC_DEFUN([MCA_memory_ptmalloc2_CONFIG],[
[memory_ptmalloc2_happy="yes"],
[memory_ptmalloc2_happy="no"])])
AS_IF([test "$memory_ptmalloc2_happy" = "yes"],
[# check for link.h (for _DYNAMIC symbol)
AC_CHECK_HEADER([link.h],
[memory_ptmalloc2_happy="yes"],
[memory_ptmalloc2_happy="no"])])
AS_IF([test "$memory_ptmalloc2_happy" = "yes"],
[# check for init hook symbol
AC_CHECK_DECL([__malloc_initialize_hook],

12
opal/mca/memory/ptmalloc2/dummy.c Обычный файл
Просмотреть файл

@ -0,0 +1,12 @@
/*
* Copyright (c) 2009 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
int opal_this_library_is_not_used_anymore(void) {
return 0;
}

Просмотреть файл

@ -33,6 +33,9 @@
#if !(USE_STARTER & 2)
/* OMPI change: these aren't used (avoid a compiler warning by if
0'ing them out */
#if 0
static Void_t*
#if __STD_C
malloc_hook_ini(size_t sz, const __malloc_ptr_t caller)
@ -45,7 +48,11 @@ malloc_hook_ini(sz, caller)
ptmalloc_init();
return public_mALLOc(sz);
}
#endif
/* OMPI change: these aren't used (avoid a compiler warning by if
0'ing them out */
#if 0
static Void_t*
#if __STD_C
realloc_hook_ini(Void_t* ptr, size_t sz, const __malloc_ptr_t caller)
@ -59,7 +66,11 @@ realloc_hook_ini(ptr, sz, caller)
ptmalloc_init();
return public_rEALLOc(ptr, sz);
}
#endif
/* OMPI change: these aren't used (avoid a compiler warning by if
0'ing them out */
#if 0
static Void_t*
#if __STD_C
memalign_hook_ini(size_t alignment, size_t sz, const __malloc_ptr_t caller)
@ -72,6 +83,7 @@ memalign_hook_ini(alignment, sz, caller)
ptmalloc_init();
return public_mEMALIGn(alignment, sz);
}
#endif
#endif /* !(USE_STARTER & 2) */
@ -633,8 +645,134 @@ public_sET_STATe(Void_t* msptr)
return 0;
}
/*-------------------------------------------------------------------------
Per
http://www.gnu.org/software/libc/manual/html_mono/libc.html#Hooks-for-Malloc,
we can define the __malloc_initialize_hook variable to be a
function that is invoked before the first allocation is ever
performed. We use this hook to wholly replace the underlying
allocator to our own allocator if a few conditions are met.
Remember that this hook is called probably at the very very very
beginning of the process. MCA parameters haven't been setup yet --
darn near nothing has been setup yet. Indeed, we're effectively in
signal context because we can't call anything that calls malloc.
So we can basically have some hard-coded tests for things to see if
we want to setup to use our internal ptmalloc2 or not. */
static void *opal_memory_ptmalloc2_malloc_hook(size_t sz,
const __malloc_ptr_t caller)
{
return public_mALLOc(sz);
}
static void *opal_memory_ptmalloc2_realloc_hook(Void_t* ptr, size_t sz,
const __malloc_ptr_t caller)
{
return public_rEALLOc(ptr, sz);
}
static void *opal_memory_ptmalloc2_memalign_hook(size_t alignment, size_t sz,
const __malloc_ptr_t caller)
{
return public_mEMALIGn(alignment, sz);
}
static void opal_memory_ptmalloc2_free_hook(__malloc_ptr_t __ptr,
const __malloc_ptr_t caller)
{
public_fREe(__ptr);
}
typedef enum {
RESULT_NO,
RESULT_YES,
RESULT_RUNTIME,
RESULT_NOT_FOUND
} check_result_t;
static check_result_t check(const char *name)
{
char *s = getenv(name);
if (NULL == s) {
return RESULT_NOT_FOUND;
}
if ('0' == s[0] && '\0' == s[1]) {
/* A value of 0 means "don't use!" */
return RESULT_NO;
} else if ('-' == s[0] && '1' == s[1] && '\0' == s[2]) {
/* A value of -1 means "use it if it would be advantageous */
return RESULT_RUNTIME;
} else {
/* Any other value means "use the hooks, Luke!" */
return RESULT_YES;
}
}
/* OMPI's init function */
static void opal_memory_ptmalloc2_malloc_init_hook(void)
{
/* Yes, checking for an MPI MCA parameter here is an abstraction
violation. Cope. Yes, even checking for *any* MCA parameter
here (without going through the MCA param API) is an
abstraction violation. Fricken' cope, will ya?
(unfortunately, there's really no good way to do this other
than this abstraction violation :-( ) */
struct stat st;
check_result_t lp = check("OMPI_MCA_mpi_leave_pinned");
check_result_t lpp = check("OMPI_MCA_mpi_leave_pinned_pipeline");
bool want_rcache = false, found_driver = false;
/* If /sys/class/infiniband exists, then the OpenFabrics
drivers are loaded. So let's default to using our hooks so
that we can utilize leave_pinned (yes, I know, further
abstraction violations... :-( ). */
if (0 == stat("/sys/class/infiniband", &st)) {
found_driver = true;
}
/* Simple combination of the results of these two environment
variables (if both "yes" and "no" are specified, then be
conservative and assume "yes):
lp / lpp yes no runtime not found
yes yes yes yes yes
no yes no no no
runtime yes no runtime runtime
not found yes no runtime runtime
*/
if (RESULT_YES == lp || RESULT_YES == lpp) {
want_rcache = true;
} else if (RESULT_NO == lp || RESULT_NO == lpp) {
want_rcache = false;
} else {
want_rcache = found_driver;
}
if (want_rcache) {
const char str[] = "using ptmallo\n";
write(1, str, sizeof(str));
/* Initialize ptmalloc */
ptmalloc_init();
/* Now set the hooks to point to our functions */
__free_hook = opal_memory_ptmalloc2_free_hook;
__malloc_hook = opal_memory_ptmalloc2_malloc_hook;
__memalign_hook = opal_memory_ptmalloc2_memalign_hook;
__realloc_hook = opal_memory_ptmalloc2_realloc_hook;
}
}
/* OMPI change: This is the symbol to override to make the above
function get fired during malloc initialization time. */
void (*__malloc_initialize_hook) (void) =
opal_memory_ptmalloc2_malloc_init_hook;
/*
* Local variables:
* c-basic-offset: 2
* c-basic-offset: 4
* End:
*/

Просмотреть файл

@ -20,6 +20,9 @@
/* $Id: $ */
/* OMPI change: Name-shift all the internal symbols */
#include "opal/mca/memory/ptmalloc2/rename.h"
#include <stdio.h> /* needed for malloc_stats */
#include <malloc-machine.h>

Просмотреть файл

@ -7,6 +7,8 @@
#include "opal/sys/atomic.h"
#include "opal/memoryhooks/memory_internal.h"
/* Name-shift all the internal symbols */
#include "opal/mca/memory/ptmalloc2/rename.h"
/*
* Not all systems have sbrk() declared, since it's technically not a
@ -521,23 +523,24 @@ Void_t * __default_morecore (ptrdiff_t);
Void_t *(*__morecore)(ptrdiff_t) = __default_morecore;
#else /* !_LIBC */
#define public_cALLOc calloc
#define public_fREe free
#define public_cFREe cfree
#define public_mALLOc malloc
#define public_mEMALIGn memalign
#define public_rEALLOc realloc
#define public_vALLOc valloc
#define public_pVALLOc pvalloc
#define public_mALLINFo mallinfo
#define public_mALLOPt mallopt
#define public_mTRIm malloc_trim
#define public_mSTATs malloc_stats
#define public_mUSABLe malloc_usable_size
#define public_iCALLOc independent_calloc
#define public_iCOMALLOc independent_comalloc
#define public_gET_STATe malloc_get_state
#define public_sET_STATe malloc_set_state
/* OMPI change: put "opal_memory_ptmalloc2_" in front of all of these */
#define public_cALLOc opal_memory_ptmalloc2_calloc
#define public_fREe opal_memory_ptmalloc2_free
#define public_cFREe opal_memory_ptmalloc2_cfree
#define public_mALLOc opal_memory_ptmalloc2_malloc
#define public_mEMALIGn opal_memory_ptmalloc2_memalign
#define public_rEALLOc opal_memory_ptmalloc2_realloc
#define public_vALLOc opal_memory_ptmalloc2_valloc
#define public_pVALLOc opal_memory_ptmalloc2_pvalloc
#define public_mALLINFo opal_memory_ptmalloc2_mallinfo
#define public_mALLOPt opal_memory_ptmalloc2_mallopt
#define public_mTRIm opal_memory_ptmalloc2_malloc_trim
#define public_mSTATs opal_memory_ptmalloc2_malloc_stats
#define public_mUSABLe opal_memory_ptmalloc2_malloc_usable_size
#define public_iCALLOc opal_memory_ptmalloc2_independent_calloc
#define public_iCOMALLOc opal_memory_ptmalloc2_independent_comalloc
#define public_gET_STATe opal_memory_ptmalloc2_malloc_get_state
#define public_sET_STATe opal_memory_ptmalloc2_malloc_set_state
#endif /* _LIBC */
#endif /* USE_DL_PREFIX */
@ -2390,6 +2393,8 @@ static Void_t** iALLOc();
#endif
#endif
/* OMPI change: these aren't used */
#if 0
#if !(USE_STARTER & 2)
# define free_hook_ini NULL
/* Forward declarations. */
@ -2405,7 +2410,11 @@ static Void_t* memalign_hook_ini __MALLOC_P ((size_t alignment, size_t sz,
# define realloc_hook_ini NULL
# define memalign_hook_ini memalign_starter
#endif
#endif
/* OMPI change: we don't want any of these -- we want to use the
underlying allocator's symbols */
#if 0
void weak_variable (*__malloc_initialize_hook) __MALLOC_PMT ((void)) = NULL;
void weak_variable (*__free_hook) __MALLOC_PMT ((__malloc_ptr_t __ptr,
const __malloc_ptr_t))
@ -2419,6 +2428,7 @@ __malloc_ptr_t weak_variable (*__memalign_hook)
__MALLOC_PMT ((size_t __alignment, size_t __size, const __malloc_ptr_t))
= memalign_hook_ini;
void weak_variable (*__after_morecore_hook) __MALLOC_P ((void)) = NULL;
#endif
/* ------------------- Support for multiple arenas -------------------- */
@ -2780,7 +2790,6 @@ static void do_check_malloc_state(mstate av)
/* ----------------- Support for debugging hooks -------------------- */
#include "hooks.c"
/* ----------- Routines dealing with system allocation -------------- */
/*
@ -3398,10 +3407,24 @@ public_mALLOc(size_t bytes)
mstate ar_ptr;
Void_t *victim;
/* OMPI change: the hook is us -- don't call the hook */
#if 0
__malloc_ptr_t (*hook) __MALLOC_P ((size_t, __const __malloc_ptr_t)) =
__malloc_hook;
if (hook != NULL)
return (*hook)(bytes, RETURN_ADDRESS (0));
#endif
/* OMPI change: put in a flag so that we can know that this function
was invoked. This flag is checked in the memory/ptmalloc2
component init to ensure that this ptmalloc is actually being
used. Used a simple "extern" here to get the flag symbol rather
than putting it in a new .h file that would only contain a small
number of symbols. */
{
extern bool opal_memory_ptmalloc2_malloc_invoked;
opal_memory_ptmalloc2_malloc_invoked = true;
}
arena_get(ar_ptr, bytes);
if(!ar_ptr)
@ -3442,12 +3465,26 @@ public_fREe(Void_t* mem)
mstate ar_ptr;
mchunkptr p; /* chunk corresponding to mem */
/* OMPI change: the hook is us -- don't call the hook */
#if 0
void (*hook) __MALLOC_P ((__malloc_ptr_t, __const __malloc_ptr_t)) =
__free_hook;
if (hook != NULL) {
(*hook)(mem, RETURN_ADDRESS (0));
return;
}
#endif
/* OMPI change: put in a flag so that we can know that this function
was invoked. This flag is checked in the memory/ptmalloc2
component init to ensure that this ptmalloc is actually being
used. Used a simple "extern" here to get the flag symbol rather
than putting it in a new .h file that would only contain a small
number of symbols. */
{
extern bool opal_memory_ptmalloc2_free_invoked;
opal_memory_ptmalloc2_free_invoked = true;
}
if (mem == 0) /* free(0) has no effect */
return;
@ -3491,11 +3528,25 @@ public_rEALLOc(Void_t* oldmem, size_t bytes)
Void_t* newp; /* chunk to return */
/* OMPI change: the hook is us -- don't call the hook */
#if 0
__malloc_ptr_t (*hook) __MALLOC_P ((__malloc_ptr_t, size_t,
__const __malloc_ptr_t)) =
__realloc_hook;
if (hook != NULL)
return (*hook)(oldmem, bytes, RETURN_ADDRESS (0));
#endif
/* OMPI change: put in a flag so that we can know that this function
was invoked. This flag is checked in the memory/ptmalloc2
component init to ensure that this ptmalloc is actually being
used. Used a simple "extern" here to get the flag symbol rather
than putting it in a new .h file that would only contain a small
number of symbols. */
{
extern bool opal_memory_ptmalloc2_realloc_invoked;
opal_memory_ptmalloc2_realloc_invoked = true;
}
#if REALLOC_ZERO_BYTES_FREES
if (bytes == 0 && oldmem != NULL) { public_fREe(oldmem); return 0; }
@ -3567,11 +3618,25 @@ public_mEMALIGn(size_t alignment, size_t bytes)
mstate ar_ptr;
Void_t *p;
/* OMPI change: the hook is us -- don't call the hook */
#if 0
__malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
__const __malloc_ptr_t)) =
__memalign_hook;
if (hook != NULL)
return (*hook)(alignment, bytes, RETURN_ADDRESS (0));
#endif
/* OMPI change: put in a flag so that we can know that this function
was invoked. This flag is checked in the memory/ptmalloc2
component init to ensure that this ptmalloc is actually being
used. Used a simple "extern" here to get the flag symbol rather
than putting it in a new .h file that would only contain a small
number of symbols. */
{
extern bool opal_memory_ptmalloc2_memalign_invoked;
opal_memory_ptmalloc2_memalign_invoked = true;
}
/* If need less alignment than we give anyway, just relay to malloc */
if (alignment <= MALLOC_ALIGNMENT) return public_mALLOc(bytes);
@ -3649,8 +3714,11 @@ public_cALLOc(size_t n, size_t elem_size)
unsigned long clearsize;
unsigned long nclears;
INTERNAL_SIZE_T* d;
/* OMPI change: the hook is us -- don't call the hook */
#if 0
__malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, __const __malloc_ptr_t)) =
__malloc_hook;
#endif
/* size_t is unsigned so the behavior on overflow is defined. */
bytes = n * elem_size;
@ -3663,6 +3731,8 @@ public_cALLOc(size_t n, size_t elem_size)
}
}
/* OMPI change: the hook is us -- don't call the hook */
#if 0
if (hook != NULL) {
sz = bytes;
mem = (*hook)(sz, RETURN_ADDRESS (0));
@ -3675,6 +3745,7 @@ public_cALLOc(size_t n, size_t elem_size)
return mem;
#endif
}
#endif
sz = bytes;
@ -5437,7 +5508,6 @@ int mALLOPt(param_number, value) int param_number; int value;
*/
/* OMPI: Need to expose our own posix_memalign, or the wrong one will
be used */
# include <sys/param.h>
@ -5447,9 +5517,13 @@ int
posix_memalign (void **memptr, size_t alignment, size_t size)
{
void *mem;
/* OMPI change: the hook is us -- don't call the hook */
#if 0
__malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
__const __malloc_ptr_t)) =
__memalign_hook;
#endif
/* Test whether the SIZE argument is valid. It must be a power of
two multiple of sizeof (void *). */
@ -5458,12 +5532,17 @@ posix_memalign (void **memptr, size_t alignment, size_t size)
|| alignment == 0)
return EINVAL;
/* OMPI change: the hook is us -- don't call the hook */
#if 0
/* Call the hook here, so that caller is posix_memalign's caller
and not posix_memalign itself. */
if (hook != NULL)
mem = (*hook)(alignment, size, RETURN_ADDRESS (0));
else
mem = public_mEMALIGn (alignment, size);
#else
mem = public_mEMALIGn (alignment, size);
#endif
if (mem != NULL) {
*memptr = mem;
@ -5472,6 +5551,7 @@ posix_memalign (void **memptr, size_t alignment, size_t size)
return ENOMEM;
}
#ifdef _LIBC
weak_alias (__posix_memalign, posix_memalign)

Просмотреть файл

@ -9,6 +9,7 @@
* University of Stuttgart. All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2009 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
@ -16,13 +17,21 @@
* $HEADER$
*/
/* The goal of this component is to wholly replace the underlying
allocator with our internal ptmalloc2 allocator.
See the file README-open-mpi.txt for details of how it works. */
#include "opal_config.h"
/* Include <link.h> for _DYNAMIC */
#include <link.h>
#include "opal/constants.h"
#include "opal/mca/memory/memory.h"
#include "opal/memoryhooks/memory.h"
static int opal_memory_ptmalloc2_open(void);
static int ptmalloc2_open(void);
const opal_memory_base_component_2_0_0_t mca_memory_ptmalloc2_component = {
/* First, the mca_component_t struct containing meta information
@ -37,7 +46,7 @@ const opal_memory_base_component_2_0_0_t mca_memory_ptmalloc2_component = {
OPAL_RELEASE_VERSION,
/* Component open and close functions */
opal_memory_ptmalloc2_open,
ptmalloc2_open,
NULL
},
{
@ -46,16 +55,60 @@ const opal_memory_base_component_2_0_0_t mca_memory_ptmalloc2_component = {
},
};
/* Public symbols */
bool opal_memory_ptmalloc2_free_invoked = false;
bool opal_memory_ptmalloc2_malloc_invoked = false;
bool opal_memory_ptmalloc2_realloc_invoked = false;
bool opal_memory_ptmalloc2_memalign_invoked = false;
static int
opal_memory_ptmalloc2_open(void)
static int ptmalloc2_open(void)
{
/* we always provide munmap support as part of libopen-pal.la.
Will also provide malloc/free support if user linked us in. In
that case, we've already likely called set_support, so don't
crush what has already been done */
if (0 == opal_mem_hooks_support_level()) {
opal_mem_hooks_set_support(OPAL_MEMORY_MUNMAP_SUPPORT);
/* We always provide munmap support as part of libopen-pal.la. */
int val = OPAL_MEMORY_MUNMAP_SUPPORT;
/* We can't catch munmap if we're a static library */
if (NULL == &_DYNAMIC) {
val = 0;
}
/* We will also provide malloc/free support if we've been
activated. We don't rely on the __malloc_initialize_hook()
previously being called because it's possible that our hook was
called, but then someone else reset the hooks to point to
something else (i.e., before MPI_INIT). So explicitly test
here if our hooks are still in place. If they are, then enable
FREE|CUNK_SUPPORT. If not, then don't enable that support --
just leave it at MUNMAP_SUPPORT.
(Look in hooks.c for the __malloc_initialize_hook setup) */
/* Do a simple set of tests to see if our hooks are still the ones
installed. Explicitly reset the flags indicating that our
functions were invoked */
opal_memory_ptmalloc2_malloc_invoked = false;
opal_memory_ptmalloc2_realloc_invoked = false;
opal_memory_ptmalloc2_memalign_invoked = false;
opal_memory_ptmalloc2_free_invoked = false;
void *p = malloc(1024 * 1024 * 4);
if (NULL == p) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
realloc(p, 1024 * 1024 * 4 + 32);
free(p);
memalign(1, 1024 * 1024);
free(p);
if (opal_memory_ptmalloc2_malloc_invoked &&
opal_memory_ptmalloc2_realloc_invoked &&
opal_memory_ptmalloc2_memalign_invoked &&
opal_memory_ptmalloc2_free_invoked) {
/* Happiness; our functions were invoked */
val |= OPAL_MEMORY_FREE_SUPPORT | OPAL_MEMORY_CHUNK_SUPPORT;
}
/* Set the support level */
opal_mem_hooks_set_support(val);
return OPAL_SUCCESS;
}

52
opal/mca/memory/ptmalloc2/rename.h Обычный файл
Просмотреть файл

@ -0,0 +1,52 @@
/*
* Copyright (c) 2009 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
/* Name-shift all the internal ptmalloc22 symbols to guarantee to not
conflict / confuse / override the internal glibc symbols. */
#define __default_morecore opal_memory_ptmalloc2_default_morecore
#define _int_malloc opal_memory_ptmalloc2_int_malloc
#define _int_free opal_memory_ptmalloc2_int_free
#define _int_realloc opal_memory_ptmalloc2_int_realloc
#define _int_memalign opal_memory_ptmalloc2_int_memalign
#define _int_valloc opal_memory_ptmalloc2_int_valloc
#define _int_pvalloc opal_memory_ptmalloc2_int_pvalloc
#define _int_icalloc opal_memory_ptmalloc2_int_icalloc
#define _int_icomalloc opal_memory_ptmalloc2_int_icomalloc
#define mTRIm opal_memory_ptmalloc2_mTRIm
#define mUSABLe opal_memory_ptmalloc2_mUSABLe
#define mALLOPt opal_memory_ptmalloc2_mALLOPt
#define mem2mem_check opal_memory_ptmalloc2_mem2mem_check
#define top_check opal_memory_ptmalloc2_top_check
#define munmap_chunk opal_memory_ptmalloc2_munmap_chunk
#define mremap_chunk opal_memory_ptmalloc2_mremap_chunk
#define malloc_check opal_memory_ptmalloc2_malloc_check
#define free_check opal_memory_ptmalloc2_free_check
#define realloc_check opal_memory_ptmalloc2_realloc_check
#define memalign_check opal_memory_ptmalloc2_memalign_check
#define malloc_starter opal_memory_ptmalloc2_malloc_starter
#define memalign_starter opal_memory_ptmalloc2_memalign_starter
#define free_starter opal_memory_ptmalloc2_free_starter
#define malloc_atfork opal_memory_ptmalloc2_malloc_atfork
#define free_atfork opal_memory_ptmalloc2_free_atfork
#define _int_get_arena opal_memory_ptmalloc2_int_get_arena
#define _int_get_arena_info opal_memory_ptmalloc2_int_get_arena_info
#define _int_get_global_info opal_memory_ptmalloc2_int_get_global_info
#define _int_new_arena opal_memory_ptmalloc2_int_new_arena
#define __malloc_check_init opal_memory_ptmalloc2_malloc_check_init
#define malloc_stats opal_memory_ptmalloc2_malloc_stats
#define posix_memalign opal_memory_ptmalloc2_posix_memalign