2019-06-06 14:21:15 +02:00
/*******************************************************************************
* Copyright ( c ) 2015 - 2018 Skymind , Inc .
*
* This program and the accompanying materials are made available under the
* terms of the Apache License , Version 2.0 which is available at
* https : //www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS , WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied . See the
* License for the specific language governing permissions and limitations
* under the License .
*
* SPDX - License - Identifier : Apache - 2.0
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//
// Created by raver119 on 07.05.19.
//
# include <memory/MemoryTracker.h>
# include <stdexcept>
# include <helpers/logger.h>
# include <stdlib.h>
2020-03-02 10:49:41 +01:00
# if defined(__GNUC__) && !defined(__MINGW64__) && !defined(SD_ANDROID_BUILD) && !defined(SD_IOS_BUILD) && !defined(SD_APPLE_BUILD)
2019-06-06 14:21:15 +02:00
# include <unistd.h>
# include <execinfo.h>
# include <cxxabi.h>
# endif
2020-03-02 10:49:41 +01:00
namespace sd {
2019-06-06 14:21:15 +02:00
namespace memory {
MemoryTracker : : MemoryTracker ( ) {
//
}
MemoryTracker * MemoryTracker : : getInstance ( ) {
if ( _INSTANCE = = 0 )
_INSTANCE = new MemoryTracker ( ) ;
return _INSTANCE ;
}
2020-03-02 10:49:41 +01:00
# if defined(__GNUC__) && !defined(__MINGW64__) && !defined(SD_ANDROID_BUILD) && !defined(SD_IOS_BUILD) && !defined(SD_APPLE_BUILD)
2019-06-06 14:21:15 +02:00
std : : string demangle ( char * message ) {
char * mangled_name = 0 , * offset_begin = 0 , * offset_end = 0 ;
// find parantheses and +address offset surrounding mangled name
for ( char * p = message ; * p ; + + p )
{
if ( * p = = ' ( ' )
{
mangled_name = p ;
}
else if ( * p = = ' + ' )
{
offset_begin = p ;
}
else if ( * p = = ' ) ' )
{
offset_end = p ;
break ;
}
}
// if the line could be processed, attempt to demangle the symbol
if ( mangled_name & & offset_begin & & offset_end & & mangled_name < offset_begin ) {
* mangled_name + + = ' \0 ' ;
* offset_begin + + = ' \0 ' ;
* offset_end + + = ' \0 ' ;
int status ;
char * real_name = abi : : __cxa_demangle ( mangled_name , 0 , 0 , & status ) ;
// if demangling is successful, output the demangled function name
if ( status = = 0 ) {
std : : string result ( real_name ) ;
free ( real_name ) ;
return result ;
} else {
// otherwise, output the mangled function name
std : : string result ( message ) ;
free ( real_name ) ;
return result ;
}
}
}
# endif
void MemoryTracker : : countIn ( MemoryType type , Nd4jPointer ptr , Nd4jLong numBytes ) {
2020-03-02 10:49:41 +01:00
# if defined(__GNUC__) && !defined(__MINGW64__) && !defined(SD_ANDROID_BUILD) && !defined(SD_IOS_BUILD) && !defined(SD_APPLE_BUILD)
2019-06-06 14:21:15 +02:00
if ( Environment : : getInstance ( ) - > isDetectingLeaks ( ) ) {
auto lptr = reinterpret_cast < Nd4jLong > ( ptr ) ;
_locker . lock ( ) ;
void * array [ 50 ] ;
size_t size ;
char * * messages ;
size = backtrace ( array , 50 ) ;
std : : string stack ( " " ) ;
messages = backtrace_symbols ( array , size ) ;
for ( int i = 1 ; i < size & & messages ! = NULL ; + + i ) {
stack + = demangle ( messages [ i ] ) + " \n " ;
}
free ( messages ) ;
if ( stack . find ( " ConstantTad " ) ! = std : : string : : npos | |
stack . find ( " ConstantShape " ) ! = std : : string : : npos ) {
_locker . unlock ( ) ;
return ;
}
std : : pair < Nd4jLong , AllocationEntry > pair ( lptr , AllocationEntry ( type , lptr , numBytes , stack ) ) ;
_allocations . insert ( pair ) ;
_locker . unlock ( ) ;
}
# endif
}
void MemoryTracker : : countOut ( Nd4jPointer ptr ) {
2020-03-02 10:49:41 +01:00
# if defined(__GNUC__) && !defined(__MINGW64__) && !defined(SD_ANDROID_BUILD) && !defined(SD_IOS_BUILD) && !defined(SD_APPLE_BUILD)
2019-06-06 14:21:15 +02:00
if ( Environment : : getInstance ( ) - > isDetectingLeaks ( ) ) {
auto lptr = reinterpret_cast < Nd4jLong > ( ptr ) ;
_locker . lock ( ) ;
if ( _released . count ( lptr ) > 0 ) {
//throw std::runtime_error("Double free!");
}
if ( _allocations . count ( lptr ) > 0 ) {
//auto entry = _allocations[lptr];
//std::string stack("new stack");
//std::pair<Nd4jLong, AllocationEntry> pair(lptr, entry);
//_released.insert(pair);
_allocations . erase ( lptr ) ;
}
_locker . unlock ( ) ;
}
# endif
}
void MemoryTracker : : summarize ( ) {
if ( ! _allocations . empty ( ) ) {
nd4j_printf ( " \n %i leaked allocations \n " , ( int ) _allocations . size ( ) ) ;
for ( auto & v : _allocations ) {
nd4j_printf ( " Leak of %i [%s] bytes \n %s \n \n " , ( int ) v . second . numBytes ( ) , v . second . memoryType ( ) = = MemoryType : : HOST ? " HOST " : " DEVICE " , v . second . stackTrace ( ) . c_str ( ) ) ;
}
throw std : : runtime_error ( " Non-released allocations found " ) ;
}
}
void MemoryTracker : : reset ( ) {
_allocations . clear ( ) ;
_released . clear ( ) ;
}
MemoryTracker * MemoryTracker : : _INSTANCE = 0 ;
}
}