1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-16 10:08:36 +03:00
occt/src/NCollection/NCollection_BaseAllocator.cxx
abv ddf2fe8eeb 0024911: Avoid using virtual functions in NCollection classes
NCollection_BaseCollection class, relevant header files, and macro DEFINE_BASECOLLECTION removed.
Hence methods Assign() from other compatible (via inheritance of BaseCollection) collections are not available any more, as well as base Iterator class.

All methods of Iterator classes are made non-virtual, allowing their inline expansion for better performance.

OCCT-specific operators new and delete added to collection classes and removed from iterator classes.
2014-06-05 14:12:18 +04:00

312 lines
10 KiB
C++

// Created on: 2002-04-12
// Created by: Alexander KARTOMIN (akm)
// Copyright (c) 2002-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
// Purpose: Implementation of the BaseAllocator class
#include <NCollection_BaseAllocator.hxx>
#include <NCollection_IncAllocator.hxx>
#include <NCollection_DataMap.hxx>
#include <NCollection_Map.hxx>
#include <NCollection_List.hxx>
#include <Standard_Mutex.hxx>
#include <fstream>
#include <iomanip>
IMPLEMENT_STANDARD_HANDLE(NCollection_BaseAllocator,MMgt_TShared)
IMPLEMENT_STANDARD_RTTIEXT(NCollection_BaseAllocator,MMgt_TShared)
//=======================================================================
//function : Allocate
//purpose : Standard allocation
//=======================================================================
void* NCollection_BaseAllocator::Allocate(const size_t size)
{
return Standard::Allocate(size);
}
//=======================================================================
//function : Free
//purpose : Standard deallocation
//=======================================================================
void NCollection_BaseAllocator::Free(void *anAddress)
{
if (anAddress) Standard::Free(anAddress);
}
//=======================================================================
//function : CommonBaseAllocator
//purpose : Creates the only one BaseAllocator
//=======================================================================
const Handle(NCollection_BaseAllocator)&
NCollection_BaseAllocator::CommonBaseAllocator(void)
{
static Handle(NCollection_BaseAllocator) pAllocator =
new NCollection_BaseAllocator;
return pAllocator;
}
// global variable to ensure that allocator will be created during loading the library
static Handle(NCollection_BaseAllocator) theAllocInit =
NCollection_BaseAllocator::CommonBaseAllocator();
//=======================================================================
/**
* Structure for collecting statistics about blocks of one size
*/
//=======================================================================
struct StorageInfo
{
Standard_Size roundSize;
int nbAlloc;
int nbFree;
StorageInfo()
: roundSize(0), nbAlloc(0), nbFree(0) {}
StorageInfo(Standard_Size theSize)
: roundSize(theSize), nbAlloc(0), nbFree(0) {}
};
//=======================================================================
/**
* Static data map (block_size -> StorageInfo)
*/
//=======================================================================
static NCollection_DataMap<Standard_Size, StorageInfo>& StorageMap()
{
static NCollection_IncAllocator TheAlloc;
static NCollection_DataMap<Standard_Size, StorageInfo>
TheMap (1, & TheAlloc);
return TheMap;
}
//=======================================================================
/**
* Static data map (address -> AllocationID)
*/
//=======================================================================
static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap()
{
static NCollection_IncAllocator TheAlloc;
static NCollection_DataMap<Standard_Address, Standard_Size>
TheMap (1, & TheAlloc);
return TheMap;
}
//=======================================================================
/**
* Static map (AllocationID)
*/
//=======================================================================
static NCollection_Map<Standard_Size>& StorageIDSet()
{
static NCollection_IncAllocator TheAlloc;
static NCollection_Map<Standard_Size> TheMap (1, & TheAlloc);
return TheMap;
}
//=======================================================================
/**
* Exported value to set the block size for which it is required
* collecting alive allocation IDs.
* The method NCollection_BaseAllocator::PrintMemUsageStatistics
* dumps all alive IDs into the file alive.d in the current directory.
*/
//=======================================================================
Standard_EXPORT Standard_Size& StandardCallBack_CatchSize()
{
static Standard_Size Value = 0;
return Value;
}
//=======================================================================
/**
* Exported value to set the allocation ID for which it is required
* to set a breakpoint on the moment of allocation or freeing.
* See the method NCollection_BaseAllocator::StandardCallBack
* where the value StandardCallBack_CatchID() is compared to the current ID.
* There you can place a break point at the stub assignment statement "a =".
*/
//=======================================================================
Standard_EXPORT Standard_Size& StandardCallBack_CatchID()
{
static Standard_Size Value = 0;
return Value;
}
//=======================================================================
/**
* Static value of the current allocation ID. It provides unique
* numbering of allocation events.
*/
//=======================================================================
static Standard_Size CurrentID = 0;
//=======================================================================
/**
* Exported function to reset the callback system to the initial state
*/
//=======================================================================
Standard_EXPORT void StandardCallBack_Reset()
{
StorageMap().Clear();
StorageIDMap().Clear();
StorageIDSet().Clear();
CurrentID = 0;
StandardCallBack_CatchSize() = 0;
StandardCallBack_CatchID() = 0;
}
namespace {
// dummy function for break point
inline void place_for_break_point () {}
};
//=======================================================================
//function : StandardCallBack
//purpose : Callback function to register alloc/free calls
//=======================================================================
void NCollection_BaseAllocator::StandardCallBack
(const Standard_Boolean theIsAlloc,
const Standard_Address theStorage,
const Standard_Size theRoundSize,
const Standard_Size /*theSize*/)
{
static Standard_Mutex aMutex;
aMutex.Lock();
// statistics by storage size
NCollection_DataMap<Standard_Size, StorageInfo>& aStMap = StorageMap();
if (!aStMap.IsBound(theRoundSize))
{
StorageInfo aEmpty(theRoundSize);
aStMap.Bind(theRoundSize, aEmpty);
}
StorageInfo& aInfo = aStMap(theRoundSize);
if (theIsAlloc)
aInfo.nbAlloc++;
else
aInfo.nbFree++;
if (theRoundSize == StandardCallBack_CatchSize())
{
// statistics by alive objects
NCollection_DataMap<Standard_Address, Standard_Size>& aStIDMap = StorageIDMap();
NCollection_Map<Standard_Size>& aStIDSet = StorageIDSet();
if (theIsAlloc)
{
aStIDMap.Bind(theStorage, ++CurrentID);
aStIDSet.Add(CurrentID);
if (CurrentID == StandardCallBack_CatchID())
{
// Place for break point for allocation of investigated ID
place_for_break_point();
}
}
else
{
if (aStIDMap.IsBound(theStorage))
{
Standard_Size anID = aStIDMap(theStorage);
aStIDSet.Remove(anID);
if (anID == StandardCallBack_CatchID())
{
// Place for break point for freeing of investigated ID
place_for_break_point();
}
}
}
}
aMutex.Unlock();
}
//=======================================================================
//function : PrintMemUsageStatistics
//purpose : Prints memory usage statistics cumulated by StandardCallBack
//=======================================================================
void NCollection_BaseAllocator::PrintMemUsageStatistics()
{
// sort by roundsize
NCollection_List<StorageInfo> aColl;
NCollection_List<StorageInfo>::Iterator itLst;
NCollection_DataMap<Standard_Size, StorageInfo>::Iterator itMap(StorageMap());
for (; itMap.More(); itMap.Next())
{
for (itLst.Init(aColl); itLst.More(); itLst.Next())
if (itMap.Value().roundSize < itLst.Value().roundSize)
break;
if (itLst.More())
aColl.InsertBefore(itMap.Value(), itLst);
else
aColl.Append(itMap.Value());
}
Standard_Size aTotAlloc = 0;
Standard_Size aTotLeft = 0;
// print
std::ofstream aFileOut ("memstat.d", std::ios_base::trunc | std::ios_base::out);
if (!aFileOut.is_open())
{
std::cout << "failure writing file memstat.d" << std::endl;
return;
}
aFileOut.imbue (std::locale ("C"));
// header
aFileOut << std::setw(20) << "BlockSize" << ' '
<< std::setw(12) << "NbAllocated" << ' '
<< std::setw(12) << "NbLeft" << ' '
<< std::setw(20) << "Allocated" << ' '
<< std::setw(20) << "Left" << '\n';
// body
for (itLst.Init(aColl); itLst.More(); itLst.Next())
{
const StorageInfo& aInfo = itLst.Value();
Standard_Integer nbLeft = aInfo.nbAlloc - aInfo.nbFree;
Standard_Size aSizeAlloc = aInfo.nbAlloc * aInfo.roundSize;
Standard_Size aSizeLeft = nbLeft * aInfo.roundSize;
aFileOut << std::setw(20) << aInfo.roundSize << ' '
<< std::setw(12) << aInfo.nbAlloc << ' '
<< std::setw(12) << nbLeft << ' '
<< std::setw(20) << aSizeAlloc << ' '
<< std::setw(20) << aSizeLeft << '\n';
aTotAlloc += aSizeAlloc;
aTotLeft += aSizeLeft;
}
// footer
aFileOut << std::setw(20) << "Total:" << ' '
<< std::setw(12) << "" << ' '
<< std::setw(12) << "" << ' '
<< std::setw(20) << aTotAlloc << ' '
<< std::setw(20) << aTotLeft << '\n';
if (!StorageIDSet().IsEmpty())
{
aFileOut << "Alive allocation numbers of size=" << StandardCallBack_CatchSize() << '\n';
for (NCollection_Map<Standard_Size>::Iterator itMap1(StorageIDSet()); itMap1.More(); itMap1.Next())
{
aFileOut << itMap1.Key() << '\n';
}
}
aFileOut.close();
}