agent/native/ext/MemoryTracker.h (116 lines of code) (raw):
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://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.
*/
#pragma once
#include <algorithm>
#include <stdbool.h>
#include "basic_types.h"
#include "StringView.h"
#include "basic_macros.h"
#include "IntrusiveDoublyLinkedList.h"
#include "internal_checks.h"
#include "TextOutputStream_forward_decl.h"
#ifndef ELASTIC_APM_MEMORY_TRACKING_ENABLED_01
# if defined( ELASTIC_APM_MEMORY_TRACKING_ENABLED ) && ( ELASTIC_APM_MEMORY_TRACKING_ENABLED == 0 )
# define ELASTIC_APM_MEMORY_TRACKING_ENABLED_01 0
# else
# define ELASTIC_APM_MEMORY_TRACKING_ENABLED_01 1
# endif
#endif
#if ( ELASTIC_APM_MEMORY_TRACKING_ENABLED_01 != 0 )
enum MemoryTrackingLevel
{
memoryTrackingLevel_not_set = -1,
memoryTrackingLevel_off = 0,
memoryTrackingLevel_totalCountOnly,
memoryTrackingLevel_eachAllocation,
memoryTrackingLevel_eachAllocationWithStackTrace,
memoryTrackingLevel_all,
numberOfMemoryTrackingLevels = memoryTrackingLevel_all + 1
};
typedef enum MemoryTrackingLevel MemoryTrackingLevel;
#define ELASTIC_APM_ASSERT_VALID_MEMORY_TRACKING_LEVEL( level ) \
ELASTIC_APM_ASSERT( ELASTIC_APM_IS_IN_END_EXCLUDED_RANGE( memoryTrackingLevel_not_set, (level), numberOfMemoryTrackingLevels ) \
, #level ": %u", (unsigned int)(level) ) \
/**/
extern const char* memoryTrackingLevelNames[ numberOfMemoryTrackingLevels ];
#ifndef ELASTIC_APM_MEMORY_TRACKING_DEFAULT_LEVEL
# if ( ELASTIC_APM_IS_DEBUG_BUILD_01 != 0 )
# define ELASTIC_APM_MEMORY_TRACKING_DEFAULT_LEVEL memoryTrackingLevel_all
# else
# define ELASTIC_APM_MEMORY_TRACKING_DEFAULT_LEVEL memoryTrackingLevel_off
# endif
#endif
#ifndef ELASTIC_APM_MEMORY_TRACKING_DEFAULT_ABORT_ON_MEMORY_LEAK
# if ( ELASTIC_APM_IS_DEBUG_BUILD_01 != 0 )
# define ELASTIC_APM_MEMORY_TRACKING_DEFAULT_ABORT_ON_MEMORY_LEAK true
# else
# define ELASTIC_APM_MEMORY_TRACKING_DEFAULT_ABORT_ON_MEMORY_LEAK false
# endif
#endif
MemoryTrackingLevel internalChecksToMemoryTrackingLevel( InternalChecksLevel internalChecksLevel );
struct MemoryTracker
{
MemoryTrackingLevel level;
bool abortOnMemoryLeak;
UInt64 allocatedPersistent;
IntrusiveDoublyLinkedList allocatedPersistentBlocks;
UInt64 allocatedRequestScoped;
IntrusiveDoublyLinkedList allocatedRequestScopedBlocks;
};
typedef struct MemoryTracker MemoryTracker;
static inline
void assertValidMemoryTracker( MemoryTracker* memTracker )
{
ELASTIC_APM_ASSERT_VALID_PTR( memTracker );
ELASTIC_APM_ASSERT_VALID_MEMORY_TRACKING_LEVEL( memTracker->level );
ELASTIC_APM_ASSERT_VALID_INTRUSIVE_LINKED_LIST( &memTracker->allocatedPersistentBlocks );
ELASTIC_APM_ASSERT_VALID_INTRUSIVE_LINKED_LIST( &memTracker->allocatedRequestScopedBlocks );
}
#define ELASTIC_APM_ASSERT_VALID_MEMORY_TRACKER( memTracker ) \
ELASTIC_APM_ASSERT_VALID_OBJ( assertValidMemoryTracker( memTracker ) ) \
static inline
bool isMemoryTrackingEnabled( MemoryTracker* memTracker )
{
return memTracker->level > memoryTrackingLevel_off;
}
static inline
bool shouldCaptureStackTrace( MemoryTracker* memTracker )
{
return memTracker->level > memoryTrackingLevel_eachAllocationWithStackTrace;
}
static inline
void reconfigureMemoryTracker(
MemoryTracker* memTracker,
MemoryTrackingLevel newConfiguredLevel,
bool newConfiguredAbortOnMemoryLeak )
{
ELASTIC_APM_ASSERT_VALID_MEMORY_TRACKING_LEVEL( newConfiguredLevel );
ELASTIC_APM_ASSERT( newConfiguredLevel != memoryTrackingLevel_not_set, "" );
/// We cannot increase tacking level after the start because it's possible that some allocations were already made
/// so starting tracking with higher level after some allocations were already made will produce invalid results
memTracker->level = std::min( memTracker->level, newConfiguredLevel );
memTracker->abortOnMemoryLeak = newConfiguredAbortOnMemoryLeak;
}
void constructMemoryTracker( MemoryTracker* memTracker );
void memoryTrackerRequestInit( MemoryTracker* memTracker );
size_t memoryTrackerCalcSizeToAlloc(
MemoryTracker* memTracker,
size_t originallyRequestedSize,
size_t stackTraceAddressesCount );
void memoryTrackerAfterAlloc(
MemoryTracker* memTracker,
const void* allocatedBlock,
size_t originallyRequestedSize,
bool isPersistent,
size_t actuallyRequestedSize,
StringView filePath,
UInt lineNumber,
bool isString,
void* const* stackTraceAddresses,
size_t stackTraceAddressesCount );
void memoryTrackerBeforeFree(
MemoryTracker* memTracker,
const void* allocatedBlock,
size_t originallyRequestedSize,
bool isPersistent,
size_t* possibleActuallyRequestedSize );
void memoryTrackerRequestShutdown( MemoryTracker* memTracker );
void destructMemoryTracker( MemoryTracker* memTracker );
String streamMemoryTrackingLevel( MemoryTrackingLevel level, TextOutputStream* txtOutStream );
MemoryTracker* getGlobalMemoryTracker();
#endif // #if ( ELASTIC_APM_MEMORY_TRACKING_ENABLED_01 != 0 )