diff --git a/Control/AthAllocators/AthAllocators/Arena.h b/Control/AthAllocators/AthAllocators/Arena.h new file mode 100755 index 0000000000000000000000000000000000000000..384dcab1f0950e34d40922a330a1d0bd61675a07 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/Arena.h @@ -0,0 +1,341 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Arena.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/Arena.h + * @author scott snyder + * @date May 2007 + * @brief Collection of memory allocators with a common lifetime, + * plus subsystem summary. + * + * The Arena classes provide a framework for memory allocation. + * It supports the following general features: + * + * - Segregated storage. Objects of identical type are grouped together. + * Memory is allocated from the system in large blocks and carved + * up into the individual objects. This allows eliminating malloc + * overhead and it helps with reducing problems due to heap fragmentation. + * + * - Objects may be `cached': the object constructor is run only when + * the memory is first allocated. If it is freed and then reallocated + * by the application, the destructor/constructor calls may be eliminated. + * + * - Memory allocations of similar lifetimes may be grouped together + * in ``Arenas''. All memory in a given Arena may be freed at once. + * + * - We attempt to make individual object allocation and deallocation + * very fast. The code for the `common' case can be entirely inlined, + * and should compile to a handful of instructions. + * + * - We keep statistics about the amount of memory allocated + * per type per Arena. + * + * First, a bit of terminology; this also summarizes the major components + * of the library. This will be followed by more detailed descriptions. + * See also the individual class headers. + * + * - An @em element is an individual piece of memory that the application + * requests. + * + * - A @em block is a piece of memory allocated from the system + * It will usually be divided up into individual elements. + * + * - An @em Allocator is the fundamental memory allocator, managing + * storage for a single type of object. Memory allocated from the + * system associated with a single Allocator. The Allocator + * classes themselves do not depend on the types being allocated; + * however, functions operating on these objects, such as constructors + * and destructors, may be given to the Allocator to be called + * at an appropriate time. Multiple Allocator implementations + * may be available, implementing different strategies. + * + * - An @em Arena is a group of Allocators, which share a common lifetime. + * The memory allocated by all Allocators in an Arena may be freed + * in a single operation. + * + * - An @em ArenaHeader represents a group of Arenas. One Arena + * is considered the `current' Arena; it is the one from which + * memory allocations will be made. Arenas within the group + * may be made current in a stack-like manner. + * + * - A @em Handle is the interface the application uses to allocate memory. + * A Handle is templated on the type being allocated as well as on the + * underlying Allocator. A Handle does not refer to any particular + * Allocator; rather, the one associated with the current Arena is the + * one used. (A new Allocator is automatically created if required.) + * Multiple Handle implementations may be available, implementing + * different strategies for initializing the elements. + * + * Here are some more details about these components. For full details, + * see the individual class headers. + * + * An @em Allocator is the fundamental allocator for a single type. + * Allocator instances generally request memory from the system + * in big blocks and then divide it up into individual elements. + * The memory allocated from the system is generally not returned + * to the system unless explicitly requested; elements not currently + * in use are kept in a pool for fast allocation. An Allocator + * class does not depend on the type being allocated. Instead, the + * necessary information is passed to the Allocator on creation + * in a parameters structure. This includes the element size, + * as well as three function pointers: + * + * - The constructor function is called when an element is first + * allocated from the system. + * - The destructor function is called just before an element's + * memory is released back to the system. + * - The clear function is called after the application frees + * an element. + * + * Any of these may be null, in which case the corresponding call is skipped. + * + * An Allocator has a name, which is used both to identify it in the + * Allocator registry when Allocators are created on demand and + * in memory statistics reports. + * An Allocator must support these operations: + * + * - @c allocate, to allocate a new element. + * - @c reset, to free all allocated elements. The memory will generally + * be retained by the Allocator to be reused again quickly. + * - @c erase, to free all allocated elements, and return all + * allocated memory to the system. + * - @c reserve, to adjust the amount of current unused memory which + * the Allocator keeps in its pool. If the amount of memory requested + * is greater than what is currently available, the new memory will + * usually be allocated in a single block. If the amount of memory + * requested is less than what is currently available, free blocks + * will be returned to the system, if possible. + * - @c name to return the Allocator's name, and @c stats to return + * the current statistics for the Allocator. + * + * There are some additional operations which an Allocator may optionally + * implement: + * + * - @c free, to free an individual element. + * - @c resetTo, to free all elements that were allocated after + * a given element, as well as the element itself. + * - An iterator, which iterates over all allocated blocks. + * + * Two @c Allocator implementations are currently available in the library: + * + * - @c ArenaPoolAllocator: Allocates elements in a stack-like manner. + * Implements the @c resetTo operation and an iterator, but does + * not implement @c free. + * + * - @c ArenaHeapAllocator: An Allocator that allows elements to be + * individually freed. Implements @c free, but not @c resetTo + * nor an iterator. This Allocator requires maintaining + * a pointer with each free element. By default, this pointer + * is kept outside the element, increasing the effective size + * per element. However, if part of the element may be overwritten + * while it is free, then the allocator may be configured + * to have this pointer overlap part of the element. + * + * @c Allocator objects are grouped into @c Arenas. Each @c Arena + * contains a vector of @c Allocator objects. Each distinct @c Allocator + * type is assigned an index into this vector; these indices are + * globally unique. An @c Arena is associated with a @c ArenaHeader, + * which maintains a notion of the `current' @c Arena; the @c ArenaHeader + * holds a reference to the @c Allocator vector of the current @c Arena. + * An @c Arena has a @c makeCurrent operation to nominate it as the + * current @c Arena for its @c ArenaHeader. A helper class @c Arena::Push + * is provided to change the current @c Arena in a stack-like manner. + * An @c Arena also has operations to @c reset or @c erase all of its + * @c Allocators, as well as for summing statistics over them all. + * An @c Arena also has a name, which is used in printing statistics reports. + * + * The object that the application uses to allocate memory is provided + * by the @c Handle classes. These are templated on the type being + * allocated as well as on the underlying @c Allocator class. + * A @c Handle is created by passing in the @c Arena (or @c ArenaHeader) + * with which it is created, as well as any optional creation + * parameters for the @c Allocator. The first time a given type + * is seen, it is assigned an index the the @c Arena @c Allocator + * vector. This index is then stored in the @c Handle. When the + * @c Handle is used, this index is used to find the proper @c Allocator + * in the current @c Arena. (A new @c Allocator is created automatically + * if needed.) A @c Handle forwards the operations from the underlying + * @c Allocator. The library provides two @c Handle implementations: + * + * - @c ArenaHandle: When this @c Handle is used, the element + * constructor/destructor are expected to be called every time + * an element is allocated/freed by the application. The @c allocate + * method returns a @c void*; it is expected that this will then + * be used in a placement new. The destructor will be called + * by the library when elements are freed. + * + * - @ ArenaCachingHandle: This @c Handle allows `caching' already-constructed + * objects, such that the constructor is run only when the element's + * memory is first allocated from the system, and the destructor + * is run only when the element's memory is released back to the system. + * The @c allocate method thus returns an already-initialized @c T*. + * An optional @c clear function may be called when the element + * is freed by the application. + * + * An example of the basic usage might be something like this. + * + *@code + * class Example { ... + * SG::Arena m_arena; + * SG::ArenaCachingHandle<MyObj, SG::ArenaPoolAllocator> m_handle; + * ...}; + * + * Example::Example() + * // Associates with the default ArenaHeader. + * : m_arena ("myarena") { ... + * ...} + * + * ret Example::execute() { ... + * SG::Arena::Push push (m_arena); + * MyObj* obj = m_handle.allocate(); + * ...} + * + * ret Example::newEvent() { ... + * m_arena.reset(); + * ... } + @endcode + * + * See also the unit tests for the Handle classes. + */ + + +#ifndef ATLALLOCATORS_ARENA_H +#define ATLALLOCATORS_ARENA_H + + +#include "AthAllocators/ArenaBase.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaAllocatorCreator.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include <cstdlib> +#include <string> +#include <string> +#include <ostream> + + +namespace SG { + + +/** + * @brief Collection of memory allocators with a common lifetime, + * + * See the file-level comments for a full description. + */ +class Arena + : public SG::ArenaBase +{ +public: + /** + * @brief Constructor. + * @param name The name of this @c Arena; to use in reports. + * @param header The header with which this @c Arena is associated. + * If defaulted, the global default @c ArenaHeader will be used. + */ + Arena (const std::string& name, ArenaHeader* header = 0); + + + /** + * @brief Destructor. + */ + ~Arena(); + + + /** + * @brief reset all contained allocators. All elements will be freed. + */ + void reset(); + + + /** + * @brief erase all contained allocators. All elements will be freed, + * and the memory returned to the system. + */ + void erase(); + + + /** + * @brief Generate a report of the memory in use by this @c Arena. + * @param os The stream to which to write the report. + */ + virtual void report (std::ostream& os) const; + + + /** + * @brief Return statistics summed over all allocators in this @c Arena. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return the @c ArenaHeader with which this @c Arena is associated. + */ + ArenaHeader* header() const; + + + /** + * @brief Return this @c Arena's name. + */ + virtual const std::string& name() const; + + + /** + * @brief Make this @c Arena the current one for its @c ArenaHeader. + * @returns The previously current allocator vector. + */ + ArenaHeader::ArenaAllocVec_t* makeCurrent(); + + + /** + * @brief Helper class for making @c Arena instances current + * in a stack-like manner. + */ + class Push + { + public: + + /** + * @brief Constructor. Make @c a current. + * @param a The @c Arena to make current. + */ + Push (Arena& a); + + + /** + * @brief Destructor. Undoes the effect of the constructor. + */ + ~Push(); + + + private: + /// The @c ArenaHeader for the stack we're managing. + ArenaHeader* m_header; + + /// The previously-current allocator vector. + ArenaHeader::ArenaAllocVec_t* m_allocs; + }; + + +private: + /// The @c ArenaHeader with which we're associated. + ArenaHeader* m_header; + + /// Our allocator vector. + ArenaHeader::ArenaAllocVec_t m_allocs; + + /// Our summed statistics block. + mutable ArenaAllocatorBase::Stats m_stats; + + /// Our name. + std::string m_name; +}; + + +} // namespace SG + + +#endif // not ATLALLOCATORS_ARENA_H diff --git a/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.h b/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.h new file mode 100755 index 0000000000000000000000000000000000000000..60d4c21a40530a83320c86d3224c85d12933a9ad --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.h @@ -0,0 +1,415 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorBase.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaAllocatorBase.h + * @author scott snyder + * @date May 2007 + * @brief Common base class for arena allocator classes. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAALLOCATORBASE_H +#define ATLALLOCATORS_ARENAALLOCATORBASE_H + + +#include <cstdlib> +#include <new> +#include <string> +#include <iosfwd> +#include "boost/type_traits.hpp" + + +namespace SG { + + +/** + * @brief Common base class for arena allocator classes. + * See Arena.h for an overview of the arena-based memory allocators. + * + * This base class provides the interfaces and common behavior for + * arena allocator classes. An allocator class is responsible for the + * actual allocation and deletion of objects. It is expected that + * unallocated objects may be maintained in a pool for efficiency. + * In addition, it should be possible to free at once all the objects + * that this allocator has allocated. See below for the details + * of the interface that classes deriving from this should implement. + * + * A matter of terminology. The objects that we allocate and free are + * called `elements'. As mentioned, it is expected that the memory will + * be allocated from the system for large groups of elements at any one + * time; these groups are called `blocks'. + * + * The allocator classes do not themselves depend on the type of the + * object being allocated. Instead, the necessary information is included + * in a parameters object of class @c Params that is passed to the allocator + * on construction. These parameters include: + * + * - @c name: The name of this allocator. This is used both in printed + * reports and to identify this allocator in the registry. + * - @c eltSize: The size in bytes of the individual elements + * we're allocating. + * - @c minSize: The minimum size that this Allocator allows for + * an element. + * - @c nblock: A hint for the number of elements to allocate in a single + * block. This is only a hint; the allocator may allocate + * a different number if that would be more efficient. + * - @c linkOffset: Some allocators may require keeping a pointer along + * with the element. This gives the offset (in bytes) + * from the start of the element where that pointer + * lives. In some cases, it may be safe to save space + * by allowing this pointer to overlap part of the element. + * Calling code is responsible for setting this up correctly. + * - @c constructor, @c destructor: It may be more efficient to call the + * element's constructor and destructor not each time the element + * is allocated and freed, but instead just when the element's + * block is allocated from or freed to the system. We thus + * cache a free pool of already-initialized objects. These + * parameters are to support this case. These are pointers + * to functions with the signature void (*)(char*). The + * @c constructor function is called when an element is first + * allocated from the system, and the @c destructor function + * is called when the element is finally released to the system. + * Either may be 0 to skip the call. + * - @c clear: In addition to the constructor and destructor, it may be + * necessary to reset the element state after the application + * releases it. If @c clear is not-null, this function will + * be called when an application frees an element. + * - @c canReclear: If true (the default), then it is safe to call @c clear + * more than once on a given element after it has been released. + * - @c mustClear: If true, then @c clear must be called before calling + * @c destructor. Otherwise (the default), @c destructor + * may be called directly without calling @c clear. + * + * The allocator class should maintain statistics for the memory it has + * allocated. These are grouped in the @c Stats structure. It should + * report the amount of space in use, the amount of free space (allocated + * from the system but not allocated by the application), and the total + * space allocated from the system, broken down into blocks, elements, + * and bytes. The derived allocator class may of course extend + * the provided statistics. + * + * The interface provided by derived allocator classes should consist + * of at least the following: + * + * - A constructor from a @c Params structure. + * + * - Implementations of the virtual methods @c reset, @c erase, @c reserve, + * @c name, @c stats. See documentation below. + * + * - An implementation of the method + *@code + * pointer allocate(); + @endcode + * This should be non-virtual, and may be inlined. It should return + * a pointer to an new element. If @c constructor was provided, + * then it should have been called on the element. + * + * - Optionally, an implementation of the non-virtual method + *@code + * void free (pointer); + @endcode + * to free a single element. @c clear will be called on the element + * if it was provided. + * + * - Optionally, an implementation of the non-virtual method + *@code + * void resetTo (pointer); + @endcode + * @c pointer should be a pointer to an element that was allocated + * from this allocator. That element and all elements that were + * allocated after it will be freed. + * + * - Optionally, @c iterator and @c const_iterator types and the + * corresponding const and non-const @c begin and @c end methods. + * These iterators should range over all allocated elements. + * The @c value_type should be @c pointer, and they should be at least + * forward iterators. + */ +class ArenaAllocatorBase +{ +public: + /// Type for pointers to elements. + typedef char* pointer; + + /// And a const version of the pointer. + typedef const char* const_pointer; + + /// Type of functions for @c constructor, etc. + typedef void func_t (pointer); + + + /** + * @brief Allocator parameters. See above for more details. + */ + struct Params + { + /// The name of this allocator. + std::string name; + + /// The size in bytes of the individual elements we're allocating. + size_t eltSize; + + /// The minimum size that this Allocator allows for an element. + size_t minSize; + + /// The number of elements we should allocate in a single block + /// (hint only). + size_t nblock; + + /// Offset from the start of a free element to a pointer to be used + /// by the allocator. Only used if the allocator requires it. + size_t linkOffset; + + /// Constructor function for elements. + + func_t* constructor; + /// Destructor function for elements. + func_t* destructor; + + /// Clear function for elements. + func_t* clear; + + /// If true, @c clear can be called more than once on a given element. + bool canReclear; + + /// If true, the @c clear call cannot be skipped before @c destructor. + bool mustClear; + }; + + + /** + * @brief Statistics for an allocator. See above for more details. + */ + struct Stats { + /// A single statistic. + struct Stat { + /// Default constructor. + Stat(); + /// Reset to zero. + void clear(); + /// Accumulate. + Stat& operator+= (const Stat& other); + + /// Number of items currently allocated by the application. + size_t inuse; + /// Number of items currently not allocated by the application + /// but cached by the allocator. + size_t free; + /// Total number of items held by the allocator. + size_t total; + }; + /// Reset to zero. + void clear(); + /// Accumulate. + Stats& operator+= (const Stats& other); + /// Print report header. + static void header (std::ostream& os); + + /// Counts of blocks. + Stat blocks; + /// Counts of elements. + Stat elts; + /// Counts of bytes. + Stat bytes; + }; + + + /** + * @brief Destructor. + */ + virtual ~ArenaAllocatorBase() {} + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + virtual void reset() = 0; + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + virtual void erase() = 0; + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + virtual void reserve (size_t size) = 0; + + + /** + * @brief Return the statistics block for this allocator. + */ + virtual const Stats& stats() const = 0; + + + /** + * @brief Return the name of this allocator. + */ + virtual const std::string& name() const = 0; + + + /** + * @brief Generate a report on the memory usage of this allocator. + * @param os Stream to which the report should be written. + */ + virtual void report (std::ostream& os) const; + + + //========================================================================= + /** + * @brief Helper to initialize a parameters structure. + * + * This creates a @c Params class appropriately initialized for class @c T. + * Assumptions made: + * - The constructor and destructor calls will be filled in + * if non-trivial, unless no_ctor or no_dtor is set to true. + * These two arguments are useful if the ctor/dtor are to + * be run elsewhere, or if they are trivial and can be skipped, + * but the compiler cannot detect that by itself. + * - The clear call will be filled in if the optional template parameter + * @c clear is true. + * - No space will be reserved for an extra link. + * - @c canReclear is @c true and @c mustClear is @c false. + * + * If these are not appropriate, you can derive from this class + * and make the appropriate changes. + */ + template <typename T, + bool clear = false, + bool no_ctor = false, + bool no_dtor = false> + struct initParams + { + /** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + initParams (size_t nblock = 1000, const std::string& name = ""); + + /// Return an initialized parameters structure. + Params params() const; + + /// Return an initialized parameters structure. + // Note: gcc 3.2.3 doesn't allow defining this out-of-line. + operator Params() const { return params(); } + + + private: + /// Saved value of the number of elements to allocate per block. + size_t m_nblock; + + /// Saved value of the allocator name. + std::string m_name; + }; + + + /// Make a constructor function pointer for a non-trivial constructor. + template <class T> + static func_t* makeConstructor (const boost::false_type&); + + /// Make a constructor function pointer for a trivial constructor. + template <class T> + static func_t* makeConstructor (const boost::true_type&); + + /// Make a constructor function pointer for a non-trivial destructor. + template <class T> + static func_t* makeDestructor (const boost::false_type&); + + /// Make a constructor function pointer for a trivial destructor. + template <class T> + static func_t* makeDestructor (const boost::true_type&); + + /// Make a function pointer for a @c clear function. + template <class T> + static func_t* makeClear (const boost::false_type&); + + /// Make a dummy @c clear function pointer. + template <class T> + static func_t* makeClear (const boost::true_type&); + +private: + /** + * @brief Call @c T's default constructor on the object at @c p. + * @param p The object on which to run the constructor. + */ + template <typename T> + static void construct_fcn (pointer p); + + + /** + * @brief Call @c T's destructor on the object at @c p. + * @param p The object on which to run the destructor. + */ + template <typename T> + static void destroy_fcn (pointer p); + + + /** + * @brief Call @c T::clear on the object at @c p. + * @param p The object on which to run the @c clear. + */ + template <typename T> + static void clear_fcn (pointer p); +}; + + +/** + * @brief Format a statistic structure. + * @param os The stream to which to write. + * @param stat The statistic structure to write. + */ +std::ostream& operator<< (std::ostream& os, + const ArenaAllocatorBase::Stats::Stat& stat); + + +/** + * @brief Format a complete statistics structure. + * @param os The stream to which to write. + * @param stats The statistics structure to write. + */ +std::ostream& operator<< (std::ostream& os, + const ArenaAllocatorBase::Stats& stats); + +} // namespace SG + + +#include "AthAllocators/ArenaAllocatorBase.icc" + + +#endif // not ATLALLOCATORS_ARENAALLOCATORBASE_H diff --git a/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.icc b/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.icc new file mode 100755 index 0000000000000000000000000000000000000000..260a0f0508db485721749320e2ebbe2a6a525afd --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaAllocatorBase.icc @@ -0,0 +1,174 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorBase.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaAllocatorBase.icc + * @author scott snyder + * @date May 2007 + * @brief Common base class for arena allocator classes. + * Inline/template implementations. + */ + + +namespace SG { + + +/** + * @brief Make a constructor function pointer for a non-trivial constructor. + */ +template <class T> +ArenaAllocatorBase::func_t* +ArenaAllocatorBase::makeConstructor (const boost::false_type&) +{ + return &construct_fcn<T>; +} + + +/** + * @brief Make a constructor function pointer for a trivial constructor. + */ +template <class T> +ArenaAllocatorBase::func_t* +ArenaAllocatorBase::makeConstructor (const boost::true_type&) +{ + return 0; +} + + +/** + * @brief Make a constructor function pointer for a non-trivial destructor. + */ +template <class T> +ArenaAllocatorBase::func_t* +ArenaAllocatorBase::makeDestructor (const boost::false_type&) +{ + return &destroy_fcn<T>; +} + + +/** + * @brief Make a constructor function pointer for a trivial destructor. + */ +template <class T> +ArenaAllocatorBase::func_t* +ArenaAllocatorBase::makeDestructor (const boost::true_type&) +{ + return 0; +} + + +/** + * @brief Make a function pointer for a @c clear function. + */ +template <class T> +ArenaAllocatorBase::func_t* +ArenaAllocatorBase::makeClear (const boost::false_type&) +{ + return &clear_fcn<T>; +} + + +/** + * @brief Make a dummy @c clear function pointer. + */ +template <class T> +ArenaAllocatorBase::func_t* +ArenaAllocatorBase::makeClear (const boost::true_type&) +{ + return 0; +} + + +/** + * @brief Call @c T's default constructor on the object at @c p. + * @param p The object on which to run the constructor. + */ +template <typename T> +void ArenaAllocatorBase::construct_fcn (pointer p) +{ + new(p) T; +} + + +/** + * @brief Call @c T's destructor on the object at @c p. + * @param p The object on which to run the destructor. + */ +template <typename T> +void ArenaAllocatorBase::destroy_fcn (pointer p) +{ + reinterpret_cast<T*>(p)->~T(); +} + + +/** + * @brief Call @c T::clear on the object at @c p. + * @param p The object on which to run the @c clear. + */ +template <typename T> +void ArenaAllocatorBase::clear_fcn (pointer p) +{ + reinterpret_cast<T*>(p)->clear(); +} + + +/** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <typename T, bool clear, bool no_ctor, bool no_dtor> +ArenaAllocatorBase::initParams<T, clear, no_ctor, no_dtor>::initParams + (size_t nblock /*=1000*/, + const std::string& name /*= ""*/) + : m_nblock (nblock), + m_name (name) +{ +} + + +/** + * @brief Return an initialized parameters structure. + */ +template <typename T, bool clear, bool no_ctor, bool no_dtor> +ArenaAllocatorBase::Params +ArenaAllocatorBase::initParams<T, clear, no_ctor, no_dtor>::params() const +{ + Params params; + + // Fill in the parameters that were passed to our constructor. + params.nblock = m_nblock; + params.name = m_name; + + // We're not setting up a link. + params.linkOffset = 0; + params.eltSize = sizeof (T); + params.minSize = 1; + + // Defaults for these. + params.canReclear = true; + params.mustClear = false; + + // Set up the constructor/destructor. + // We want the pointers to be null if they're trivial. + params.constructor = + makeConstructor<T> (::boost::integral_constant<bool, + ::boost::has_trivial_constructor<T>::value || + no_ctor>()); + params.destructor = + makeDestructor<T> (::boost::integral_constant<bool, + ::boost::has_trivial_destructor<T>::value || + no_dtor>()); + + // Set up the clear function --- only if the flag is set! + params.clear = makeClear<T> (::boost::integral_constant<bool, !clear>()); + + return params; +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/ArenaAllocatorCreator.h b/Control/AthAllocators/AthAllocators/ArenaAllocatorCreator.h new file mode 100755 index 0000000000000000000000000000000000000000..789b770c0fcdea3bd4b658e2aa112df145bb222f --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaAllocatorCreator.h @@ -0,0 +1,52 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorCreator.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaAllocatorCreator.h + * @author scott snyder + * @date May 2007 + * @brief Provide an interface for creating an arena Allocator. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAALLOCATORCREATOR_H +#define ATLALLOCATORS_ARENAALLOCATORCREATOR_H + + +namespace SG { + + +class ArenaAllocatorBase; + + +/** + * @brief Provide an interface for creating an arena Allocator. + * See Arena.h for an overview of the arena-based memory allocators. + * + * Objects deriving from this will be stored in @c ArenaAllocatorRegistry, + * and are used to create allocator instances on demand. + */ +class ArenaAllocatorCreator +{ +public: + /// Destructor. + virtual ~ArenaAllocatorCreator() {} + + + /** + * @brief Create an allocator instance. + */ + virtual ArenaAllocatorBase* create() = 0; +}; + + +} // namespace SG + + +#endif // not ATLALLOCATORS_ARENAALLOCATORCREATOR_H diff --git a/Control/AthAllocators/AthAllocators/ArenaAllocatorRegistry.h b/Control/AthAllocators/AthAllocators/ArenaAllocatorRegistry.h new file mode 100755 index 0000000000000000000000000000000000000000..1d74bd6aeffaa8b8b96d9963af9b0aaa74303de5 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaAllocatorRegistry.h @@ -0,0 +1,101 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorRegistry.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaAllocatorRegistry.h + * @author scott snyder + * @date May 2007 + * @brief Registry of allocator factories. + * See Arena.h for an overview of the arena-based memory allocators. + */ + +#ifndef ATLALLOCATORS_ARENAALLOCATORREGISTRY_H +#define ATLALLOCATORS_ARENAALLOCATORREGISTRY_H + + +#include <cstdlib> +#include <string> + + +namespace SG { + + +class ArenaAllocatorBase; +class ArenaAllocatorCreator; +class ArenaAllocatorRegistryImpl; + + +/** + * @brief Registry of allocator factories. + * See Arena.h for an overview of the arena-based memory allocators. + * + * Each Allocator type that the application uses is registered here; + * we assign to each one a small integer index. We can then create an instance + * of the Allocator given the index. Allocators have names; we also + * handle finding the index for an Allocator given the name. + */ +class ArenaAllocatorRegistry +{ +public: + /** + * @brief Register a new allocator type. + * @param name The name of the allocator type. Must not already exist. + * @param creator The factory object to create instances of this type. + * The registry takes ownership of this pointer. + * @return The new integer index for this allocator type. + */ + size_t registerCreator (const std::string& name, + ArenaAllocatorCreator* creator); + + + /** + * @brief Look up the index for an allocator type name. + * @param name The name of the allocator type to find. + * @return The index corresponding to the type, or @c std::string::npos + * if it hasn't yet been registered. + */ + size_t lookup (const std::string& name); + + + /** + * @brief Create a new instance of an allocator. + * @param i The index of the allocator to create. + * @return A newly-allocated allocator instance. + */ + ArenaAllocatorBase* create (size_t i); + + + /** + * @brief Return a pointer to the global @c ArenaAllocatorRegistry instance. + */ + static ArenaAllocatorRegistry* instance(); + + +private: + /// The implementation object. + ArenaAllocatorRegistryImpl* m_impl; + + // Disallow copying. + ArenaAllocatorRegistry (const ArenaAllocatorRegistry&); + ArenaAllocatorRegistry& operator= (const ArenaAllocatorRegistry&); + + /// Constructor. Called only by @c instance. + ArenaAllocatorRegistry(); + + /// Destructor. Called only by @c instance. + ~ArenaAllocatorRegistry(); + + // Just to avoid compiler warnings. + friend class ArenaAllocatorRegistryImpl; +}; + + +} // namespace SG + + +#endif // not ATLALLOCATORS_ARENAALLOCATORREGISTRY_H diff --git a/Control/AthAllocators/AthAllocators/ArenaBase.h b/Control/AthAllocators/AthAllocators/ArenaBase.h new file mode 100755 index 0000000000000000000000000000000000000000..85f0fef5f19debdcc426351f709431d0088e9a66 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaBase.h @@ -0,0 +1,59 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBase.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaBase.h + * @author scott snyder + * @date May 2007 + * @brief Reporting interface for @c Arena, to avoid a dependency + * loop with @c ArenaHeader. + * See Arena.h for an overview of the arena-based memory allocators. + */ + +#ifndef ATLALLOCATORS_ARENABASE_H +#define ATLALLOCATORS_ARENABASE_H + + +#include <iosfwd> +#include <string> + + +namespace SG { + + +/** + * @brief Reporting interface for @c Arena, to avoid a dependency + * loop with @c ArenaHeader. + * See Arena.h for an overview of the arena-based memory allocators. + */ +class ArenaBase +{ +public: + /// Destructor. + virtual ~ArenaBase() {} + + + /** + * @brief Generate a report of the memory in use by this @c Arena. + * @param os The stream to which to write the report. + */ + virtual void report (std::ostream& os) const = 0; + + + /** + * @brief Return this @c Arena's name. + */ + virtual const std::string& name() const = 0; +}; + + +} // namespace SG + + +#endif // not ATLALLOCATORS_ARENABASE_H + diff --git a/Control/AthAllocators/AthAllocators/ArenaBlock.h b/Control/AthAllocators/AthAllocators/ArenaBlock.h new file mode 100755 index 0000000000000000000000000000000000000000..1cde06626f8253166774642edde218b361059615 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaBlock.h @@ -0,0 +1,207 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlock.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaBlock.h + * @author scott snyder + * @date May 2007 + * @brief A large memory block that gets carved into smaller uniform elements. + * See Arena.h for an overview of the arena-based memory allocators. + */ + +#ifndef ATLALLOCATORS_ARENABLOCK_H +#define ATLALLOCATORS_ARENABLOCK_H + + +#include <cstdlib> + + +namespace SG { + + +class ArenaAllocatorBase; + + +/** + * @brief A large memory block that gets carved into smaller uniform elements. + * See Arena.h for an overview of the arena-based memory allocators. + * + * The block-based memory allocators allocate memory in large blocks + * and then carve them up into smaller, uniform elements. This class + * is used for those large blocks. Actually, the contents of this class + * is a fixed header for the block; the contents of the block itself + * will immediately follow the class contents. + * + * Each block keeps some housekeeping information: the element size in bytes, + * the number of elements in the block, and a pointer that can be used + * to chain blocks together in singly-linked lists. There are a few + * functions available to help manage such lists. + */ +class ArenaBlock +{ +public: + /// Type for a pointer to an element. + typedef char* pointer; + + /// Function that operates on an element. + typedef void func_t (pointer); + + + /** + * @brief Create a new block. + * @param n The number of elements in the new block. + * @param elt_size The size in bytes of each element. + * @param ctor If non-null, call this function on each element + * in the new block. + */ + static ArenaBlock* newBlock (size_t n, size_t elt_size, func_t* ctor); + + + /** + * @brief Destroy a block. + * @param p The block to destroy. + * @param dtor If non-null, call this function on each element in the block. + */ + static void destroy (ArenaBlock* p, func_t* dtor); + + + /** + * @brief Destroy all blocks in a list. + * @param p The first block to destroy. + * @param dtor If non-null, call this function on each element in the blocks. + * + * Will destroy all blocks in the linked list headed by @c p. + */ + static void destroyList (ArenaBlock* p, func_t* dtor); + + + /** + * @brief Concatenate two lists of blocks. + * @param headp Pointer to pointer to the head of the list. + * @param tail Pointer to list to append to the end. + * + * The list @c tail is appended to the end of the list @c *headp. + * (@c headp is a pointer-to-pointer to be able to handle the case + * of an empty list.) + */ + static void appendList (ArenaBlock** headp, ArenaBlock* tail); + + + /** + * @brief Call a function on elements in a list of blocks. + * @param p Pointer to the head of the list. + * @param func Function to apply. + * @param n Number of elements in the first block on which + * to call the function. + * + * This will loop through the elements in all blocks on the list, + * calling @c func. In the first block, we apply the function + * only to the first @c n elements. In subsequent blocks, the + * function is applied to all elements. + */ + static void applyList (ArenaBlock* p, func_t* func, size_t n); + + + /** + * @brief Return the number of elements in the block. + */ + size_t size() const; + + + /** + * @brief Return the size of the elements in the block. + */ + size_t eltSize() const; + + + /** + * @brief Return the link pointer of the block. + */ + ArenaBlock* & link(); + + + /** + * @brief Return a pointer to element @c i in the block. + * @param i The index of the desired element. + */ + pointer index (size_t i); + + + /** + * @brief Return a pointer to element @c i in the block. + * @param i The index of the desired element. + * @param elt_size The block's element size. + * + * This is provided in addition to the previous function as it may + * allow for better inlined code in when used in a loop, if @c elt_size + * is saved in a local. + */ + pointer index (size_t i, size_t elt_size); + + + /** + * @brief Return the per-block memory overhead, in bytes. + * + * This tries to include malloc overhead as well, but that may just + * be an estimate. Don't rely on this to be exact. + */ + static size_t overhead(); + + + /// Return the global number of blocks in use. + static size_t nactive(); + + +private: + /// Prohibit calling these. + ArenaBlock (size_t n, size_t elt_size); + ~ArenaBlock() {} + ArenaBlock (const ArenaBlock&); + ArenaBlock& operator= (const ArenaBlock&); + + // This is not really needed. It's just to squelch the g++ warning + // about classes with all private ctors/dtors and no friends. + friend class ArenaAllocatorBase; + + /// The link for the linked list. + ArenaBlock* m_link; + + /// Number of elements in this block. + size_t m_size; + + /// Size, in bytes, of each element in this block. + size_t m_elt_size; + + /// The start of the block body. + // Try to make sure it's maximally aligned. + // __attribute__ ((aligned)) will do that with gcc; on other compilers, + // try to get at least what a double requires. That's probably enough. + double m_dummy +#ifdef __GCC__ + __attribute__ ((aligned)) +#endif + ; + + + /// Global count of the number of blocks in use. + static size_t s_nactive; +}; + + +/// The offset from the start of the block to the first element. +static const int ArenaBlockBodyOffset = + sizeof (ArenaBlock) - sizeof (double); + + +} // namespace SG + + +#include "AthAllocators/ArenaBlock.icc" + + +#endif // not ATLALLOCATORS_ARENABLOCK_H diff --git a/Control/AthAllocators/AthAllocators/ArenaBlock.icc b/Control/AthAllocators/AthAllocators/ArenaBlock.icc new file mode 100755 index 0000000000000000000000000000000000000000..2719a1265df09650a6eee8d69d148f8f7bf73e78 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaBlock.icc @@ -0,0 +1,86 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlock.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaBlock.icc + * @author scott snyder + * @date May 2007 + * @brief These are large blocks of memory that get allocated and + * divided up into smaller, uniform elements. + * Inline/template implementations. + */ + +namespace SG { + + +/** + * @brief Return the number of elements in the block. + */ +inline +size_t ArenaBlock::size() const +{ + return m_size; +} + + +/** + * @brief Return the size of the elements in the block. + */ +inline +size_t ArenaBlock::eltSize() const +{ + return m_elt_size; +} + + +/** + * @brief Return the link pointer of the block. + */ +inline +ArenaBlock*& ArenaBlock::link() +{ + return m_link; +} + + +/** + * @brief Return a pointer to element @c i in the block. + * @param i The index of the desired element. + */ +inline +ArenaBlock::pointer ArenaBlock::index (size_t i) +{ + return reinterpret_cast<char*>(this) + + ArenaBlockBodyOffset + i*eltSize(); +} + + +/** + * @brief Return a pointer to element @c i in the block. + * @param i The index of the desired element. + * @param elt_size The block's element size. + * + * This is provided in addition to the previous function as it may + * allow for better inlined code in when used in a loop, if @c elt_size + * is saved in a local. + */ +inline +ArenaBlock::pointer ArenaBlock::index (size_t i, size_t elt_size) +{ + return reinterpret_cast<char*>(this) + ArenaBlockBodyOffset + i*elt_size; +} + + +/** + * @brief Return the global number of blocks in use. + */ +inline +size_t ArenaBlock::nactive() +{ + return s_nactive; +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/ArenaBlockAllocatorBase.h b/Control/AthAllocators/AthAllocators/ArenaBlockAllocatorBase.h new file mode 100755 index 0000000000000000000000000000000000000000..87155e58a6adf5c111f968f7487deb3759c33098 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaBlockAllocatorBase.h @@ -0,0 +1,121 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlockAllocatorBase.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaBlockAllocatorBase.h + * @author scott snyder + * @date May 2007 + * @brief Common functionality for block-oriented allocators. + */ + + +#ifndef ATLALLOCATORS_ARENABLOCKALLOCATORBASE_H +#define ATLALLOCATORS_ARENABLOCKALLOCATORBASE_H + + +#include "AthAllocators/ArenaAllocatorBase.h" + + +namespace SG { + + +class ArenaBlock; + + +/** + * @brief Common functionality for block-oriented allocators. + * See Arena.h for an overview of the arena-based memory allocators. + * + * This class factors out some common functionality for allocators + * that use @c ArenaBlock. + */ +class ArenaBlockAllocatorBase + : public ArenaAllocatorBase +{ +public: + /** + * @brief Constructor. + * @param params The parameters structure for this allocator. + * See @c ArenaAllocatorBase.h for the contents. + */ + ArenaBlockAllocatorBase (const Params& params); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + virtual void reserve (size_t size); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + virtual void erase(); + + + /** + * @brief Return the statistics block for this allocator. + */ + virtual const Stats& stats() const; + + + /** + * @brief Return the name of this allocator. + */ + virtual const std::string& name() const; + + + /** + * @brief Return this Allocator's parameters. + */ + const Params& params() const; + + +protected: + /** + * @brief Return an empty block, either newly-allocated or from the + * free list. Update statistics appropriately. + */ + ArenaBlock* getBlock(); + + /// The parameters for this allocator. + Params m_params; + + /// The list of blocks currently in use. + ArenaBlock* m_blocks; + + /// The list of free blocks. + ArenaBlock* m_freeblocks; + + /// The statistics structure. + mutable ArenaAllocatorBase::Stats m_stats; +}; + + +} // namespace SG + +#endif // not ATLALLOCATORS_ARENABLOCKALLOCATORBASE_H diff --git a/Control/AthAllocators/AthAllocators/ArenaCachingHandle.h b/Control/AthAllocators/AthAllocators/ArenaCachingHandle.h new file mode 100755 index 0000000000000000000000000000000000000000..dca22ad3ca57bf9e9e4334df641813ec23f84f4e --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaCachingHandle.h @@ -0,0 +1,170 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaCachingHandle.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaCachingHandle.h + * @author scott snyder + * @date May 2007 + * @brief User interface for allocating memory that caches constructed objects. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENACACHINGHANDLE_H +#define ATLALLOCATORS_ARENACACHINGHANDLE_H + + +#include "AthAllocators/ArenaHandleBaseT.h" +#include "AthAllocators/Arena.h" + + +namespace SG { + + +/** + * @brief User interface for allocating memory that caches constructed objects. + * See Arena.h for an overview of the arena-based memory allocators. + * + * A @em Handle is the interface the application uses to allocate memory. + * It is templated on the type being allocated as well as on the + * underlying Allocator. A Handle does not refer to any particular + * Allocator; rather, the one associated with the current Arena is the + * one used. (A new Allocator is automatically created if required.) + * + * This particular Handle implementation calls the element constructor + * only when the memory is first allocated by the system, and calls + * the destructor only when the memory is returned to the system. + * The @c allocate method thus returns an already-initialized pointer + * to the element. The element's default constructor must work + * for this. + * + * Note that it's possible to set up an additional @c clear method + * that's called when the element is freed; see @c ArenaAllocatorBase. + * + * Here's an example of how you might create the Handle and allocate + * memory: + * + *@code + * SG::ArenaCachingHandle<MyObj, SG::ArenaPoolAllocator> handle; + * MyObj* obj = handle.allocate(); + @endcode + * + * This associates the Handle with the default @c ArenaHeader. + * You can then erase all objects allocated though this Handle + * in the current Allocator with + * + *@code + * handle.reset(); + @endcode + * + * Note that most of the public interface for this class is inherited + * from the base classes. + */ +template <class T, class ALLOC> +class ArenaCachingHandle + : public ArenaHandleBaseT<T, ALLOC> +{ +public: + /// Shorthand for our base class. + typedef ArenaHandleBaseT<T, ALLOC> Base; + + /// Pointer to an element. + typedef T* pointer; + + /// Iterators over elements. + /// (May only be instantiated if the underlying Allocator supports them.) + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + + /** + * @brief Constructor, passing in an index. (For internal/testing use.) + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ + ArenaCachingHandle (ArenaHeader* header, size_t index); + + + /// The class that initializes the default parameter set. + typedef typename ALLOC::template initParams<T, false> defaultParams_t; + + + /** + * @brief Constructor, passing in an optional parameter set. + * @param params Parameters to pass to the Allocator. + */ + ArenaCachingHandle (const typename ALLOC::Params& params = + defaultParams_t()); + + + + /** + * @brief Constructor, passing in a Header and an optional parameter set. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ + ArenaCachingHandle (ArenaHeader* header, + const typename ALLOC::Params& params = + defaultParams_t()); + + + /** + * @brief Constructor, passing in an Arena and an optional parameter set. + * @param arena One Arena in the group which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ + ArenaCachingHandle (Arena* arena, const typename ALLOC::Params& params = + defaultParams_t()); + + + /** + * @brief Allocate a new element. + * + * This returns an already-initialized element. + */ + pointer allocate() const; + + + /** + * @brief Internal helper: create a new Allocator instance. + * @param params The parameters for the Allocator. + */ + static + ArenaAllocatorBase* makeAllocator (const typename ALLOC::Params& params); + + + // The following methods are inherited: + // const ALLOC::Params& params() const; + // void reset(); + // void erase(); + // void reserve(size_t); + // const ArenaAllocatorBase::Stats& stats() const; + // + // The following inherited functions may be instantiated only + // if the Allocator supports them: + // iterator begin(); + // const_iterator begin() const; + // iterator end(); + // const_iterator end() const; + // void free (pointer p) const; + // void resetTo (pointer p) const; +}; + + +} // namespace SG + + + +#include "AthAllocators/ArenaCachingHandle.icc" + + + +#endif // not ATLALLOCATORS_ARENACACHINGHANDLE_H diff --git a/Control/AthAllocators/AthAllocators/ArenaCachingHandle.icc b/Control/AthAllocators/AthAllocators/ArenaCachingHandle.icc new file mode 100755 index 0000000000000000000000000000000000000000..525b810ef1399082f80ec5f499ace85e73c92ea3 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaCachingHandle.icc @@ -0,0 +1,105 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaCachingHandle.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaCachingHandle.icc + * @author scott snyder + * @date May 2007 + * @brief User interface for allocating memory that caches constructed objects. + * Inline and template implementations. + */ + + +namespace SG { + + +/** + * @brief Constructor, passing in an index. (For internal/testing use.) + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ +template <class T, class ALLOC> +ArenaCachingHandle<T, ALLOC>::ArenaCachingHandle (ArenaHeader* header, + size_t index) + : ArenaHandleBaseT<T, ALLOC> (header, index) +{ +} + + +/** + * @brief Constructor, passing in an optional parameter set. + * @param params Parameters to pass to the Allocator. + */ +template <class T, class ALLOC> +ArenaCachingHandle<T, ALLOC>::ArenaCachingHandle + (const typename ALLOC::Params& params) + : ArenaHandleBaseT<T, ALLOC> (0, typename Base::Creator (this, params)) +{ +} + + +/** + * @brief Constructor, passing in a Header and an optional parameter set. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ +template <class T, class ALLOC> +ArenaCachingHandle<T, ALLOC>::ArenaCachingHandle + (ArenaHeader* header, + const typename ALLOC::Params& params) + : ArenaHandleBaseT<T, ALLOC> (header, + typename Base::Creator (this, params)) +{ +} + + +/** + * @brief Constructor, passing in an Arena and an optional parameter set. + * @param arena One Arena in the group which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ +template <class T, class ALLOC> +ArenaCachingHandle<T, ALLOC>::ArenaCachingHandle + (Arena* arena, + const typename ALLOC::Params& params) + : ArenaHandleBaseT<T, ALLOC> (arena ? arena->header() : 0, + typename Base::Creator (this, params)) +{ +} + + +/** + * @brief Allocate a new element. + * + * This returns an already-initialized element. + * + * This is on the fast path for element allocation, so keep it small + * and inline. + */ +template <class T, class ALLOC> +inline +typename ArenaCachingHandle<T, ALLOC>::pointer +ArenaCachingHandle<T, ALLOC>::allocate() const +{ + return reinterpret_cast<pointer> (this->allocator()->allocate()); +} + + +/** + * @brief Internal helper: create a new Allocator instance. + * @param params The parameters for the Allocator. + */ +template <class T, class ALLOC> +ArenaAllocatorBase* ArenaCachingHandle<T, ALLOC>::makeAllocator + (const typename ALLOC::Params& params) +{ + return new ALLOC (params); +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/ArenaHandle.h b/Control/AthAllocators/AthAllocators/ArenaHandle.h new file mode 100755 index 0000000000000000000000000000000000000000..e13d8b1b00f1faa53c57b6b39d1dcea1fa90a483 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHandle.h @@ -0,0 +1,163 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandle.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHandle.h + * @author scott snyder + * @date May 2007 + * @brief User interface for allocating memory. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAHANDLE_H +#define ATLALLOCATORS_ARENAHANDLE_H + + +#include "AthAllocators/ArenaHandleBaseT.h" +#include "AthAllocators/Arena.h" + + +namespace SG { + + +/** + * @brief User interface for allocating memory. + * See Arena.h for an overview of the arena-based memory allocators. + * + * A @em Handle is the interface the application uses to allocate memory. + * It is templated on the type being allocated as well as on the + * underlying Allocator. A Handle does not refer to any particular + * Allocator; rather, the one associated with the current Arena is the + * one used. (A new Allocator is automatically created if required.) + * + * This particular Handle implementation does not call element constructors, + * and calls destructors when elements are freed. The @c allocate + * method returns a @c void*, so you're expected to use it in a placement new. + * Here's an example of how you might create the Handle and allocate + * memory: + * + *@code + * SG::ArenaHandle<MyObj, SG::ArenaPoolAllocator> handle; + * MyObj* obj = new (handle.allocate()) (...); + @endcode + * + * This associates the Handle with the default @c ArenaHeader. + * You can then erase all objects allocated though this Handle + * in the current Allocator with + * + *@code + * handle.reset(); + @endcode + * + * The destructors for the allocated objects will be called at that time. + * + * Note that most of the public interface for this class is inherited + * from the base classes. + */ +template <class T, class ALLOC> +class ArenaHandle + : public ArenaHandleBaseT<T, ALLOC> +{ +public: + /// Shorthand for our base class. + typedef ArenaHandleBaseT<T, ALLOC> Base; + + /// Pointer to an element. + typedef typename Base::pointer pointer; + + /// Iterators over elements. + /// (May only be instantiated if the underlying Allocator supports them.) + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + + + /** + * @brief Constructor, passing in an index. (For internal/testing use.) + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ + ArenaHandle (ArenaHeader* header, size_t index); + + + /// The class that initializes the default parameter set. + typedef typename ALLOC::template initParams<T, false, true> defaultParams_t; + + + /** + * @brief Constructor, passing in an optional parameter set. + * @param params Parameters to pass to the Allocator. + */ + ArenaHandle (const typename ALLOC::Params& params = + defaultParams_t()); + + + /** + * @brief Constructor, passing in a Header and an optional parameter set. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ + ArenaHandle (ArenaHeader* header, + const typename ALLOC::Params& params = + defaultParams_t()); + + + /** + * @brief Constructor, passing in an Arena and an optional parameter set. + * @param arena One Arena in the group which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ + ArenaHandle (Arena* arena, const typename ALLOC::Params& params = + defaultParams_t()); + + + /** + * @brief Allocate a new element. + * + * The element's constructor will not have been called; thus, the memory + * is returned as a @c void*. + */ + void* allocate() const; + + + /** + * @brief Internal helper: create a new Allocator instance. + * @param params The parameters for the Allocator. + */ + static + ArenaAllocatorBase* makeAllocator (const typename ALLOC::Params& params); + + + // The following methods are inherited: + // const ALLOC::Params& params() const; + // void reset(); + // void erase(); + // void reserve(size_t); + // const ArenaAllocatorBase::Stats& stats() const; + // + // The following inherited functions may be instantiated only + // if the Allocator supports them: + // iterator begin(); + // const_iterator begin() const; + // iterator end(); + // const_iterator end() const; + // void free (pointer p) const; + // void resetTo (pointer p) const; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHandle.icc" + + +#endif // not ATLALLOCATORS_ARENAHANDLE_H diff --git a/Control/AthAllocators/AthAllocators/ArenaHandle.icc b/Control/AthAllocators/AthAllocators/ArenaHandle.icc new file mode 100755 index 0000000000000000000000000000000000000000..26cb4c8740127ce061ee6305513501515ecf5053 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHandle.icc @@ -0,0 +1,126 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandle.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaHandle.icc + * @author scott snyder + * @date May 2007 + * @brief User interface for allocating memory. + * Inline and template implementations. + */ + + +namespace SG { + + +/** + * @brief Constructor, passing in an index. (For internal/testing use.) + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ +template <class T, class ALLOC> +ArenaHandle<T, ALLOC>::ArenaHandle (ArenaHeader* header, + size_t index) + : ArenaHandleBaseT<T, ALLOC> (header, index) +{ +} + + +/** + * @brief Constructor, passing in an optional parameter set. + * @param params Parameters to pass to the Allocator. + */ +template <class T, class ALLOC> +ArenaHandle<T, ALLOC>::ArenaHandle + (const typename ALLOC::Params& params) + : ArenaHandleBaseT<T, ALLOC> (0, typename Base::Creator (this, params)) +{ +} + + +/** + * @brief Constructor, passing in a Header and an optional parameter set. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ +template <class T, class ALLOC> +ArenaHandle<T, ALLOC>::ArenaHandle + (ArenaHeader* header, + const typename ALLOC::Params& params) + : ArenaHandleBaseT<T, ALLOC> (header, + typename Base::Creator (this, params)) +{ +} + + +/** + * @brief Constructor, passing in an Arena and an optional parameter set. + * @param arena One Arena in the group which this Handle may reference. + * May be null to select the global default. + * @param params Parameters to pass to the Allocator. + */ +template <class T, class ALLOC> +ArenaHandle<T, ALLOC>::ArenaHandle + (Arena* arena, + const typename ALLOC::Params& params) + : ArenaHandleBaseT<T, ALLOC> (arena ? arena->header() : 0, + typename Base::Creator (this, params)) +{ +} + + +/** + * @brief Allocate a new element. + * + * The element's constructor will not be called; thus, the memory + * is returned as a @c void*. + * + * This is on the fast path for element allocation, so keep it small + * and inline. + */ +template <class T, class ALLOC> +inline +void* ArenaHandle<T, ALLOC>::allocate() const +{ + return this->allocator()->allocate(); +} + + +/** + * @brief Internal helper: create a new Allocator instance. + * @param params The parameters for the Allocator. + */ +template <class T, class ALLOC> +ArenaAllocatorBase* ArenaHandle<T, ALLOC>::makeAllocator + (const typename ALLOC::Params& params) +{ + typename ALLOC::Params newparams = params; + + // We don't call the element constructor. + newparams.constructor = 0; + + // The destructor is called when we free an element --- not when + // we return it to the system. + newparams.clear = newparams.destructor; + newparams.destructor = 0; + + // We can't skip running the destructor. + newparams.mustClear = true; + + // We can't call the destructor twice. + newparams.canReclear = false; + + // If we need a link, it can overlap the element. + newparams.eltSize = std::max (sizeof(T), newparams.minSize); + newparams.linkOffset = 0; + + // Make the Allocator. + return new ALLOC (newparams); +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/ArenaHandleBase.h b/Control/AthAllocators/AthAllocators/ArenaHandleBase.h new file mode 100755 index 0000000000000000000000000000000000000000..b167373abc502f3a80a0de6a0ca707357ff5de15 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHandleBase.h @@ -0,0 +1,142 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBase.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHandleBase.h + * @author scott snyder + * @date May 2007 + * @brief Base class for all @c Handle classes, containing parts that + * do not depend on the referenced type. + * See Arena.h for an overview of the arena-based memory allocators. + */ + +#ifndef ATLALLOCATORS_ARENAHANDLEBASE_H +#define ATLALLOCATORS_ARENAHANDLEBASE_H + +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include <cstdlib> + + +namespace SG { + + +/** + * @brief Base class for all @c Handle classes, containing parts that + * do not depend on the referenced type. + * See Arena.h for an overview of the arena-based memory allocators. + * + * A @em Handle is the interface the application uses to allocate memory. + * A Handle is templated on the type being allocated as well as on the + * underlying Allocator. A Handle does not refer to any particular + * Allocator; rather, the one associated with the current Arena is the + * one used. (A new Allocator is automatically created if required.) + * Multiple Handle implementations may be available, implementing + * different strategies for initializing the elements. + * + * This class contains the parts of the Handle interface that do not + * depend on the template parameters. + * + * The first time a given Handle type + * is seen, it is assigned an index the the @c Arena @c Allocator + * vector. This index is then stored in the @c Handle. When the + * @c Handle is used, this index is used to find the proper @c Allocator + * in the current @c Arena. (A new @c Allocator is created automatically + * if needed.) A @c Handle forwards the operations from the underlying + * @c Allocator. + */ +class ArenaHandleBase +{ +public: + /** + * @brief Constructor. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ + ArenaHandleBase (ArenaHeader* header, size_t index); + + + /** + * @brief Free all allocated elements (of this type in the current Arena). + * + * All elements allocated in the current Arena by our associated + * Allocator are returned to the + * free state. @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system + * (of this type in the current Arena). + * + * All elements allocated in the current Arena by our associated + * Allocator are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator + * (in the current Arena). + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator, + * for the current Arena. + */ + const ArenaAllocatorBase::Stats& stats() const; + + +protected: + /** + * @brief Return the current Allocator which we are referencing. + * + * This may cause a new Allocator to be created. + */ + ArenaAllocatorBase* baseAllocator() const; + + +private: + /// The group of Arenas which this Handle may reference. + ArenaHeader* m_header; + + /// The index of this Handle's Allocator type. + size_t m_index; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHandleBase.icc" + + +#endif // not ATLALLOCATORS_ARENAHANDLEBASE_H diff --git a/Control/AthAllocators/AthAllocators/ArenaHandleBase.icc b/Control/AthAllocators/AthAllocators/ArenaHandleBase.icc new file mode 100755 index 0000000000000000000000000000000000000000..719f9f77acc41a211e25420dd0f4a8db7cc24ea1 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHandleBase.icc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBase.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaHandleBase.icc + * @author scott snyder + * @date May 2007 + * @brief Base class for all @c Handle classes, containing parts that + * do not depend on the referenced type. + * Inline implementations. + */ + + +namespace SG { + + +/** + * @brief Return the current Allocator which we are referencing. + * + * This may cause a new Allocator to be created. + * + * This is on the fast path for allocations, so keep it small and inline. + */ +inline +ArenaAllocatorBase* ArenaHandleBase::baseAllocator() const +{ + return m_header->allocator (m_index); +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.h b/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.h new file mode 100755 index 0000000000000000000000000000000000000000..96638c0e68d20cb6d3ab90698292e42cdd292628 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.h @@ -0,0 +1,169 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBaseAllocT.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHandleBaseAllocT.h + * @author scott snyder + * @date May 2007 + * @brief Base class for @c Handle classes, containing parts that + * depend only on the Allocator. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAHANDLEBASEALLOCT_H +#define ATLALLOCATORS_ARENAHANDLEBASEALLOCT_H + + +#include "AthAllocators/ArenaHandleBase.h" +#include "AthAllocators/ArenaAllocatorCreator.h" +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include "GaudiKernel/System.h" +#include <string> + + +namespace SG { + + +/** + * @brief Base class for @c Handle classes, containing parts that + * depend only on the Allocator. + * See Arena.h for an overview of the arena-based memory allocators. + * + * This is the part of @c Handle that depends only on the Allocator class + * (on which it is templated). This implementation here is responsible + * for registering the Allocator and handling its possible creation. + * + * A @c Handle holds an index which identifies the particular Allocator + * class which it uses; the @c ArenaAllocatorRegistry class maps between + * these indices and instances of @c ArenaAllocatorCreator, which are + * capable of creating new @c Allocator instances. + * An @c ArenaHandleBaseAllocT may be created by either passing + * in the index directly or by passing in a concrete instance + * of @c ArenaAllocatorCreator. In the latter case, we will + * look up the index, registering the creator if needed. + */ +template <typename ALLOC> +class ArenaHandleBaseAllocT + : public ArenaHandleBase +{ +public: + /// The @c Allocator we use. + typedef ALLOC alloc_t; + + + /** + * @brief Concrete ArenaAllocatorCreator class used to create + * the Allocator for this handle. + * + * There are two members of this class: @c m_makeFunc is the function + * which actually creates the Allocator, and @c m_params is the + * parameters structure to pass to the new Allocator. These will + * get filled in by @c ArenaAllocatorCreatorInit, which derives + * from this. + */ + class Creator + : public ArenaAllocatorCreator + { + public: + /// Type for @c m_makeFunc --- a function returning a new Allocator + /// from a parameters structure. + typedef + ArenaAllocatorBase* makeFunc_t (const typename ALLOC::Params&); + + + /** + * @brief Constructor. + * @param hand Dummy to set the template argument type. + * @param params Allocator parameters. + * + * This initializes the @c Creator for creating an Allocator + * appropriate for the Handle class @c HANDLE. The @c HANDLE + * class should have a static function @c makeAllocator + */ + template <class HANDLE> + Creator (HANDLE* hand, const typename ALLOC::Params& params); + + + /** + * @brief Create an allocator instance. + */ + virtual ArenaAllocatorBase* create(); + + + /** + * @brief Return the name of the Allocator we create. + */ + const std::string& name() const; + + + protected: + /// Function that creates an Allocator given a set of parameters. + makeFunc_t* m_makeFunc; + + /// Set of parameters to use to create our allocator. + typename ALLOC::Params m_params; + }; + + + /** + * @brief Constructor, passing in an index. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ + ArenaHandleBaseAllocT (ArenaHeader* header, size_t index); + + + /** + * @brief Constructor, passing in a creator instance. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param creator A @c Creator instance that will create an instance + * of the Allocator we use. + * + * We'll try looking up the allocator name (from @c creator) in the + * registry to find the proper index. If it's not found, we'll + * register @c creator. + */ + ArenaHandleBaseAllocT (ArenaHeader* header, const Creator& creator); + + + /** + * @brief Return our Allocator's parameters. + */ + const typename ALLOC::Params& params() const; + + +protected: + /** + * @brief Return our current Allocator. + * + * (Note that the current Allocator may change; see @c Arena.h) + */ + ALLOC* allocator() const; + + +private: + /** + * @brief Find the index for @c Creator, registering it if needed. + * + * We look up in the registry the Allocator name we get from @c creator. + * If not found, then we register @c creator and return the new index. + */ + size_t makeIndex (const Creator& creator); +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHandleBaseAllocT.icc" + + +#endif // not ATLALLOCATORS_ARENAHANDLEBASEALLOCT_H diff --git a/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.icc b/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.icc new file mode 100755 index 0000000000000000000000000000000000000000..da799e093d6ea58b1f30cd7aa5924a2fd7f512c6 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHandleBaseAllocT.icc @@ -0,0 +1,130 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBaseAllocT.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaHandleBaseAllocT.icc + * @author scott snyder + * @date May 2007 + * @brief Base class for @c Handle classes, containing parts that + * depend only on the Allocator. + * Inline and template implementations. + */ + + +namespace SG { + + +template <typename ALLOC> +template <class HANDLE> +ArenaHandleBaseAllocT<ALLOC>::Creator::Creator + (HANDLE*, const typename ALLOC::Params& params) + : m_makeFunc (HANDLE::makeAllocator), + m_params (params) +{ + if (m_params.name.empty()) + m_params.name = System::typeinfoName (typeid (HANDLE)); +} + + +/** + * @brief Create an allocator instance. + */ +template <typename ALLOC> +ArenaAllocatorBase* ArenaHandleBaseAllocT<ALLOC>::Creator::create() +{ + return m_makeFunc (m_params); +} + + +/** + * @brief Return the name of the Allocator we create. + */ +template <typename ALLOC> +const std::string& +ArenaHandleBaseAllocT<ALLOC>::Creator::name() const +{ + return m_params.name; +} + + +/** + * @brief Constructor, passing in an index. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ +template <typename ALLOC> +ArenaHandleBaseAllocT<ALLOC>::ArenaHandleBaseAllocT + (ArenaHeader* header, size_t index) + : ArenaHandleBase (header, index) +{ +} + + +/** + * @brief Constructor, passing in a creator instance. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param creator A @c Creator instance that will create an instance + * of the Allocator we use. + * + * We'll try looking up the allocator name (from @c creator) in the + * registry to find the proper index. If it's not found, we'll + * register @c creator. + */ +template <typename ALLOC> +ArenaHandleBaseAllocT<ALLOC>::ArenaHandleBaseAllocT (ArenaHeader* header, + const Creator& creator) + : ArenaHandleBase (header, makeIndex (creator)) +{ +} + + +/** + * @brief Return our Allocator's parameters. + */ +template <typename ALLOC> +const typename ALLOC::Params& +ArenaHandleBaseAllocT<ALLOC>::params() const +{ + return dynamic_cast<const ALLOC*>(this->baseAllocator())->params(); +} + + +/** + * @brief Return our current Allocator. + * + * (Note that the current Allocator may change; see @c Arena.h) + * + * This is on the fast path for allocation. It should be kept + * simple and inline. + */ +template <typename ALLOC> +inline +ALLOC* ArenaHandleBaseAllocT<ALLOC>::allocator() const +{ + return reinterpret_cast<ALLOC*> (this->baseAllocator()); +} + + +/** + * @brief Find the index for @c Creator, registering it if needed. + * + * We look up in the registry the Allocator name we get from @c creator. + * If not found, then we register @c creator and return the new index. + */ +template <typename ALLOC> +size_t +ArenaHandleBaseAllocT<ALLOC>::makeIndex (const Creator& creator) +{ + ArenaAllocatorRegistry* reg = ArenaAllocatorRegistry::instance(); + size_t i = reg->lookup (creator.name()); + if (i != std::string::npos) + return i; + return reg->registerCreator (creator.name(), new Creator (creator)); +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.h b/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.h new file mode 100755 index 0000000000000000000000000000000000000000..150a36657e7e9a779e827ce0539344014f6efd12 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.h @@ -0,0 +1,244 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBaseT.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHandleBaseT.h + * @author scott snyder + * @date May 2007 + * @brief Base class for @c Handle classes, containing parts that + * are independent of how the Allocator gets created. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAHANDLEBASET_H +#define ATLALLOCATORS_ARENAHANDLEBASET_H + +#include "AthAllocators/ArenaHandleBaseAllocT.h" +#include "AthAllocators/ArenaHeader.h" +#include "boost/iterator/iterator_adaptor.hpp" +#include <cstdlib> + + +namespace SG { + + +/** + * @brief Base class for @c Handle classes, containing parts that + * are independent of how the Allocator gets created. + * See Arena.h for an overview of the arena-based memory allocators. + */ +template <class T, class ALLOC> +class ArenaHandleBaseT + : public ArenaHandleBaseAllocT<ALLOC> +{ +public: + /// A pointer to the element type we're allocating. + typedef T* pointer; + + /// Shorthand for our base class. + typedef ArenaHandleBaseAllocT<ALLOC> Base; + + /// @c AllocatorCreatorBase concrete derived class for creating + /// our Allocator. + typedef typename Base::Creator Creator; + + + /** + * @brief Constructor, passing in an index. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ + ArenaHandleBaseT (ArenaHeader* header, size_t index); + + + /** + * @brief Constructor, passing in a creator instance. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param creator A @c Creator instance that will create an instance + * of the Allocator we use. + * + * We'll try looking up the allocator name (from @c creator) in the + * registry to find the proper index. If it's not found, we'll + * register @c creator. + */ + ArenaHandleBaseT (ArenaHeader* header, const Creator& creator); + + + // Forward declaration. + class const_iterator; + + + /** + * @brief Non-const iterator. + * It iterates over all unallocated blocks in the current + * Allocator (in unspecified order). It will be at least + * a @c forward_iterator. + * + * Note that this is only supported if the underlying Allocator + * supports it. If it does not, you will not be able + * to instantiate this type. + * + * This uses @c boost::iterator_adaptor to handle casting + * the element pointers to the proper type. + */ + class iterator + : public boost::iterator_adaptor< + iterator, + typename ALLOC::iterator, + T, + boost::forward_traversal_tag> + { + public: + /** + * @brief Constructor. + * @param it The base iterator. + */ + iterator (const typename ALLOC::iterator& it); + + + // To allow initializing a @c const_iterator from an @c iterator. + friend class const_iterator; + + + private: + // Required by @c iterator_adaptor. + friend class boost::iterator_core_access; + + + /** + * @brief Dereference the iterator. + */ + typename iterator::reference dereference() const; + }; + + + /** + * @brief Const iterator. + * It iterates over all unallocated blocks in the current + * Allocator (in unspecified order). It will be at least + * a @c forward_iterator. + * + * Note that this is only supported if the underlying Allocator + * supports it. If it does not, you will not be able + * to instantiate this type. + * + * This uses @c boost::iterator_adaptor to handle casting + * the element pointers to the proper type. + */ + class const_iterator + : public boost::iterator_adaptor< + const_iterator, + typename ALLOC::const_iterator, + T const, + boost::forward_traversal_tag> + { + + public: + /** + * @brief Constructor. + * @param it The base iterator. + */ + const_iterator (const typename ALLOC::const_iterator& it); + + + /** + * @brief Constructor from a non-const iterator. + * @param it The non-const iterator. + */ + const_iterator (const iterator& it); + + + private: + // Required by @c iterator_adaptor. + friend class boost::iterator_core_access; + + + /** + * @brief Dereference the iterator. + */ + typename const_iterator::reference dereference() const; + }; + + + /** + * @brief Starting iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is at least a @c forward_iterator. + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ + iterator begin(); + + + /** + * @brief Starting const iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is at least a @c forward_iterator. + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ + const_iterator begin() const; + + + /** + * @brief Ending iterator. + * + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ + iterator end(); + + + /** + * @brief Ending const iterator. + * + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ + const_iterator end() const; + + + /** + * @brief Free an element. + * @param p The element to be freed. + * + * @c clear() will be called on the element at this point, + * if it has been defined. + * + * This may only be instantiated if it's supported + * by the underlying Allocator. + */ + void free (pointer p); + + + /** + * @brief Reset pool back to a previous state. + * @param p The pointer back to which to reset. + * + * This will free (a la @c reset) the element @c p and all elements + * that have been allocated after it from this allocator. + * + * This may only be instantiated if it's supported + * by the underlying Allocator. + */ + void resetTo (pointer p); +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHandleBaseT.icc" + + +#endif // not ATLALLOCATORS_ARENAHANDLEBASET_H diff --git a/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.icc b/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.icc new file mode 100755 index 0000000000000000000000000000000000000000..90ceeafe565088ff96f357929032f7c8c5883c8b --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHandleBaseT.icc @@ -0,0 +1,212 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBaseT.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaHandleBaseT.icc + * @author scott snyder + * @date May 2007 + * @brief Base class for @c Handle classes, containing parts that + * are independent of how the Allocator gets created. + * Inline and template implementations. + */ + + +namespace SG { + + +/** + * @brief Constructor, passing in an index. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ +template <typename T, typename ALLOC> +ArenaHandleBaseT<T, ALLOC>::ArenaHandleBaseT (ArenaHeader* header, + size_t index) + : Base (header, index) +{ +} + + +/** + * @brief Constructor, passing in a creator instance. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param creator A @c Creator instance that will create an instance + * of the Allocator we use. + * + * We'll try looking up the allocator name (from @c creator) in the + * registry to find the proper index. If it's not found, we'll + * register @c creator. + */ +template <typename T, typename ALLOC> +ArenaHandleBaseT<T, ALLOC>::ArenaHandleBaseT (ArenaHeader* header, + const Creator& creator) + : Base (header, creator) +{ +} + + +/** + * @brief Constructor. + * @param it The base iterator. + */ +template <typename T, typename ALLOC> +inline +ArenaHandleBaseT<T, ALLOC>::iterator::iterator + (const typename ALLOC::iterator& it) + : iterator::iterator_adaptor_ (it) +{ +} + + +/** + * @brief Dereference the iterator. + */ +template <typename T, typename ALLOC> +inline +typename ArenaHandleBaseT<T, ALLOC>::iterator::reference +ArenaHandleBaseT<T, ALLOC>::iterator::dereference() const +{ + return reinterpret_cast<T&> (*this->base_reference()); +} + + +/** + * @brief Constructor. + * @param it The base iterator. + */ +template <typename T, typename ALLOC> +inline +ArenaHandleBaseT<T, ALLOC>::const_iterator::const_iterator + (const typename ALLOC::const_iterator& it) + : const_iterator::iterator_adaptor_ (it) +{ +} + + +/** + * @brief Constructor from a non-const iterator. + * @param it The non-const iterator. + */ +template <typename T, typename ALLOC> +inline +ArenaHandleBaseT<T, ALLOC>::const_iterator::const_iterator + (const iterator& it) + : const_iterator::iterator_adaptor_ (it.base_reference()) +{ +} + + +/** + * @brief Dereference the iterator. + */ +template <typename T, typename ALLOC> +inline +typename ArenaHandleBaseT<T, ALLOC>::const_iterator::reference +ArenaHandleBaseT<T, ALLOC>::const_iterator::dereference() const +{ + return reinterpret_cast<const T&> (*this->base_reference()); +} + + +/** + * @brief Starting iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is at least a @c forward_iterator. + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ +template <class T, class ALLOC> +typename ArenaHandleBaseT<T, ALLOC>::iterator +ArenaHandleBaseT<T, ALLOC>::begin() +{ + return const_cast<ALLOC*>(this->allocator())->begin(); +} + + +/** + * @brief Starting const iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is at least a @c forward_iterator. + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ +template <class T, class ALLOC> +typename ArenaHandleBaseT<T, ALLOC>::const_iterator +ArenaHandleBaseT<T, ALLOC>::begin() const +{ + return const_cast<const ALLOC*>(this->allocator())->begin(); +} + + +/** + * @brief Ending iterator. + * + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ +template <class T, class ALLOC> +typename ArenaHandleBaseT<T, ALLOC>::iterator +ArenaHandleBaseT<T, ALLOC>::end() +{ + return const_cast<ALLOC*>(this->allocator())->end(); +} + + +/** + * @brief Ending const iterator. + * + * This may only be instantiated if the underlying Allocator + * supports iterators. + */ +template <class T, class ALLOC> +typename ArenaHandleBaseT<T, ALLOC>::const_iterator +ArenaHandleBaseT<T, ALLOC>::end() const +{ + return const_cast<const ALLOC*>(this->allocator())->end(); +} + + +/** + * @brief Free an element. + * @param p The element to be freed. + * + * @c clear() will be called on the element at this point, + * if it has been defined. + * + * This may only be instantiated if it's supported + * by the underlying Allocator. + */ +template <class T, class ALLOC> +inline +void ArenaHandleBaseT<T, ALLOC>::free (pointer p) +{ + this->allocator()->free + (reinterpret_cast<typename ALLOC::pointer>(p)); +} + + +/** + * @brief Reset pool back to a previous state. + * @param p The pointer back to which to reset. + * + * This will free (a la @c reset) the element @c p and all elements + * that have been allocated after it from this allocator. + * + * This may only be instantiated if it's supported + * by the underlying Allocator. + */ +template <class T, class ALLOC> +void ArenaHandleBaseT<T, ALLOC>::resetTo(pointer p) +{ + return this->allocator()->resetTo + (reinterpret_cast<typename ALLOC::pointer>(p)); +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/ArenaHeader.h b/Control/AthAllocators/AthAllocators/ArenaHeader.h new file mode 100755 index 0000000000000000000000000000000000000000..8d348ca7bb6e10e5941f7e7ca2de77654c61dcec --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHeader.h @@ -0,0 +1,170 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeader.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHeader.h + * @author scott snyder + * @date May 2007 + * @brief Proxy for a group of Arenas. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAHEADER_H +#define ATLALLOCATORS_ARENAHEADER_H + + +#include <vector> +#include <cstdlib> +#include <string> +#include <iosfwd> + + +namespace SG { + + +class ArenaAllocatorBase; +class ArenaBase; + + +/** + * @brief Proxy for a group of Arenas. + * See Arena.h for an overview of the arena-based memory allocators. + * + * A Header collects a group of Arenas. One of these is the current Arena, + * in which memory operations will take place. We can also generate + * a report of memory usage from all the Arenas in the group. + * + * This is also where we handle the mapping from indices to Allocator + * instances. This is done simply with a vector of Allocator pointers. + * Each Arena has such a vector. We keep a pointer to one of these; + * that's what defines the notion of the current Arena. + */ +class ArenaHeader +{ +public: + /// Vector of pointers to Allocator instances. + typedef std::vector<ArenaAllocatorBase*> ArenaAllocVec_t; + + + /** + * @brief Constructor. + */ + ArenaHeader(); + + + /** + * @brief Destructor. + * + * This will clean up any memory allocated in the default Arena. + */ + ~ArenaHeader(); + + + /** + * @brief Translate an integer index to an Allocator index. + * @param i The index to look up. + * + * If the index isn't valid, an assertion will be tripped. + */ + ArenaAllocatorBase* allocator (size_t i); + + + /** + * @brief Set the current Arena. + * @param allocvec New vector of Allocator instances. + * @return The previous vector. + * + * This sets the notion of the current Arena. + */ + ArenaAllocVec_t* setAllocVec (ArenaAllocVec_t* allocvec); + + + /** + * @brief Add a new Arena to the group. + * @param a The Arena to add. + */ + void addArena (ArenaBase* a); + + + /** + * @brief Remove an Arena from the group. + * @param a The Arena to remove. + * + * Will trip an assertion if the Arena is not in the group. + */ + void delArena (ArenaBase* a); + + + /** + * @brief Generate a report of all Arenas in the group. + * @param os Stream to which to send a report. + */ + void report (std::ostream& os) const; + + + /** + * @brief Generate a report of all Arenas in the group, and return + * the result as a string. + * + * We have this in addition to @c report() in order to make it easier + * to call from scripting languages. + */ + std::string reportStr () const; + + + /** + * @brief Call @c reset on all Allocators in the current Arena. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Return the global default Header instance. + */ + static ArenaHeader* defaultHeader(); + + +private: + /** + * @brief Make a new Allocator for index i. + * @param i The index of the Allocator. + * + * The Allocator vector was empty for index @c i. Make an appropriate + * new Allocator, store it in the vector, and return it. Will trip + * an assertion if the index is not valid. + */ + ArenaAllocatorBase* makeAllocator (size_t i); + + + /// Current vector of Allocators. + ArenaAllocVec_t* m_allocvec; + + /// Vector of Allocators which are owned by this object. + /// This constitutes the default Arena. + ArenaAllocVec_t* m_ownedAllocvec; + + /// List of all Arenas in our group. + std::vector<ArenaBase*> m_arenas; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHeader.icc" + + + +#endif // not ATLALLOCATORS_ARENAHEADER_H + diff --git a/Control/AthAllocators/AthAllocators/ArenaHeader.icc b/Control/AthAllocators/AthAllocators/ArenaHeader.icc new file mode 100755 index 0000000000000000000000000000000000000000..bd358a02820b1f2b507a22b89d9d661c159b3646 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHeader.icc @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeader.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaHeader.icc + * @author scott snyder + * @date May 2007 + * @brief Proxy for a group of Arenas. + * Inline implementations. + */ + + +namespace SG { + + +/** + * @brief Translate an integer index to an Allocator index. + * @param i The index to look up. + * + * If the index isn't valid, an assertion will be tripped. + * + * This is on the fast path for element allocation, so keep + * it small and inline. + */ +inline +ArenaAllocatorBase* ArenaHeader::allocator (size_t i) +{ + if (m_allocvec && i < m_allocvec->size()) { + ArenaAllocatorBase* allocbase = (*m_allocvec)[i]; + if (allocbase) return allocbase; + } + return makeAllocator (i); +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/ArenaHeaderGaudiClear.h b/Control/AthAllocators/AthAllocators/ArenaHeaderGaudiClear.h new file mode 100755 index 0000000000000000000000000000000000000000..a2e9f2c1f7e73aefa0d02162b48df736da59fd0e --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHeaderGaudiClear.h @@ -0,0 +1,105 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeaderGaudiClear.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHeaderGaudiClear.h + * @author scott snyder + * @date May 2007 + * @brief An @c ArenaHeader that's cleared on every Gaudi event. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAHEADERGAUDICLEAR_H +#define ATLALLOCATORS_ARENAHEADERGAUDICLEAR_H + + +#include "AthAllocators/ArenaHeader.h" +#include "GaudiKernel/IIncidentListener.h" + + +namespace SG { + + +/** + * @brief An @c ArenaHeader that's cleared on every Gaudi event. + * + * This is a version of @c ArenaHeader on which @c reset will be called + * automatically on every new event. + */ +class ArenaHeaderGaudiClear + : public ArenaHeader, + public IIncidentListener +{ +public: + /** + * @brief Constructor. + */ + ArenaHeaderGaudiClear(); + + + /** + * @brief Register with Gaudi. + */ + void initialize(); + + + /** + * @brief Handle a Gaudi incident. + * @param inc The incident to handle. + */ + virtual void handle(const Incident& inc); + + + /** + * @brief Increase the reference count. (Required by @c IInterface.) + */ + virtual unsigned long addRef(); + + + /** + * @brief Decrease the reference count. (Required by @c IInterface.) + */ + virtual unsigned long release(); + + + /** + * @brief Return the Gaudi interface for this object. + * (Required by @c IInterface.) + */ + virtual StatusCode queryInterface(const InterfaceID& riid, + void** ppvInterface); + + + /** + * @brief Disable the Gaudi functionality. + * + * If this is called before @c initialize(), we will not attempt + * to register ourselves with Gaudi. This can be used for running + * outside of the framework. + */ + static void disable(); + + +private: + /// True after we've called @c initialize(). + bool m_initialized; + + /// Current reference count. + unsigned int m_instanceCount; + + /// True if @c disable has been called. + static bool m_disabled; +}; + + +} // namespace SG + + +#endif // not ATLALLOCATORS_ARENAHEADERGAUDICLEAR_H + diff --git a/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.h b/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.h new file mode 100755 index 0000000000000000000000000000000000000000..4f278d5aca448f8527db806ddb8fec8fd9b3de0e --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.h @@ -0,0 +1,200 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapAllocator.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaHeapAllocator.h + * @author scott snyder + * @date May 2007 + * @brief Heap-based allocator. + * See Arena.h for an overview of the arena-based memory allocators. + */ + + +#ifndef ATLALLOCATORS_ARENAHEAPALLOCATOR_H +#define ATLALLOCATORS_ARENAHEAPALLOCATOR_H + + +#include "AthAllocators/ArenaBlockAllocatorBase.h" +#include <cstdlib> + + +namespace SG { + + +class ArenaBlock; + + +/** + * @brief Heap-based allocator. + * See Arena.h for an overview of the arena-based memory allocators. + * + * This is a block-based memory allocator, with heap-like behavior. + * This allows freeing individual elements, but we don't implement + * @c resetTo or an iterator. + * + * There are some extra costs though. + * + * - We need an additional pointer (`link') for each free element. + * + * By default, this is done by increasing the element size by a pointer, + * since we don't know whether there is data in the element itself + * that must be preserved across free/allocate. However, if you know + * that part of the element may be safely while it is free, then + * the allocator can be configured to use that as the link instead. + * + * - When @c reset() is called, we need to call @c clear() on all + * allocated elements (if it is defined). If @c canReclear is set, + * then we just call @c clear() on all elements in allocated blocks + * on @c reset(), regardless of whether or not the individual elements + * are allocated or not. Otherwise, we make two passes over the elements, + * first to build a list of those that are allocated and second + * to actually call @c clear(). + * + * An intermediate strategy, not currently implemented, could be used + * if the link does not overlap the element: set the link to a magic + * value when an element is allocated. + */ +class ArenaHeapAllocator + : public ArenaBlockAllocatorBase +{ +public: + /** + * @brief Helper to initialize a parameters structure. + * + * This creates a @c Params class appropriately initialized for class @c T. + * Assumptions made: + * - The constructor and destructor calls will be filled in + * if non-trivial, unless no_ctor or no_dtor is set to true. + * - The clear call will be filled in if the optional template parameter + * @c clear is true. + * - No space will be reserved for an extra link. + * - @c canReclear is @c true and @c mustClear is @c false. + * - The link will be allocated externally to the element. + * + * If these are not appropriate, you can derive from this class + * and make the appropriate changes. + */ + template <typename T, + bool clear = false, + bool no_ctor = false, + bool no_dtor = false> + struct initParams + : public ArenaAllocatorBase::initParams<T, clear, no_ctor, no_dtor> + { + // Short name for our base class. + typedef ArenaAllocatorBase::initParams<T, clear, no_ctor, no_dtor> Base; + + + /** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + initParams (size_t nblock = 1000, const std::string& name = ""); + + /// Return an initialized parameters structure. + ArenaAllocatorBase::Params params() const; + + /// Return an initialized parameters structure. + // Note: gcc 3.2.3 doesn't allow defining this out-of-line. + operator ArenaAllocatorBase::Params() const { return params(); } + }; + + + /** + * @brief Constructor. + * @param params The parameters structure for this allocator. + * See @c ArenaAllocatorBase.h for the contents. + */ + ArenaHeapAllocator (const Params& params); + + + /** + * @brief Destructor. This will free all the Allocator's storage. + */ + ~ArenaHeapAllocator(); + + + /** + * @brief Allocate a new element. + * + * The fast path of this will be completely inlined. + */ + pointer allocate(); + + + /** + * @brief Free an element. + * @param p The element to be freed. + * + * @c clear() will be called on the element at this point, + * if it has been defined. + */ + void free (pointer p); + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + virtual void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + virtual void erase(); + + + // These are just placeholders --- the iterators are not implemented. + typedef void iterator; + typedef void const_iterator; + + +private: + /** + * @brief Call @c clear() for all allocated elements. + */ + void slowClear(); + + + /** + * @brief Add more free elements to the pool, and allocate a new element. + */ + pointer refill(); + + + /** + * @brief Return a reference to the link for an element. + * @param p The element. + */ + pointer& link (pointer p) const; + + /// Pointer to the next free element. + pointer m_freeptr; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHeapAllocator.icc" + + +#endif // not ATLALLOCATORS_ARENAHEAPALLOCATOR_H diff --git a/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.icc b/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.icc new file mode 100755 index 0000000000000000000000000000000000000000..47706751745086354b9c401e555b9760ea15aad3 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHeapAllocator.icc @@ -0,0 +1,107 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapAllocator.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaPoolAllocator.icc + * @author scott snyder + * @date May 2007 + * @brief Heap-based allocator. + * Inline and template implementations. + */ + + +namespace SG { + + +/** + * @brief Constructor for parameters helper. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <typename T, bool clear, bool no_ctor, bool no_dtor> +ArenaHeapAllocator::initParams<T, clear, no_ctor, no_dtor>:: +initParams (size_t nblock /*=1000*/, const std::string& name /*=""*/) + : Base (nblock, name) +{ +} + + +/** + * @brief Return an initialized parameters structure. + */ +template <typename T, bool clear, bool no_ctor, bool no_dtor> +ArenaAllocatorBase::Params +ArenaHeapAllocator::initParams<T, clear, no_ctor, no_dtor>::params() const +{ + // Do the base class stuff. + Params p = Base::operator ArenaAllocatorBase::Params(); + + // Allow space for an extra pointer. + struct Dummy { + T x; + pointer y; + }; + p.eltSize = sizeof (Dummy); + Dummy* dummy = (Dummy*)0x1234; + p.linkOffset = (char*)&dummy->y - (char*)dummy; + + // Need to allow at least enough space for a pointer. + p.minSize = sizeof (pointer); + + return p; +} + + +/** + * @brief Allocate a new element. + * + * The fast path of this will be completely inlined. + */ +inline +ArenaHeapAllocator::pointer ArenaHeapAllocator::allocate() +{ + ++m_stats.elts.inuse; + pointer ret = m_freeptr; + if (ret) { + m_freeptr = link (ret); + return ret; + } + return refill(); +} + + +/** + * @brief Free an element. + * @param p The element to be freed. + * + * @c clear() will be called on the element at this point, + * if it has been defined. + */ +inline +void ArenaHeapAllocator::free (pointer p) +{ + if (m_params.clear) + m_params.clear (p); + link (p) = m_freeptr; + m_freeptr = p; + --m_stats.elts.inuse; +} + + +/** + * @brief Return a reference to the link for an element. + * @param p The element. + */ +inline +ArenaHeapAllocator::pointer& ArenaHeapAllocator::link (pointer p) const +{ + return *reinterpret_cast<pointer*> (p + m_params.linkOffset); +} + + +} // namespace SG + diff --git a/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.h b/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.h new file mode 100644 index 0000000000000000000000000000000000000000..259f5ce28deead2fc67413d6425ae2cfa598d292 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.h @@ -0,0 +1,388 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapSTLAllocator.h,v 1.2 2008-08-26 02:12:26 ssnyder Exp $ + +/** + * @file AthAllocators/ArenaHeapSTLAllocator.h + * @author scott snyder + * @date Nov 2011 + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator. + * + * This class defines a STL-style allocator for types @c T with the + * following special properties. + * + * - We use an @c ArenaHeapAllocator for allocations. + * - The memory is owned directly by the allocator object. + * - Only one object at a time may be allocated. + * + * So, this allocator is suitable for an STL container which allocates + * lots of fixed-size objects, such as @c std::list. + * + * Much of the complexity here is due to the fact that the allocator + * type that gets passed to the container is an allocator for the + * container's value_type, but that allocator is not actually + * used to allocate memory. Instead, an allocator for the internal + * node type is used. This makes it awkward if you want to have + * allocators that store state. + * + * Further, to avoid creating a pool for the allocator for the container's + * value_type (when the container doesn't actually use that for allocation), + * this template has a second argument. This defaults to the first argument, + * but is passed through by rebind. If the first and second argument + * are the same, then we don't create a pool. + * + * The effect of all this is that you can give an allocator type like + * ArenaHeapSTLAllocator<Mytype> + * to a STL container. Allocators for Mytype won't use + * a pool, but an allocator for node<Mytype> will use the pool. + */ + + +#ifndef ATLALLOCATORS_ARENAHEAPSTLALLOCATOR +#define ATLALLOCATORS_ARENAHEAPSTLALLOCATOR + + +#include "AthAllocators/ArenaHeapAllocator.h" +#include <string> + + +namespace SG { + + +/** + * @brief Initializer for pool allocator parameters. + * + * We override the defaults to disable calling the payload ctor/dtor. + */ +template <class T> +class ArenaHeapSTLAllocator_initParams + : public ArenaHeapAllocator::initParams<T, false, true, true> +{ +public: + /// We take defaults from this. + typedef ArenaHeapAllocator::initParams<T, false, true, true> Base; + + /** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaHeapSTLAllocator_initParams (size_t nblock = 1000, + const std::string& name = ""); + + /// Return an initialized parameters structure. + ArenaAllocatorBase::Params params() const; + + /// Return an initialized parameters structure. + // Note: gcc 3.2.3 doesn't allow defining this out-of-line. + operator ArenaAllocatorBase::Params() const { return params(); } +}; + + +/** + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator. + * This is the generic specialization, which uses the heap allocator. + * + * See the file-level comments for details. + */ +template <class T, class VETO=T> +class ArenaHeapSTLAllocator +{ +public: + /// Standard STL allocator typedefs. + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaHeapSTLAllocator<U, VETO> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaHeapSTLAllocator (size_t nblock = 1000, const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaHeapSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ + template <class U, class V> + ArenaHeapSTLAllocator (const ArenaHeapSTLAllocator<U, V>& a); + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + + + /// Convert a reference to an address. + pointer address (reference x) const; + const_pointer address (const_reference x) const; + + + /** + * @brief Allocate new objects. + * @param n Number of objects to allocate. Must be 1. + * @param hint Allocation hint. Not used. + */ + pointer allocate (size_type n, const void* hint = 0); + + + /** + * @brief Deallocate objects. + * @param n Number of objects to deallocate. Must be 1. + */ + void deallocate (pointer, size_type n); + + + /** + * @brief Return the maximum number of objects we can allocate at once. + * + * This always returns 1. + */ + size_type max_size() const throw(); + + + /** + * @brief Call the @c T constructor. + * @param p Location of the memory. + * @param val Parameter to pass to the constructor. + */ + void construct (pointer p, const T& val); + + + /** + * @brief Call the @c T destructor. + * @param p Location of the memory. + */ + void destroy (pointer p); + + + /** + * @brief Return the hinted number of objects allocated per block. + */ + size_t nblock() const; + + + /** + * @brief Return the name of this allocator. + */ + const std::string& name() const; + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return a pointer to the underlying allocator (may be 0). + */ + ArenaAllocatorBase* poolptr() const; + + +private: + /// The underlying allocator. + ArenaHeapAllocator m_pool; +}; + + + +/** + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator. + * This is the specialization for the case of the vetoed type. + * + * See the file-level comments for details. + */ +template <class T> +class ArenaHeapSTLAllocator<T, T> + : public std::allocator<T> +{ +public: + typedef std::allocator<T> base; + + /// Standard STL allocator typedefs. + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaHeapSTLAllocator<U, T> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaHeapSTLAllocator (size_t nblock = 1000, const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaHeapSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ + template <class U, class V> + ArenaHeapSTLAllocator (const ArenaHeapSTLAllocator<U, V>& a); + + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + + + /** + * @brief Return the hinted number of objects allocated per block. + */ + size_t nblock() const; + + + /** + * @brief Return the name of this allocator. + */ + const std::string& name() const; + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return a pointer to the underlying allocator (may be 0). + */ + ArenaAllocatorBase* poolptr() const; + + +private: + /// Saved hinted number of objects per block. + size_t m_nblock; + + /// Saved allocator name. + std::string m_name; + + /// Point at an underlying allocator from a different specialization. + ArenaAllocatorBase* m_poolptr; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaHeapSTLAllocator.icc" + + +#endif // ATLALLOCATORS_ARENAHEAPSTLALLOCATOR diff --git a/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.icc b/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.icc new file mode 100644 index 0000000000000000000000000000000000000000..570fc5d2b7b679fc19b9921a54210acf8da4a595 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaHeapSTLAllocator.icc @@ -0,0 +1,432 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapSTLAllocator.icc,v 1.2 2008-08-26 02:12:26 ssnyder Exp $ +/** + * @file AthAllocators/ArenaHeapSTLAllocator.icc + * @author scott snyder + * @date Nov 2011 + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator. + */ + + +#include <cassert> + + +namespace SG { + + + +//**************************************************************************** +// Generic specialization +// + + +/** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T> +ArenaHeapSTLAllocator_initParams<T>::ArenaHeapSTLAllocator_initParams + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : Base (nblock, name) +{ +} + + +/** + * @brief Return an initialized parameters structure. + */ +template <class T> +ArenaAllocatorBase::Params ArenaHeapSTLAllocator_initParams<T>::params() const +{ + // Do the base class stuff. + ArenaAllocatorBase::Params p = + Base::operator ArenaAllocatorBase::Params(); + + // Disable ctor/dtor. + p.constructor = 0; + p.destructor = 0; + + // Overlap link over free struct. + p.eltSize = std::max (sizeof(T), p.minSize); + p.linkOffset = 0; + + return p; +} + + +/** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T, class VETO> +ArenaHeapSTLAllocator<T, VETO>::ArenaHeapSTLAllocator + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : m_pool (ArenaHeapSTLAllocator_initParams<T> (nblock, name)) +{ +} + + +/** + * @brief Constructor from another @c ArenaHeapSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ +template <class T, class VETO> +template <class U, class V> +ArenaHeapSTLAllocator<T, VETO>::ArenaHeapSTLAllocator + (const ArenaHeapSTLAllocator<U, V>& a) + : m_pool (ArenaHeapSTLAllocator_initParams<T> (a.nblock(), a.name())) +{ +} + + +/** + * @brief Convert a reference to an address. + */ +template <class T, class VETO> +inline +typename ArenaHeapSTLAllocator<T, VETO>::pointer +ArenaHeapSTLAllocator<T, VETO>::address (reference x) const +{ + return &x; +} + + +/** + * @brief Convert a reference to an address. + */ +template <class T, class VETO> +inline +typename ArenaHeapSTLAllocator<T, VETO>::const_pointer +ArenaHeapSTLAllocator<T, VETO>::address (const_reference x) const +{ + return &x; +} + + + +/** + * @brief Allocate new objects. + * @param n Number of objects to allocate. Must be 1. + * @param hint Allocation hint. Not used. + */ +template <class T, class VETO> +inline +typename ArenaHeapSTLAllocator<T, VETO>::pointer +ArenaHeapSTLAllocator<T, VETO>::allocate (size_type +#ifndef NDEBUG + n +#endif + , const void* /*hint = 0*/) +{ + assert (n == 1); + return reinterpret_cast<pointer> (m_pool.allocate()); +} + + +/** + * @brief Deallocate objects. + * @param n Number of objects to deallocate. Must be 1. + * + * This implementation doesn't do anything. + */ +template <class T, class VETO> +inline +void ArenaHeapSTLAllocator<T, VETO>::deallocate (pointer p, size_type +#ifndef NDEBUG + n +#endif + ) +{ + assert (n == 1); + m_pool.free (reinterpret_cast<ArenaHeapAllocator::pointer> (p)); +} + + +/** + * @brief Return the maximum number of objects we can allocate at once. + * + * This always returns 1. + */ +template <class T, class VETO> +inline +typename ArenaHeapSTLAllocator<T, VETO>::size_type +ArenaHeapSTLAllocator<T, VETO>::max_size() const throw() +{ + return 1; +} + + +/** + * @brief Call the @c T constructor. + * @param p Location of the memory. + * @param val Parameter to pass to the constructor. + */ +template <class T, class VETO> +inline +void ArenaHeapSTLAllocator<T, VETO>::construct (pointer p, const T& val) +{ + new (reinterpret_cast<void*>(p)) T(val); +} + + +/** + * @brief Call the @c T destructor. + * @param p Location of the memory. + */ +template <class T, class VETO> +inline +void ArenaHeapSTLAllocator<T, VETO>::destroy (pointer p) +{ + p->~T(); +} + + +/** + * @brief Return the hinted number of objects allocated per block. + */ +template <class T, class VETO> +inline +size_t ArenaHeapSTLAllocator<T, VETO>::nblock() const +{ + return m_pool.params().nblock; +} + + +/** + * @brief Return the name of this allocator. + */ +template <class T, class VETO> +inline +const std::string& ArenaHeapSTLAllocator<T, VETO>::name() const +{ + return m_pool.name(); +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +template <class T, class VETO> +void ArenaHeapSTLAllocator<T, VETO>::reset() +{ + m_pool.reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +template <class T, class VETO> +void ArenaHeapSTLAllocator<T, VETO>::erase() +{ + m_pool.erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +template <class T, class VETO> +void ArenaHeapSTLAllocator<T, VETO>::reserve (size_t size) +{ + m_pool.reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +template <class T, class VETO> +const ArenaAllocatorBase::Stats& ArenaHeapSTLAllocator<T, VETO>::stats() const +{ + return m_pool.stats(); +} + + +/** + * @brief Return a pointer to the underlying allocator (may be 0). + */ +template <class T, class VETO> +ArenaAllocatorBase* ArenaHeapSTLAllocator<T, VETO>::poolptr() const +{ + const ArenaAllocatorBase* tmp = &m_pool; + return const_cast<ArenaAllocatorBase*> (tmp); +} + + +//**************************************************************************** +// Vetoed specialization. +// + + +/** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T> +ArenaHeapSTLAllocator<T, T>::ArenaHeapSTLAllocator + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : m_nblock (nblock), + m_name (name), + m_poolptr (0) +{ +} + + +/** + * @brief Constructor from another @c ArenaHeapSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ +template <class T> +template <class U, class V> +ArenaHeapSTLAllocator<T, T>::ArenaHeapSTLAllocator + (const ArenaHeapSTLAllocator<U, V>& a) + : m_nblock (a.nblock()), + m_name (a.name()), + m_poolptr (a.poolptr()) +{ +} + + +/** + * @brief Return the hinted number of objects allocated per block. + */ +template <class T> +inline +size_t ArenaHeapSTLAllocator<T, T>::nblock() const +{ + return m_nblock; +} + + +/** + * @brief Return the name of this allocator. + */ +template <class T> +inline +const std::string& ArenaHeapSTLAllocator<T, T>::name() const +{ + return m_name; +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +template <class T> +void ArenaHeapSTLAllocator<T, T>::reset() +{ + if (m_poolptr) + m_poolptr->reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +template <class T> +void ArenaHeapSTLAllocator<T, T>::erase() +{ + if (m_poolptr) + m_poolptr->erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +template <class T> +void ArenaHeapSTLAllocator<T, T>::reserve (size_t size) +{ + if (m_poolptr) + m_poolptr->reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +template <class T> +const ArenaAllocatorBase::Stats& +ArenaHeapSTLAllocator<T, T>::stats() const +{ + if (m_poolptr) + return m_poolptr->stats(); + static ArenaAllocatorBase::Stats tmp; + return tmp; +} + + +/** + * @brief Return a pointer to the underlying allocator (may be 0). + */ +template <class T> +ArenaAllocatorBase* ArenaHeapSTLAllocator<T, T>::poolptr() const +{ + return m_poolptr; +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.h b/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.h new file mode 100755 index 0000000000000000000000000000000000000000..be2743f3851dcecdb4b47173ead3bd9958132879 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.h @@ -0,0 +1,256 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolAllocator.h 470529 2011-11-24 23:54:22Z ssnyder $ + +/** + * @file AthAllocators/ArenaPoolAllocator.h + * @author scott snyder + * @date May 2007 + * @brief Pool-based allocator. + * See Arena.h for an overview of the arena-based memory allocators. + */ + +#ifndef ATLALLOCATORS_ARENAPOOLALLOCATOR_H +#define ATLALLOCATORS_ARENAPOOLALLOCATOR_H + + +#include "AthAllocators/ArenaBlockAllocatorBase.h" +#include "boost/iterator/iterator_adaptor.hpp" +#include <cstdlib> + + +namespace SG { + + +class ArenaBlock; + + +/** + * @brief Pool-based allocator. + * See Arena.h for an overview of the arena-based memory allocators. + * + * This is a block-based memory allocator, with stack-like behavior + * (like the @c DataPool class). We do not allow freeing individual + * elements; instead, we support @c resetTo(p), which frees @p and all + * elements allocated after it (in this allocator). We also implement + * an iterator over the allocated blocks. + */ +class ArenaPoolAllocator + : public ArenaBlockAllocatorBase +{ +public: + // Needed forward declaration. + class const_iterator; + + /** + * @brief Non-const iterator for the pool. + * It iterates over all allocated blocks (in unspecified order). + * + * We use @c boost::iterator_adaptor, and take a @c pointer + * as the base iterator type. Besides that, we also need + * to record the current block which we're within. + */ + class iterator + : public boost::iterator_adaptor< + iterator, + pointer, + boost::use_default, + boost::forward_traversal_tag> + { + public: + /** + * @brief Default constructor. + */ + iterator (); + + + /** + * @brief Constructor. + * @param p Pointer to the element. + * @param block Block containing the element. + */ + iterator (pointer p, ArenaBlock* block); + + + // To allow initializing a @c const_iterator from an @c iterator. + friend class const_iterator; + + + private: + /// Block containing the current element. + ArenaBlock* m_block; + + // Required by @c iterator_adaptor. + friend class boost::iterator_core_access; + + /// Move the iterator forward. + void increment(); + }; + + + /** + * @brief Const iterator for the pool. + * It iterates over all allocated blocks (in unspecified order). + * + * We use @c boost::iterator_adaptor, and take a @c pointer + * as the base iterator type. Besides that, we also need + * to record the current block which we're within. + */ + class const_iterator + : public boost::iterator_adaptor< + const_iterator, + const_pointer, + boost::use_default, + boost::forward_traversal_tag> + { + public: + /** + * @brief Default constructor. + */ + const_iterator (); + + + /** + * @brief Constructor. + * @param p Pointer to the element. + * @param block Block containing the element. + */ + const_iterator (pointer p, ArenaBlock* block); + + + /** + * @brief Constructor from @c iterator. + * @param it The iterator to copy. + */ + const_iterator (const iterator& it); + + + private: + /// Block containing the current element. + ArenaBlock* m_block; + + // Required by @c iterator_adaptor. + friend class boost::iterator_core_access; + + /// Move the iterator forward. + void increment(); + }; + + + /** + * @brief Constructor. + * @param params The parameters structure for this allocator. + * See @c ArenaAllocatorBase.h for the contents. + */ + ArenaPoolAllocator (const Params& params); + + + /** + * @brief Destructor. This will free all the Allocator's storage. + */ + ~ArenaPoolAllocator(); + + + /** + * @brief Allocate a new element. + * + * The fast path of this will be completely inlined. + */ + pointer allocate(); + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + virtual void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + virtual void erase(); + + + /** + * @brief Reset pool back to a previous state. + * @param p The pointer back to which to reset. + * + * This will free (a la @c reset) the element @c p and all elements + * that have been allocated after it from this allocator. + */ + void resetTo (pointer p); + + + /** + * @brief Starting pool iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is a @c forward_iterator. + */ + iterator begin(); + + + /** + * @brief Starting pool const iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is a @c forward_iterator. + */ + const_iterator begin() const; + + + /** + * @brief Ending pool iterator. + */ + iterator end(); + + + /** + * @brief Ending pool const iterator. + */ + const_iterator end() const; + + +private: + /** + * @brief Add more free elements to the pool. + */ + void refill(); + + + /** + * @brief Reset all elements in the topmost block, and move the block + * to the free list. + */ + void clearBlock(); + + + /// Pointer to the next free element to allocate, or null. + pointer m_ptr; + + /// One past the last available element in the current block, of null. + pointer m_end; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaPoolAllocator.icc" + + +#endif // not ATLALLOCATORS_ARENABLOCK_H diff --git a/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.icc b/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.icc new file mode 100755 index 0000000000000000000000000000000000000000..ea333449f1178ba3ff81b1243e68bcfb4fa980b9 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaPoolAllocator.icc @@ -0,0 +1,102 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolAllocator.icc 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/ArenaPoolAllocator.icc + * @author scott snyder + * @date May 2007 + * @brief Pool-based allocator. + * Inline implementations. + */ + + +namespace SG { + + +/** + * @brief Default constructor. + */ +inline +ArenaPoolAllocator::iterator::iterator() + : iterator::iterator_adaptor_ (0), + m_block (0) +{ +} + + +/** + * @brief Constructor. + * @param p Pointer to the element. + * @param block Block containing the element. + */ +inline +ArenaPoolAllocator::iterator::iterator (pointer p, ArenaBlock* block) + : iterator::iterator_adaptor_ (p), + m_block (block) +{ +} + + +/** + * @brief Default constructor. + */ +inline +ArenaPoolAllocator::const_iterator::const_iterator () + : const_iterator::iterator_adaptor_ (0), + m_block (0) +{ +} + + +/** + * @brief Constructor. + * @param p Pointer to the element. + * @param block Block containing the element. + */ +inline +ArenaPoolAllocator::const_iterator::const_iterator (pointer p, + ArenaBlock* block) + : const_iterator::iterator_adaptor_ (p), + m_block (block) +{ +} + + +/** + * @brief Constructor from @c iterator. + * @param it The iterator to copy. + */ +inline +ArenaPoolAllocator::const_iterator::const_iterator (const iterator& it) + : const_iterator::iterator_adaptor_ (it.base_reference()), + m_block (it.m_block) +{ +} + + +/** + * @brief Allocate a new element. + * + * The fast path of this will be completely inlined. + */ +inline +ArenaPoolAllocator::pointer ArenaPoolAllocator::allocate() +{ + // If there are no free elements get more. + if (m_ptr >= m_end) + refill(); + + // Take the first free element. + pointer ret = m_ptr; + m_ptr = m_ptr + m_params.eltSize; + + // Update statistics. + ++m_stats.elts.inuse; + + return ret; +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.h b/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.h new file mode 100644 index 0000000000000000000000000000000000000000..5cbff761bdba837187de51a827ee2a29f462993e --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.h @@ -0,0 +1,532 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolSTLAllocator.h,v 1.2 2008-08-26 02:12:26 ssnyder Exp $ + +/** + * @file AthAllocators/ArenaPoolSTLAllocator.h + * @author scott snyder + * @date Jul 2008 + * @brief STL-style allocator wrapper for @c ArenaPoolAllocator. + * + * This class defines a STL-style allocator for types @c T with the + * following special properties. + * + * - For non-pointer @c T's, we use an @c ArenaPoolAllocator. + * For pointer @c T's, we use the standard STL allocator. + * STL @c pair<> types will also use the standard STL allocator. + * Further comments below apply to the first case. + * - The memory is owned directly by the allocator object. + * - Only one object at a time may be allocated. + * - Deallocate doesn't do anything. The only way to release + * the memory is to delete the allocator. + * + * So, this allocator is suitable for an STL container which allocates + * lots of fixed-size objects, where the usage pattern is to fill the + * container up, use it for a while, then delete the container. + * (The particular scenario that inspired this was the map for + * @c NavigationToken.) + * + * Much of the complexity here is due to the fact that the allocator + * type that gets passed to the container is an allocator for the + * container's value_type, but that allocator is not actually + * used to allocate memory. Instead, an allocator for the internal + * node type is used. This makes it awkward if you want to have + * allocators that store state. We also need to support hash tables, + * which make two types of allocation. Nodes are fixed-size and + * are allocated individually, while the hash table is variable-sized + * and is of pointer type. + * + * Further, to avoid creating a pool for the allocator for the container's + * value_type (when the container doesn't actually use that for allocation), + * this template has a second argument. This defaults to the first argument, + * but is passed through by rebind. If the first and second argument + * are the same, then we don't create a pool. + * + * The effect of all this is that you can give an allocator type like + * ArenaPoolSTLAllocator<Mytype> + * to a STL container. Allocators for Mytype and Mytype* won't use + * a pool, but an allocator for node<Mytype> will use the pool. + */ + + +#ifndef ATLALLOCATORS_ARENAPOOLSTLALLOCATOR +#define ATLALLOCATORS_ARENAPOOLSTLALLOCATOR + + +#include "AthAllocators/ArenaPoolAllocator.h" +#include <string> + + +namespace SG { + + +/** + * @brief Initializer for pool allocator parameters. + * + * We override the defaults to disable calling the payload ctor/dtor. + */ +template <class T> +class ArenaPoolSTLAllocator_initParams + : public ArenaAllocatorBase::initParams<T, false, true, true> +{ +public: + /// We take defaults from this. + typedef ArenaAllocatorBase::initParams<T, false, true, true> Base; + + /** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaPoolSTLAllocator_initParams (size_t nblock = 1000, + const std::string& name = ""); + + /// Return an initialized parameters structure. + ArenaAllocatorBase::Params params() const; + + /// Return an initialized parameters structure. + // Note: gcc 3.2.3 doesn't allow defining this out-of-line. + operator ArenaAllocatorBase::Params() const { return params(); } +}; + + +/** + * @brief STL-style allocator wrapper for @c ArenaPoolAllocator. + * This is the generic specialization, which uses the pool allocator. + * + * See the file-level comments for details. + */ +template <class T, class VETO=T> +class ArenaPoolSTLAllocator +{ +public: + /// Standard STL allocator typedefs. + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaPoolSTLAllocator<U, VETO> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaPoolSTLAllocator (size_t nblock = 1000, const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaPoolSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ + template <class U, class V> + ArenaPoolSTLAllocator (const ArenaPoolSTLAllocator<U, V>& a); + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + + + /// Convert a reference to an address. + pointer address (reference x) const; + const_pointer address (const_reference x) const; + + + /** + * @brief Allocate new objects. + * @param n Number of objects to allocate. Must be 1. + * @param hint Allocation hint. Not used. + */ + pointer allocate (size_type n, const void* hint = 0); + + + /** + * @brief Deallocate objects. + * @param n Number of objects to deallocate. Must be 1. + * + * This implementation doesn't do anything. + */ + void deallocate (pointer, size_type n); + + + /** + * @brief Return the maximum number of objects we can allocate at once. + * + * This always returns 1. + */ + size_type max_size() const throw(); + + + /** + * @brief Call the @c T constructor. + * @param p Location of the memory. + * @param val Parameter to pass to the constructor. + */ + void construct (pointer p, const T& val); + + + /** + * @brief Call the @c T destructor. + * @param p Location of the memory. + */ + void destroy (pointer p); + + + /** + * @brief Return the hinted number of objects allocated per block. + */ + size_t nblock() const; + + + /** + * @brief Return the name of this allocator. + */ + const std::string& name() const; + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return a pointer to the underlying allocator (may be 0). + */ + ArenaAllocatorBase* poolptr() const; + + +private: + /// The underlying allocator. + ArenaPoolAllocator m_pool; +}; + + + +/** + * @brief STL-style allocator wrapper for @c ArenaPoolAllocator. + * This is the specialization for pointers, which uses + * the standard STL allocator. + * + * See the file-level comments for details. + */ +template <class T, class VETO> +class ArenaPoolSTLAllocator<T*, VETO> + : public std::allocator<T*> +{ +public: + typedef std::allocator<T*> base; + + /// Standard STL allocator typedefs. + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaPoolSTLAllocator<U, VETO> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaPoolSTLAllocator (size_t nblock = 1000, const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaPoolSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ + template <class U, class V> + ArenaPoolSTLAllocator (const ArenaPoolSTLAllocator<U, V>& a); + + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + + + /** + * @brief Return the hinted number of objects allocated per block. + */ + size_t nblock() const; + + + /** + * @brief Return the name of this allocator. + */ + const std::string& name() const; + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return a pointer to the underlying allocator (may be 0). + */ + ArenaAllocatorBase* poolptr() const; + + +private: + /// Saved hinted number of objects per block. + size_t m_nblock; + + /// Saved allocator name. + std::string m_name; + + /// Point at an underlying allocator from a different specialization. + ArenaAllocatorBase* m_poolptr; +}; + + +/** + * @brief STL-style allocator wrapper for @c ArenaPoolAllocator. + * This is the specialization for the case of the vetoed type. + * + * See the file-level comments for details. + */ +template <class T> +class ArenaPoolSTLAllocator<T, T> + : public std::allocator<T> +{ +public: + typedef std::allocator<T> base; + + /// Standard STL allocator typedefs. + typedef typename base::pointer pointer; + typedef typename base::const_pointer const_pointer; + typedef typename base::reference reference; + typedef typename base::const_reference const_reference; + typedef typename base::value_type value_type; + typedef typename base::size_type size_type; + typedef typename base::difference_type difference_type; + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaPoolSTLAllocator<U, T> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ + ArenaPoolSTLAllocator (size_t nblock = 1000, const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaPoolSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ + template <class U, class V> + ArenaPoolSTLAllocator (const ArenaPoolSTLAllocator<U, V>& a); + + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + + + /** + * @brief Return the hinted number of objects allocated per block. + */ + size_t nblock() const; + + + /** + * @brief Return the name of this allocator. + */ + const std::string& name() const; + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return a pointer to the underlying allocator (may be 0). + */ + ArenaAllocatorBase* poolptr() const; + + +private: + /// Saved hinted number of objects per block. + size_t m_nblock; + + /// Saved allocator name. + std::string m_name; + + /// Point at an underlying allocator from a different specialization. + ArenaAllocatorBase* m_poolptr; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaPoolSTLAllocator.icc" + + +#endif // ATLALLOCATORS_ARENAPOOLSTLALLOCATOR diff --git a/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.icc b/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.icc new file mode 100644 index 0000000000000000000000000000000000000000..1fe2420b4261881a00489e817f27147cb54f1e19 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaPoolSTLAllocator.icc @@ -0,0 +1,567 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolSTLAllocator.icc,v 1.2 2008-08-26 02:12:26 ssnyder Exp $ +/** + * @file AthAllocators/ArenaPoolSTLAllocator.icc + * @author scott snyder + * @date Jul 2008 + * @brief STL-style allocator wrapper for @c ArenaPoolAllocator. + */ + + +#include <cassert> + + +namespace SG { + + + +//**************************************************************************** +// Generic specialization +// + + +/** + * @brief Constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T> +ArenaPoolSTLAllocator_initParams<T>::ArenaPoolSTLAllocator_initParams + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : Base (nblock, name) +{ +} + + +/** + * @brief Return an initialized parameters structure. + */ +template <class T> +ArenaAllocatorBase::Params ArenaPoolSTLAllocator_initParams<T>::params() const +{ + // Do the base class stuff. + ArenaAllocatorBase::Params p = + Base::operator ArenaAllocatorBase::Params(); + + // Disable ctor/dtor. + p.constructor = 0; + p.destructor = 0; + + return p; +} + + +/** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T, class VETO> +ArenaPoolSTLAllocator<T, VETO>::ArenaPoolSTLAllocator + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : m_pool (ArenaPoolSTLAllocator_initParams<T> (nblock, name)) +{ +} + + +/** + * @brief Constructor from another @c ArenaPoolSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ +template <class T, class VETO> +template <class U, class V> +ArenaPoolSTLAllocator<T, VETO>::ArenaPoolSTLAllocator + (const ArenaPoolSTLAllocator<U, V>& a) + : m_pool (ArenaPoolSTLAllocator_initParams<T> (a.nblock(), a.name())) +{ +} + + +/** + * @brief Convert a reference to an address. + */ +template <class T, class VETO> +inline +typename ArenaPoolSTLAllocator<T, VETO>::pointer +ArenaPoolSTLAllocator<T, VETO>::address (reference x) const +{ + return &x; +} + + +/** + * @brief Convert a reference to an address. + */ +template <class T, class VETO> +inline +typename ArenaPoolSTLAllocator<T, VETO>::const_pointer +ArenaPoolSTLAllocator<T, VETO>::address (const_reference x) const +{ + return &x; +} + + + +/** + * @brief Allocate new objects. + * @param n Number of objects to allocate. Must be 1. + * @param hint Allocation hint. Not used. + */ +template <class T, class VETO> +inline +typename ArenaPoolSTLAllocator<T, VETO>::pointer +ArenaPoolSTLAllocator<T, VETO>::allocate (size_type +#ifndef NDEBUG + n +#endif + , const void* /*hint = 0*/) +{ + assert (n == 1); + return reinterpret_cast<pointer> (m_pool.allocate()); +} + + +/** + * @brief Deallocate objects. + * @param n Number of objects to deallocate. Must be 1. + * + * This implementation doesn't do anything. + */ +template <class T, class VETO> +inline +void ArenaPoolSTLAllocator<T, VETO>::deallocate (pointer, size_type +#ifndef NDEBUG + n +#endif + ) +{ + assert (n == 1); +} + + +/** + * @brief Return the maximum number of objects we can allocate at once. + * + * This always returns 1. + */ +template <class T, class VETO> +inline +typename ArenaPoolSTLAllocator<T, VETO>::size_type +ArenaPoolSTLAllocator<T, VETO>::max_size() const throw() +{ + return 1; +} + + +/** + * @brief Call the @c T constructor. + * @param p Location of the memory. + * @param val Parameter to pass to the constructor. + */ +template <class T, class VETO> +inline +void ArenaPoolSTLAllocator<T, VETO>::construct (pointer p, const T& val) +{ + new (reinterpret_cast<void*>(p)) T(val); +} + + +/** + * @brief Call the @c T destructor. + * @param p Location of the memory. + */ +template <class T, class VETO> +inline +void ArenaPoolSTLAllocator<T, VETO>::destroy (pointer p) +{ + p->~T(); +} + + +/** + * @brief Return the hinted number of objects allocated per block. + */ +template <class T, class VETO> +inline +size_t ArenaPoolSTLAllocator<T, VETO>::nblock() const +{ + return m_pool.params().nblock; +} + + +/** + * @brief Return the name of this allocator. + */ +template <class T, class VETO> +inline +const std::string& ArenaPoolSTLAllocator<T, VETO>::name() const +{ + return m_pool.name(); +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +template <class T, class VETO> +void ArenaPoolSTLAllocator<T, VETO>::reset() +{ + m_pool.reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +template <class T, class VETO> +void ArenaPoolSTLAllocator<T, VETO>::erase() +{ + m_pool.erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +template <class T, class VETO> +void ArenaPoolSTLAllocator<T, VETO>::reserve (size_t size) +{ + m_pool.reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +template <class T, class VETO> +const ArenaAllocatorBase::Stats& ArenaPoolSTLAllocator<T, VETO>::stats() const +{ + return m_pool.stats(); +} + + +/** + * @brief Return a pointer to the underlying allocator (may be 0). + */ +template <class T, class VETO> +ArenaAllocatorBase* ArenaPoolSTLAllocator<T, VETO>::poolptr() const +{ + const ArenaAllocatorBase* tmp = &m_pool; + return const_cast<ArenaAllocatorBase*> (tmp); +} + + +//**************************************************************************** +// Pointer specialization. +// + + +/** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T, class VETO> +ArenaPoolSTLAllocator<T*, VETO>::ArenaPoolSTLAllocator + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : m_nblock (nblock), + m_name (name), + m_poolptr (0) +{ +} + + +/** + * @brief Constructor from another @c ArenaPoolSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ +template <class T, class VETO> +template <class U, class V> +ArenaPoolSTLAllocator<T*, VETO>::ArenaPoolSTLAllocator + (const ArenaPoolSTLAllocator<U, V>& a) + : m_nblock (a.nblock()), + m_name (a.name()), + m_poolptr (a.poolptr()) +{ +} + + +/** + * @brief Return the hinted number of objects allocated per block. + */ +template <class T, class VETO> +inline +size_t ArenaPoolSTLAllocator<T*, VETO>::nblock() const +{ + return m_nblock; +} + + +/** + * @brief Return the name of this allocator. + */ +template <class T, class VETO> +inline +const std::string& ArenaPoolSTLAllocator<T*, VETO>::name() const +{ + return m_name; +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +template <class T, class VETO> +void ArenaPoolSTLAllocator<T*, VETO>::reset() +{ + if (m_poolptr) + m_poolptr->reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +template <class T, class VETO> +void ArenaPoolSTLAllocator<T*, VETO>::erase() +{ + if (m_poolptr) + m_poolptr->erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +template <class T, class VETO> +void ArenaPoolSTLAllocator<T*, VETO>::reserve (size_t size) +{ + if (m_poolptr) + m_poolptr->reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +template <class T, class VETO> +const ArenaAllocatorBase::Stats& ArenaPoolSTLAllocator<T*, VETO>::stats() const +{ + if (m_poolptr) + return m_poolptr->stats(); + static ArenaAllocatorBase::Stats tmp; + return tmp; +} + + +/** + * @brief Return a pointer to the underlying allocator (may be 0). + */ +template <class T, class VETO> +ArenaAllocatorBase* ArenaPoolSTLAllocator<T*, VETO>::poolptr() const +{ + return m_poolptr; +} + + +//**************************************************************************** +// Vetoed specialization. +// + + +/** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to set in the parameters structure for the + * allocator name. + */ +template <class T> +ArenaPoolSTLAllocator<T, T>::ArenaPoolSTLAllocator + (size_t nblock /*= 1000*/, const std::string& name /*= ""*/) + : m_nblock (nblock), + m_name (name), + m_poolptr (0) +{ +} + + +/** + * @brief Constructor from another @c ArenaPoolSTLAllocator. + * + * The @c name and @c nblock parameters are copied, but the data are not. + */ +template <class T> +template <class U, class V> +ArenaPoolSTLAllocator<T, T>::ArenaPoolSTLAllocator + (const ArenaPoolSTLAllocator<U, V>& a) + : m_nblock (a.nblock()), + m_name (a.name()), + m_poolptr (a.poolptr()) +{ +} + + +/** + * @brief Return the hinted number of objects allocated per block. + */ +template <class T> +inline +size_t ArenaPoolSTLAllocator<T, T>::nblock() const +{ + return m_nblock; +} + + +/** + * @brief Return the name of this allocator. + */ +template <class T> +inline +const std::string& ArenaPoolSTLAllocator<T, T>::name() const +{ + return m_name; +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +template <class T> +void ArenaPoolSTLAllocator<T, T>::reset() +{ + if (m_poolptr) + m_poolptr->reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +template <class T> +void ArenaPoolSTLAllocator<T, T>::erase() +{ + if (m_poolptr) + m_poolptr->erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +template <class T> +void ArenaPoolSTLAllocator<T, T>::reserve (size_t size) +{ + if (m_poolptr) + m_poolptr->reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +template <class T> +const ArenaAllocatorBase::Stats& +ArenaPoolSTLAllocator<T, T>::stats() const +{ + if (m_poolptr) + return m_poolptr->stats(); + static ArenaAllocatorBase::Stats tmp; + return tmp; +} + + +/** + * @brief Return a pointer to the underlying allocator (may be 0). + */ +template <class T> +ArenaAllocatorBase* ArenaPoolSTLAllocator<T, T>::poolptr() const +{ + return m_poolptr; +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.h b/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.h new file mode 100644 index 0000000000000000000000000000000000000000..879f0eeaf620f631d7487b4cfa96b565f7edfc1d --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.h @@ -0,0 +1,89 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSTLAllocator.h 470825 2011-11-25 23:20:57Z ssnyder $ +/** + * @file AthAllocators/ArenaSTLAllocator.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2011 + * @brief + */ + + +#ifndef ATLALLOCATORS_ARENASTLALLOCATOR_H +#define ATLALLOCATORS_ARENASTLALLOCATOR_H + + +#include <string> +#include <cstdlib> + + +namespace SG { + + +template <class BASE> +class ArenaSTLAllocator + : public BASE +{ +public: + /// Standard STL allocator typedefs. + typedef typename BASE::value_type value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + typedef std::ptrdiff_t difference_type; + + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaSTLAllocator<U> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to use as the base for the allocator names. + */ + ArenaSTLAllocator (size_t nblock = 1000, + const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaSTLAllocator. + * + * The new STL allocator will reference the same set of underlying + * Arena allocators as the old one. + */ + ArenaSTLAllocator (const ArenaSTLAllocator& a); + + + /** + * @brief Constructor from another @c ArenaSTLAllocator. + * + * The new STL allocator will reference the same set of underlying + * Arena allocators as the old one. + */ + template <class U> + ArenaSTLAllocator (const ArenaSTLAllocator<U>& a); + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + +}; + + +} // namespace SG + + + +#include "AthAllocators/ArenaSTLAllocator.icc" + +#endif // not ATLALLOCATORS_ARENASTLALLOCATOR_H diff --git a/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.icc b/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.icc new file mode 100644 index 0000000000000000000000000000000000000000..e056f0d9eededc8f5653fac80af91d389e066afa --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaSTLAllocator.icc @@ -0,0 +1,40 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSTLAllocator.icc 470825 2011-11-25 23:20:57Z ssnyder $ +/** + * @file AthAllocators/ArenaSTLAllocator.icc + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2011 + * @brief + */ + + +namespace SG { + + +template <class BASE> +ArenaSTLAllocator<BASE>::ArenaSTLAllocator (size_t nblock /*= 1000*/, + const std::string& name /*= ""*/) + : BASE (nblock, name) +{ +} + + +template <class BASE> +ArenaSTLAllocator<BASE>::ArenaSTLAllocator (const ArenaSTLAllocator& a) + : BASE (a) +{ +} + + +template <class BASE> +template <class U> +ArenaSTLAllocator<BASE>::ArenaSTLAllocator (const ArenaSTLAllocator<U>& a) + : BASE (a) +{ +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.h b/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.h new file mode 100644 index 0000000000000000000000000000000000000000..80dacc23ea107677945490f85abaf14633fee2d9 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.h @@ -0,0 +1,410 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSharedHeapSTLAllocator.h 552460 2013-06-25 17:29:25Z ssnyder $ +/** + * @file AthAllocators/ArenaSharedHeapSTLAllocator.h + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2011 + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator allowing + * the heap to be shared between containers. + * + * This class defines a STL-style allocator for types @c T with the + * following special properties. + * + * - We use an @c ArenaHeapAllocator for allocations. + * - Only one object at a time may be allocated. + * - The memory from several allocators may be grouped + * together in the same memory pool. + * + * So, this allocator is suitable for an STL container which allocates + * lots of fixed-size objects, such as @c std::list, and further, + * you want to be able to have multiple list instances use + * the same pool. + * + * Note that this allocator will not work for containers that + * make variable-sized allocations, such as vector and the + * hash table containers. + * + * To use it, you should first explicitly create the allocator class, + * and then pass it to the constructors of the containers. + * The memory pool will be deleted when the original allocator + * instance is deleted. Example: + * + *@code + * { + * typedef SG::ArenaSharedHeapSTLAllocator<int> alloc_t; + * typedef std::list<int> list_t; + * + * alloc_t allocator; + * list_t list1 (allocator); + * list_t list2 (allocator); + * ... Now list1 and list2 will both use the same memory pool. + * } + * ... The memory pool is freed when the object `allocator' is deleted. + @endcode + * + * Implementation: Each allocator references a Header object, + * which is common to all allocators in the pool. When an allocator + * is copied, the header pointer is copied too. The Header object + * remembers the address of the allocator which originally created it, + * so that we can clean things up when that allocator goes away. + * + * A Header contains a list of ArenaHeapAllocator objects, one per + * payload type. We use ArenaAllocatorRegistry to assign indices + * to the different allocator types. + */ + + +#ifndef ATLALLOCATORS_ARENASHAREDHEAPSTLALLOCATOR_H +#define ATLALLOCATORS_ARENASHAREDHEAPSTLALLOCATOR_H + + +#include "AthAllocators/ArenaSTLAllocator.h" +#include "AthAllocators/ArenaHeapAllocator.h" +#include "AthAllocators/ArenaHeapSTLAllocator.h" +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include <string> +#include <vector> + + +namespace SG { + +/// Forward declaration. +template <class T> +class ArenaSharedHeapSTLAllocator; + + +/** + * @brief Common header class for ArenaSharedHeapSTLAllocator. + * + * Each ArenaSharedHeapSTLAllocator has a pointer to a Header class. + * When a new ASHSTLAllocator object is constructed, we make a new Header; + * after that, the Header pointer is copied on copy-construction. + * The Header remembers the address of the object that created it, + * so that it can be deleted when that allocator is. + * + * The Header contains a list of ArenaHeapAllocator objects, one for + * each type we're allocating. + */ +class ArenaSharedHeapSTLHeader +{ +public: + /** + * @brief Constructor. + * @param owner Address of the object that owns this Header. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to use as the base for the allocator names. + */ + ArenaSharedHeapSTLHeader (const void* owner, + int nblock, + const std::string& name); + + + /** + * @brief Destructor. + * + * Destroy all the allocators we own. + */ + ~ArenaSharedHeapSTLHeader(); + + + /** + * @brief Call this when an allocator is being deleted. + * @param a The address of calling allocator. + * + * If the address matches the address we were given when we were created, + * this object will be destroyed. + */ + void maybe_delete (const void* a); + + + /** + * @brief Return allocator statistics summed over all our owned allocators. + */ + ArenaAllocatorBase::Stats totstats() const; + + + /** + * @brief Return the name to use for an allocator for type @c T. + */ + template <class T> + std::string get_name(); + + + /** + * @brief Return the heap allocator for type @c T. + * @param index Reference to the index for type @c T. + * Before the first call, this should be initialized + * to std::string::npos. This should generally + * be a static variable. + */ + template <class T> + ArenaHeapAllocator* get_pool (size_t& index); + + + void report (std::ostream& os) const + { + for (size_t i = 0; i < m_allocators.size(); i++) + if (m_allocators[i]) + m_allocators[i]->report (os); + } + + +private: + /// Address of the allocator that created this header. + const void* m_owner; + + /// Saved value for nblock parameter. + size_t m_nblock; + + /// Saved value for base name. + std::string m_name; + + /// List of allocators. + std::vector<ArenaHeapAllocator*> m_allocators; +}; + + + + +/** + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator allowing + * the heap to be shared between containers. + * + * See the file-level comments for details. + */ +template <class T> +class ArenaSharedHeapSTLAllocator +{ +public: + /// Make all instantiations of this class friends + /// (to be able to copy the header pointer). + template <class U> friend class ArenaSharedHeapSTLAllocator; + + /// Standard STL allocator typedefs. + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + + /// Standard STL allocator rebinder. + template <class U> struct rebind { + typedef ArenaSharedHeapSTLAllocator<U> other; + }; + + + /** + * @brief Default constructor. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to use as the base for the allocator names. + */ + ArenaSharedHeapSTLAllocator (size_t nblock = 1000, + const std::string& name = ""); + + + /** + * @brief Constructor from another @c ArenaHeapSTLAllocator. + * + * The new STL allocator will reference the same set of underlying + * Arena allocators as the old one. + */ + ArenaSharedHeapSTLAllocator (const ArenaSharedHeapSTLAllocator& a); + + + /** + * @brief Constructor from another @c ArenaHeapSTLAllocator. + * + * The new STL allocator will reference the same set of underlying + * Arena allocators as the old one. + */ + template <class U> + ArenaSharedHeapSTLAllocator (const ArenaSharedHeapSTLAllocator<U>& a); + + // We don't bother to supply a more general constructor --- shouldn't + // be needed. + + ~ArenaSharedHeapSTLAllocator(); + + + /** + * @brief Assignment. + * + * We allow assignment only if the two objects involved represent + * the same arena, in which case it's a no-op. + * In other cases, we raise an exception. + * + * FIXME: By default, swap() is implemented in terms of this. + * It might be useful, though, to have a swap() that could + * handle different arenas. We would need to be able handle + * updating the ownership back pointers from the headers, though; + * but that's much easier for swap than for the case of general + * assignments. + */ + ArenaSharedHeapSTLAllocator& + operator= (const ArenaSharedHeapSTLAllocator& a); + + + /// Convert a reference to an address. + pointer address (reference x) const; + const_pointer address (const_reference x) const; + + + /** + * @brief Allocate new objects. + * @param n Number of objects to allocate. Must be 1. + * @param hint Allocation hint. Not used. + */ + pointer allocate (size_type n, const void* hint = 0); + + + /** + * @brief Deallocate objects. + * @param n Number of objects to deallocate. Must be 1. + */ + void deallocate (pointer, size_type n); + + + /** + * @brief Return the maximum number of objects we can allocate at once. + * + * This always returns 1. + */ + size_type max_size() const throw(); + + + /** + * @brief Call the @c T constructor. + * @param p Location of the memory. + * @param val Parameter to pass to the constructor. + */ + void construct (pointer p, const T& val); + + + /** + * @brief Call the @c T destructor. + * @param p Location of the memory. + */ + void destroy (pointer p); + + + /** + * @brief Return the hinted number of objects allocated per block. + */ + size_t nblock() const; + + + /** + * @brief Return the name of this allocator. + */ + const std::string& name() const; + + + /** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ + void reset(); + + + /** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ + void erase(); + + + /** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ + void reserve (size_t size); + + + /** + * @brief Return the statistics block for this allocator. + */ + const ArenaAllocatorBase::Stats& stats() const; + + + /** + * @brief Return the statistics blocks summed up over all allocators + * using this pool. + */ + ArenaAllocatorBase::Stats totstats() const; + + + /** + * @brief Return a pointer to the underlying allocator. + * This creates the allocator if needed. + */ + ArenaHeapAllocator* poolptr() const; + + + void report (std::ostream& os) const + { + m_header->report(os); + } + + + + /** + * @brief Compare two allocators. Needed by some @c swap implementations. + * + * We consider two allocators to be the same if they're + * referencing the same Header. + */ + bool operator!= (const ArenaSharedHeapSTLAllocator& other) const; + + +private: + /** + * @brief Ask the Header for the allocator to use. + * This will either return an existing one or create a new one. + */ + void get_pool() const; + + ArenaSharedHeapSTLHeader* m_header; + mutable ArenaHeapAllocator* m_pool; + + static size_t s_index; +}; + + +} // namespace SG + + +#include "AthAllocators/ArenaSharedHeapSTLAllocator.icc" + + +#endif // not ATLALLOCATORS_ARENASHAREDHEAPSTLALLOCATOR_H diff --git a/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.icc b/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.icc new file mode 100644 index 0000000000000000000000000000000000000000..633010dd767052505bc6b4022a96aa34695a5f83 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/ArenaSharedHeapSTLAllocator.icc @@ -0,0 +1,407 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSharedHeapSTLAllocator.icc 496835 2012-04-20 07:58:52Z ssnyder $ +/** + * @file AthAllocators/ArenaSharedHeapSTLAllocator.icc + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2011 + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator allowing + * the heap to be shared between containers. + */ + + +#include "GaudiKernel/System.h" +#include <cassert> +#include <stdexcept> + + +namespace SG { + + +/** + * @brief Call this when an allocator is being deleted. + * @param a The address of calling allocator. + * + * If the address matches the address we were given when we were created, + * this object will be destroyed. + */ +inline +void ArenaSharedHeapSTLHeader::maybe_delete (const void* a) +{ + if (a == m_owner) { + delete this; + } +} + + +/** + * @brief Return the name to use for an allocator for type @c T. + */ +template <class T> +std::string ArenaSharedHeapSTLHeader::get_name() +{ + return m_name + "::ArenaSharedHeapSTLAllocator<" + + System::typeinfoName (typeid (T)) + ">"; +} + + +/** + * @brief Return the heap allocator for type @c T. + * @param index Reference to the index for type @c T. + * Before the first call, this should be initialized + * to std::string::npos. This should generally + * be a static variable. + */ +template <class T> +ArenaHeapAllocator* ArenaSharedHeapSTLHeader::get_pool (size_t& index) +{ + // If we need the name, we'll put it here. + std::string name; + + // If we don't have an index yet, ask the global registry. + // Note: We're only using the registry for the name<->index + // mapping; we're not using it to construct the allocators + // for us. This, we pass in a null pointer for the constructor. + // (We don't construct the allocators from the registry because + // we cant to be able to change the number of blocks from instance + // to instance, but there's no way passing that to the Registry + // interface.) + if (index == std::string::npos) { + name = get_name<T>(); + ArenaAllocatorRegistry* reg = ArenaAllocatorRegistry::instance(); + index = reg->lookup (name); + if (index == std::string::npos) + index = reg->registerCreator (name, 0); + } + + // Expand the list of allocators if needed. + if (index >= m_allocators.size()) + m_allocators.resize (index+1); + + // Create the allocator if we haven't done so yet. + if (!m_allocators[index]) { + if (name.empty()) // Only construct the name once. + name = get_name<T>(); + m_allocators[index] = new ArenaHeapAllocator + (ArenaHeapSTLAllocator_initParams<T> (m_nblock, name)); + } + + // Return the allocator. + return m_allocators[index]; +} + + + +//=========================================================================== + + +template <class T> +size_t ArenaSharedHeapSTLAllocator<T>::s_index = -1; + + +template <class T> +ArenaSharedHeapSTLAllocator<T>::ArenaSharedHeapSTLAllocator + (size_t nblock /*= 1000*/, + const std::string& name /*= ""*/) + : m_header (new ArenaSharedHeapSTLHeader (this, nblock, name)), + m_pool (0) +{ +} + + +template <class T> +inline +ArenaSharedHeapSTLAllocator<T>::ArenaSharedHeapSTLAllocator + (const ArenaSharedHeapSTLAllocator& a) + : m_header (const_cast<ArenaSharedHeapSTLHeader*>(a.m_header)), + m_pool (const_cast<ArenaHeapAllocator*> (a.m_pool)) +{ +} + + +template <class T> +template <class U> +inline +ArenaSharedHeapSTLAllocator<T>::ArenaSharedHeapSTLAllocator + (const ArenaSharedHeapSTLAllocator<U>& a) + : m_header (const_cast<ArenaSharedHeapSTLHeader*>(a.m_header)), + m_pool (0) +{ +} + + +template <class T> +inline +ArenaSharedHeapSTLAllocator<T>::~ArenaSharedHeapSTLAllocator() +{ + m_header->maybe_delete (this); +} + + +/** + * @brief Assignment. + * + * We allow assignment only if the two objects involved represent + * the same arena, in which case it's a no-op. + * In other cases, we raise an exception. + */ +template <class T> +ArenaSharedHeapSTLAllocator<T>& +ArenaSharedHeapSTLAllocator<T>::operator= + (const ArenaSharedHeapSTLAllocator& a) +{ + if (&a != this) { + if (m_header != a.m_header) + throw std::runtime_error + ("Attempt to assign between ArenaSharedHeapSTLAllocators " + "for different arenas"); + assert (m_pool == a.m_pool); + } + return *this; +} + + +/** + * @brief Convert a reference to an address. + */ +template <class T> +inline +typename ArenaSharedHeapSTLAllocator<T>::pointer +ArenaSharedHeapSTLAllocator<T>::address (reference x) const +{ + return &x; +} + + +/** + * @brief Convert a reference to an address. + */ +template <class T> +inline +typename ArenaSharedHeapSTLAllocator<T>::const_pointer +ArenaSharedHeapSTLAllocator<T>::address (const_reference x) const +{ + return &x; +} + + +/** + * @brief Allocate new objects. + * @param n Number of objects to allocate. Must be 1. + * @param hint Allocation hint. Not used. + */ +template <class T> +inline +typename ArenaSharedHeapSTLAllocator<T>::pointer +ArenaSharedHeapSTLAllocator<T>::allocate (size_type +#ifndef NDEBUG + n +#endif + , const void* /*hint = 0*/) +{ + assert (n == 1); + return reinterpret_cast<pointer> (poolptr()->allocate()); +} + + +/** + * @brief Deallocate objects. + * @param n Number of objects to deallocate. Must be 1. + * + * This implementation doesn't do anything. + */ +template <class T> +inline +void ArenaSharedHeapSTLAllocator<T>::deallocate (pointer p, size_type +#ifndef NDEBUG + n +#endif + ) +{ + assert (n == 1); + poolptr()->free (reinterpret_cast<ArenaAllocatorBase::pointer> (p)); +} + + +/** + * @brief Return the maximum number of objects we can allocate at once. + * + * This always returns 1. + */ +template <class T> +inline +typename ArenaSharedHeapSTLAllocator<T>::size_type +ArenaSharedHeapSTLAllocator<T>::max_size() const throw() +{ + return 1; +} + + +/** + * @brief Call the @c T constructor. + * @param p Location of the memory. + * @param val Parameter to pass to the constructor. + */ +template <class T> +inline +void ArenaSharedHeapSTLAllocator<T>::construct (pointer p, const T& val) +{ + new (reinterpret_cast<void*>(p)) T(val); +} + + +/** + * @brief Call the @c T destructor. + * @param p Location of the memory. + */ +template <class T> +inline +void ArenaSharedHeapSTLAllocator<T>::destroy (pointer p) +{ + p->~T(); +} + + +/** + * @brief Return the hinted number of objects allocated per block. + */ +template <class T> +inline +size_t ArenaSharedHeapSTLAllocator<T>::nblock() const +{ + return poolptr()->params().nblock; +} + + +/** + * @brief Return the name of this allocator. + */ +template <class T> +inline +const std::string& ArenaSharedHeapSTLAllocator<T>::name() const +{ + return poolptr()->name(); +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +template <class T> +void ArenaSharedHeapSTLAllocator<T>::reset() +{ + poolptr()->reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +template <class T> +void ArenaSharedHeapSTLAllocator<T>::erase() +{ + poolptr()->erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +template <class T> +void ArenaSharedHeapSTLAllocator<T>::reserve (size_t size) +{ + poolptr()->reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +template <class T> +const ArenaAllocatorBase::Stats& +ArenaSharedHeapSTLAllocator<T>::stats() const +{ + return poolptr()->stats(); +} + + +/** + * @brief Return the statistics blocks summed up over all allocators + * using this pool. + */ +template <class T> +inline +ArenaAllocatorBase::Stats ArenaSharedHeapSTLAllocator<T>::totstats() const +{ + return m_header->totstats(); +} + + +/** + * @brief Return a pointer to the underlying allocator. + * This creates the allocator if needed. + */ +template <class T> +inline +ArenaHeapAllocator* ArenaSharedHeapSTLAllocator<T>::poolptr() const +{ + if (!m_pool) + get_pool(); + return m_pool; +} + + +/** + * @brief Compare two allocators. Needed by some @c swap implementations. + * + * We consider two allocators to be the same if they're + * referencing the same Header. + */ +template <class T> +inline +bool ArenaSharedHeapSTLAllocator<T>::operator!= + (const ArenaSharedHeapSTLAllocator& other) const +{ + return m_header != other.m_header; +} + + +/** + * @brief Ask the Header for the allocator to use. + * This will either return an existing one or create a new one. + */ +template <class T> +inline +void ArenaSharedHeapSTLAllocator<T>::get_pool() const +{ + m_pool = m_header->get_pool<T> (s_index); +} + + +} // namespace SG diff --git a/Control/AthAllocators/AthAllocators/AthAllocatorsDict.h b/Control/AthAllocators/AthAllocators/AthAllocatorsDict.h new file mode 100755 index 0000000000000000000000000000000000000000..09baf47b511d8c2b80a673e8b8254b3aefaa1bbb --- /dev/null +++ b/Control/AthAllocators/AthAllocators/AthAllocatorsDict.h @@ -0,0 +1,5 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#include "AthAllocators/ArenaHeader.h" diff --git a/Control/AthAllocators/AthAllocators/DataPool.h b/Control/AthAllocators/AthAllocators/DataPool.h new file mode 100755 index 0000000000000000000000000000000000000000..6a45c1b23df2f1649c804e350bd6a8abf008dbb9 --- /dev/null +++ b/Control/AthAllocators/AthAllocators/DataPool.h @@ -0,0 +1,154 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef ATHALLOCATORS_DATAPOOL_H +#define ATHALLOCATORS_DATAPOOL_H +/** @class DataPool + * @brief a typed memory pool that saves time spent + * allocation small object. This is typically used + * by container such as DataVector and DataList + * @author Srini Rajagopalan - ATLAS Collaboration + *$Id: DataPool.h 470529 2011-11-24 23:54:22Z ssnyder $ + */ + +#include "AthAllocators/ArenaCachingHandle.h" +#include "AthAllocators/ArenaPoolAllocator.h" +#include <string> +#include "boost/iterator/iterator_adaptor.hpp" + +template <typename VALUE> +class DataPool +{ +private: + typedef SG::ArenaPoolAllocator alloc_t; + typedef SG::ArenaCachingHandle<VALUE, alloc_t> handle_t; + +public: + typedef typename handle_t::pointer pointer; + typedef size_t size_type; + + class const_iterator; + + class iterator + : public boost::iterator_adaptor< + iterator, + typename handle_t::iterator, + VALUE *, + boost::forward_traversal_tag, + VALUE *> + { + public: + iterator (const typename handle_t::iterator& it) + : iterator::iterator_adaptor_ (it) + { + } + + friend class const_iterator; + + private: + friend class boost::iterator_core_access; + + typename iterator::reference dereference() const + { return &*this->base_reference(); } + }; + + class const_iterator + : public boost::iterator_adaptor< + const_iterator, + typename handle_t::const_iterator, + VALUE const *, + boost::forward_traversal_tag, + VALUE const *> + { + public: + const_iterator (const typename handle_t::const_iterator& it) + : const_iterator::iterator_adaptor_ (it) + { + } + + const_iterator (const iterator& it) + : const_iterator::iterator_adaptor_ (it.base_reference()) + { + } + + private: + friend class boost::iterator_core_access; + + typename const_iterator::reference dereference() const + { return &*this->base_reference(); } + }; + + + ////////////////////////////////////////////////////////////////////// + /// Constructors: + ////////////////////////////////////////////////////////////////////// + + /// default constructor will initialize the pool with m_minRefCount + DataPool(size_type n = 0, + size_type block_size = 0, + SG::Arena* arena = 0); + + /////////////////////////////////////////////////////// + + /// release all elements in the pool. + void reset(); + + /// free all memory in the pool. + void erase(); + + void reserve(unsigned int size); + + /// return capacity of pool OK + unsigned int capacity(); + + /// return size already allocated OK + unsigned int allocated(); + + /// begin iterators over pool + iterator begin(); + const_iterator begin() const; + + /// the end() method will allow looping over only valid elements + /// and not over ALL elements of the pool + iterator end(); + const_iterator end() const; + + /// obtain the next available element in pool by pointer + /// pool is resized if its limit has been reached + /// This may be faster than calling the constructors with + /// the following two methods. But one must be sure to + /// completely reset each object since it has values set in the + /// previous event. + pointer nextElementPtr(); + + /// obtain the next available element in pool by pointer + /// return as void* to minimize misuse, client usage is: + /// MyElement* m = new(pool->mem) MyElement(...); // pool is ptr + /// DANGEROUS --- do we need this??? + void* mem(); + + /// can also say: + /// MyElement* m = new ((*pool)()) MyElement(...); // pool = pointer + /// MyElement* m = new (pool()) MyElement(...); // pool = value + /// DANGEROUS --- do we need this??? + void *operator ()(); + + /// typename of pool + static const std::string& typeName(); + +//-----------------------------------------------------------// + + private: + + handle_t m_handle; + + /// minimum number of elements in pool + static const unsigned int m_minRefCount = 1024; +}; + +#include "AthAllocators/DataPool.icc" + +#endif + + diff --git a/Control/AthAllocators/AthAllocators/DataPool.icc b/Control/AthAllocators/AthAllocators/DataPool.icc new file mode 100755 index 0000000000000000000000000000000000000000..27d1a63de821d6d2cab78a89e890124ce8f9bd4f --- /dev/null +++ b/Control/AthAllocators/AthAllocators/DataPool.icc @@ -0,0 +1,130 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//----------------------------------------------------------- +// .icc file for DataPool +//----------------------------------------------------------- +// includes: +#include <algorithm> +#include "GaudiKernel/System.h" +//----------------------------------------------------------- + +/// default constructor will initialize the pool with m_minRefCount +template <typename VALUE> +DataPool<VALUE>::DataPool(size_type n /*= 0*/, + size_type block_size /*= 0*/, + SG::Arena* arena /*= 0*/) + : m_handle (arena, + typename alloc_t::initParams<VALUE> (std::max (block_size, + static_cast<size_type>(1024u)))) +{ + if (n > 0) + m_handle.reserve (n); +} + +//----------------------------------------------------------- +/// release all elements in the pool. +template <typename VALUE> +void DataPool<VALUE>::reset() +{ + m_handle.reset(); +} + +/// free all memory in the pool. +template <typename VALUE> +void DataPool<VALUE>::erase() +{ + m_handle.erase(); +} +//----------------------------------------------------------- +// reserve space for the pool +// allocated elements will not be deleted. + +template <typename VALUE> +void DataPool<VALUE>::reserve(unsigned int size) +{ + m_handle.reserve (size); +} + + +template <typename VALUE> +unsigned int DataPool<VALUE>::capacity() +{ + return m_handle.stats().elts.total; +} + +template <typename VALUE> +unsigned int DataPool<VALUE>::allocated() +{ + return m_handle.stats().elts.inuse; +} + + +//----------------------------------------------------------- +/// begin iterators over pool +template <typename VALUE> +typename DataPool<VALUE>::iterator DataPool<VALUE>::begin() +{ + return iterator (m_handle.begin()); +} + +template <typename VALUE> +typename DataPool<VALUE>::const_iterator DataPool<VALUE>::begin() const +{ + return const_Iterator (m_handle.begin()); +} + +//----------------------------------------------------------- +/// the end() method will allow looping over only valid elements +/// and not over ALL elements of the pool + +template <typename VALUE> +typename DataPool<VALUE>::iterator DataPool<VALUE>::end() +{ + return iterator (m_handle.end()); +} + +template <typename VALUE> +typename DataPool<VALUE>::const_iterator DataPool<VALUE>::end() const { + return const_iterator (m_handle.end()); +} + +//----------------------------------------------------------- +/// obtain the next available element in pool by pointer +/// return as void* to minimize misuse, client usage is: +/// MyElement* m = new(pool->mem) MyElement(...); // pool is ptr +template <typename VALUE> +void* DataPool<VALUE>::mem() { + pointer p = nextElementPtr(); + return p; +} + +/// can also say: +/// MyElement* m = new ((*pool)()) MyElement(...); // pool = pointer +/// MyElement* m = new (pool()) MyElement(...); // pool = value + +template <typename VALUE> +void* DataPool<VALUE>::operator()() { + return mem(); +} + +//----------------------------------------------------------- +/// typename of pool +template <typename VALUE> +const std::string& DataPool<VALUE>::typeName() { + static std::string name = System::typeinfoName (typeid (VALUE)); + return name; +} + +//----------------------------------------------------------- +/// obtain the next available element in pool by pointer +/// pool is resized if reached its limit +template <typename VALUE> +inline +typename DataPool<VALUE>::pointer DataPool<VALUE>::nextElementPtr() +{ + return m_handle.allocate(); +} + + diff --git a/Control/AthAllocators/AthAllocators/selection.xml b/Control/AthAllocators/AthAllocators/selection.xml new file mode 100755 index 0000000000000000000000000000000000000000..7bde1fab2f800e90aa3cfa827fa221055eff8bcd --- /dev/null +++ b/Control/AthAllocators/AthAllocators/selection.xml @@ -0,0 +1,3 @@ +<lcgdict> + <class name="SG::ArenaHeader"/> +</lcgdict> diff --git a/Control/AthAllocators/cmt/requirements b/Control/AthAllocators/cmt/requirements new file mode 100755 index 0000000000000000000000000000000000000000..ad012cf535deacc677cf2af0d3201e1b87532104 --- /dev/null +++ b/Control/AthAllocators/cmt/requirements @@ -0,0 +1,51 @@ +package AthAllocators + +author scott snyder <snyder@bnl.gov> + +use AtlasPolicy AtlasPolicy-* +use GaudiInterface GaudiInterface-* External +use AtlasBoost AtlasBoost-* External + + +private +use CxxUtils CxxUtils-* Control +end_private + + +apply_pattern installed_library +library AthAllocators *.cxx + + +private +use TestTools TestTools-* AtlasTest + +apply_pattern UnitTest_run unit_test=ArenaAllocatorBase +apply_pattern UnitTest_run unit_test=ArenaBlockAllocatorBase +apply_pattern UnitTest_run unit_test=ArenaBlock +apply_pattern UnitTest_run unit_test=ArenaPoolAllocator +apply_pattern UnitTest_run unit_test=ArenaHeapAllocator +apply_pattern UnitTest_run unit_test=ArenaHandleBase +apply_pattern UnitTest_run unit_test=ArenaHandleBaseAllocT +apply_pattern UnitTest_run unit_test=ArenaHandleBaseT +apply_pattern UnitTest_run unit_test=ArenaHeader +apply_pattern UnitTest_run unit_test=ArenaCachingHandle +apply_pattern UnitTest_run unit_test=ArenaHandle +apply_pattern UnitTest_run unit_test=ArenaAllocatorCreator +apply_pattern UnitTest_run unit_test=ArenaAllocatorRegistry +apply_pattern UnitTest_run unit_test=Arena +apply_pattern UnitTest_run unit_test=ArenaBase +apply_pattern UnitTest_run unit_test=ArenaHeaderGaudiClear \ + extrapatterns="^IncidentSvc +DEBUG Adding" +apply_pattern UnitTest_run unit_test=ArenaPoolSTLAllocator +apply_pattern UnitTest_run unit_test=ArenaHeapSTLAllocator +apply_pattern UnitTest_run unit_test=ArenaSharedHeapSTLAllocator +apply_pattern UnitTest_run unit_test=DataPool \ + extrapatterns="^IncidentSvc +DEBUG Adding|^HistogramPersis.* (INFO|DEBUG)|^JobOptionsSvc +INFO" + +macro_append DOXYGEN_INPUT " ../doc" + + +private +use AtlasReflex AtlasReflex-* External +apply_pattern lcgdict dict=AthAllocators selectionfile=selection.xml headerfiles="../AthAllocators/AthAllocatorsDict.h" + diff --git a/Control/AthAllocators/ispellwords b/Control/AthAllocators/ispellwords new file mode 100755 index 0000000000000000000000000000000000000000..915b514e94953df0af6cff6cb8fc53bb4b361da6 --- /dev/null +++ b/Control/AthAllocators/ispellwords @@ -0,0 +1,732 @@ +personal_ws-1.1 en 698 +assoPointer +persistency +IdentifiableContainer +multi +toContainedElement +GaudiKernel +situ +someone's +refcnt +GENERATEINDEXINGPOLICIES +elementShortRef +originalSize +unary +blk +arg +objectContainer +dataID +bkt +Amram +endif +typeid +fooB +ForwardIndexingPolicy +JetCollection +resized +constr +PackedArray +const's +RandomAccessIterator +CompareAndPrint +del +IProxyDict +deallocate +dep +DVLNoBase +cassert +creat +ASHSTLAllocator +ness +Resizes +autoselect +doinit +setElement +DataVector +theAsso +addHostDObj +gaudi +Dreizin +scott +theAssociatedObjects +cmt +objIndex +assocIndex +dir +ArenaAllocatorRegistry +allocator's +persistifiable +InhVectorIntLink +functor +nclear +crc +elmts +ssnyder +Predwrapper +MessageSvc +DNC +readback +binet +theTrack +DL's +DataPool +Faz +newAssoc +fdl +GenerateIndexingPolicy +ConstDataVector +AtlasReflex +fangled +fdv +LongRef +pCont's +gcc +Ilija +HistogramPersis +absFluff +liint +getAssociations +allo +isDefault +utest +ArenaCachingHandle +depcy +nctor +ELs +CVS +ClassName +destructor +tTrack +elt +hashtable's +PlainPtrElementLink +ELV +DList +DSO +resetWithKeyAndIndex +DataLinkVector +ElemLink +resetWithKey +typedef +pbad +dum +firstAssoc +cxx +theStore +BaseContainer +persistified +dvl +endAssociation +ispellwords +ILink +endHostDObjs +shortRefs +shortrefs +GenParticleIndexing +Elsing +DV's +BinaryPredicate +anOther +FooDequeLink +moveHostDObjs +theObjects +FooDeque +ArenaBase +AtlasSEAL +FNV +NoBase +icc +iCtr +NOGAUDI +swapElement +defaultHeader +objectPointer +src's +StoreGateSvc +hashtable +CopyConstructible +findProxy +BeginEvent +GNUC +toPersistentDL +iff +firstAssObject +bitsize +pCopyDerFluff +findAssociationObjects +DataVectorBase +fdvlcopy +line'll +func +ArenaHandleBaseAllocT +asDataList +CLID's +CLIDs +convertable +fdlcopy +hoc +DHAVE +functionalities +addArena +dataGet +namespaces +StoreGate +IOSTREAMS +oldElem +DataProxy +paolo +eltest +jobOs +AssociationLinks +DataLink +RVersion +pAssoc +hpp +TODO +valgrind +DataProxyStorageBase +srini +getObject +ASSCONT +cerr +proxying +ASSOCONT +DataListBase +AthenaPOOL +Calafiura +MapIndexingPolicy +param +AssociationVector +IProxyDictWithPool +persistify +changeState +canReclear +doxygen +setHashAndIndex +runtime +lcg +args +DataList +DataPtrs +rebinder +theAssociations +inserters +uint +ndtor +DVLCast +theAssociationObjects +assoStore +AssociationVectorCollection +isStreamable +irt +resetTo +AssociationVectorIterator +wronglmint +pairtype +pdata +RemoveDataPtr +theType +printf +setStorableObject +ArenaHeapSTLAllocator +iJet +doRemap +toPersistable +OBJCONT +deallocation +iTracks +getFirstAssociation +SGFolder +AssociationLinkCollection +objectIter +lhs +storeName +ArenaBlockAllocatorBase +rvalue +DerivedFluff +ElemLinkVector +ArenaHeaderGaudiClear +mem +hasher +dobjs +assoIter +Quarrie +hasAssociations +assoContainer +dereferencing +cinquanta +IdentContIndexingPolicy +DVLDataBucket +ElementLinkVector +vers +PDTR +nav +Hong +forwardContainer +cinq +eltSize +AtlasBoost +CINT +typeinfoName +reverseIterators +ArenaPoolAllocator +kwd +ndx +resize +indexingPolicy +tradeoff +ClusterContainer +oldInt +getDataSourcePointer +MacOSX +NavigationToken +asso +PlainPtrStorage +bool +shortref +shortRef +dieci +DataMap +Nir +OBJTYPE +asDataVector +ArenaHeapAllocator +DataLinks +gmake +mLink +castfn +AssociationBaseCollection +clid +deps +LWG +namespace +IOHandler +ArenaAllocatorCreatorInit +pdf +pAssocs +dflt +dfluff +pDL +reflextion +typename +typeName +DVLIterator +iTrack +getDataSource +initParams +LXR +DataBucket +pDV +pJets +refCount +snyder +ASSOBJECT +initGaudi +Srini's +multimap +pTransient +DataBucketTrait +dict +ElemLinkRefs +interoperate +nreserve +lastAssObject +theAssoc +TrackContainer +init +minRefCount +impl +OwnershipPolicy +otherElemLinkRefs +AssociativeIndexingPolicy +DataVector's +oper +IsSTLSequence +findProxyFromKey +newAss +mutators +addTrack +IncidentSvc +makeIndex +sgkey +StrictWeakOrdering +lastTrack +ClassID +classID +calaf +rbegin +containsAssociation +SetIndexingPolicy +ifndef +assocPointer +BaseConstReference +pos +PtrVector +ret +pre +params +BList +theAssocs +ArenaAllocatorBase +Dufus +GaudiClear +ppvInterface +reextracted +lookup +arghh +rhs +pointee +maxRefCount +config +toPersistentState +intL +Sep +hostDObjs +ClassIDSvc +ptr +BVec +intV +pvp +getDataSourcePointerFromGaudi +RNG +pTracks +Metafunction +ArenaHandleBase +shortIterFromLong +tCluster +successFlag +genreflex +DataProxyStorage +DataProxyStorageData +theJet +ElementType +ELVDEBUG +PtrList +AllocatorCreatorBase +asStorable +ArenaSharedHeapSTLAllocator +AthenaKernel +ChangeLog +getLastAssocation +nblock +dvlinfo +DVLInfo +PlainPtrDataLink +src +cout +IDtype +pcopy +jobO +Vec +resizePool +TestTools +dtors +DataPtr +tdefs +enums +ArenaSTLAllocator +findHostDObj +DataList's +toIndexedElement +stl +sizeof +svc +cptr +sss +checkreq +dobj +Vukotic +packageinfo +frexp +str +setData +MyObj +iter +DVLEltBase +AssociationType +clidsvc +CLIDSvc +backNavigation +toPersistent +theCluster +mustClear +storable +IInterface +AssociationObjectIterator +DefaultKey +TSS +inlined +Rajagopalan +makeFunc +savannah +ArenaBlock +multiset +GeneratorObjects +reverseLookup +DefaultState +Obreshkov +pred +malloc +myassert +AthExStoreGateExamples +DVLInfoBase +setOwner +txt +myCluster +FIXME +LIBSTDCXX +ArenaAllocatorCreator +Gemmeren +makeAllocator +JetTrackAssociation +IOVSvc +prev +newElement +beginAssociation +specializable +removeHostDObj +toAccessible +RefVector +EndEvent +PersistentState +tinfo +myassertion +elcnv +ctor +struct +vpvp +dereference +allocvec +getDataRef +ElementParameter +fdvl +AthenaROOTAccess +ControlTest +objectIndex +iHost +emacs +alloc +pElem +riid +accessor +setValid +DataObject +makeCurrent +dpint +symLink +decls +ElementLink +bb +anAss +DataSource +linkOffset +linkoffset +lookups +refVector's +DPSB +isValid +ibadlint +ForwardIterator +assoIndex +firstTrack +NDEBUG +NULLs +templated +endl +br +getDataPtr +venti +eg +dl +mainpage +VirtBases +DefaultIndexingPolicy +utests +reportStr +fd +FooDataVectorLink +CxxUtils +ivint +findInContainer +dv +DVLTYPE +RehashPolicy +ElementProxy +theObject +fn +JetTrackAssociationCollection +SGASSERTERROR +checkForRemap +iliint +toTransient +anotherString +ctors +AssociationLink +FolderItem +IdentContIndex +dereferences +iptrlint +intLF +DataModel +getLastAssociation +IP +indices +multithreaded +sstream +intLL +ld +destructors +Elts +ownPolicy +tryELRemap +li +rvalues +DeclareIndexingPolicy +Koenig +IndexingPolicies +nd +xyz +Austern +delArena +TrackParticleContainer +minSize +toAccessibleState +storagePolicy +NavFourMon +ArenaHandle +ConstDataList +ok +TrackParticle +ChronoStatSvc +ElemLinkRef +ns +findAssociation +Compwrapper +proxied +gccxml +RegisterDVLEltBaseInit +badI +DataPoolTest +os +stdcont +stdCont +initializer +lastAssoc +DVec +ri +BaseInfo +sg +ElemLinks +ElemLink's +targ +DirSearchPath +ELVRef +intVF +headp +BidirectionalIterator +cplusplus +Tavori +SGElvRef +dtor +enum +schaffer +intVL +vd +ForwardContainerConcept +InUse +sz +WG +ArenaPoolSTLAllocator +inline +typedefs +typedef's +Vo +getE +vp +sgname +sgName +rObj +SequenceIndexing +setStorable +trenta +AssociationMap +abc +thinning's +newElem +jobOptions +getAssociationObjects +myarena +lvalues +CategoryOrTraversal +PTAss +accessors +Mytype +raiseInvalidErrorBase +MyElement +rdata +adaptors +toPersistentNomap +DVL's +endcode +aFoo +ftemplate +ExtractKey +ArenaHandleBaseT +defaultDataSource +IdentifiedState +lvalue +ElementHolder +adaptor +preload +ifdef +AssociationBase +theContext +AssociationObject +ArenaHeader +ElementLinks +toIdentified +wrongvint +AssociationObjects +Baz +overridable +const +SGTools +NULLLINK +DefaultKeyState +getDataSourcePointerFunc +libstdc +persistable +SGgetDataSource +allocator +Allocator +allocators +AthAllocators +ATLALLOCATORS +unallocated +doesn +hasn +isn +ve +shouldn +list2 +list1 +instantiations +ArenaSharedHeapSTLAllocators +wasn +inuse +elts +a1 +a2 +test1 +a3 +test2 +test3 +test4 +p1 +p2 +Payload2 +alloc2 +alloc1 +JobOptionsSvc +ain +resizing diff --git a/Control/AthAllocators/share/ArenaAllocatorBase_test.ref b/Control/AthAllocators/share/ArenaAllocatorBase_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaAllocatorCreator_test.ref b/Control/AthAllocators/share/ArenaAllocatorCreator_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaAllocatorRegistry_test.ref b/Control/AthAllocators/share/ArenaAllocatorRegistry_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaBase_test.ref b/Control/AthAllocators/share/ArenaBase_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaBlockAllocatorBase_test.ref b/Control/AthAllocators/share/ArenaBlockAllocatorBase_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaBlock_test.ref b/Control/AthAllocators/share/ArenaBlock_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaCachingHandle_test.ref b/Control/AthAllocators/share/ArenaCachingHandle_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaHandleBaseAllocT_test.ref b/Control/AthAllocators/share/ArenaHandleBaseAllocT_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaHandleBaseT_test.ref b/Control/AthAllocators/share/ArenaHandleBaseT_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaHandleBase_test.ref b/Control/AthAllocators/share/ArenaHandleBase_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaHandle_test.ref b/Control/AthAllocators/share/ArenaHandle_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaHeaderGaudiClear_test.ref b/Control/AthAllocators/share/ArenaHeaderGaudiClear_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaHeader_test.ref b/Control/AthAllocators/share/ArenaHeader_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaHeapAllocator_test.ref b/Control/AthAllocators/share/ArenaHeapAllocator_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaHeapSTLAllocator_test.ref b/Control/AthAllocators/share/ArenaHeapSTLAllocator_test.ref new file mode 100644 index 0000000000000000000000000000000000000000..76983460f7f43b842604ab76921a6ea289362661 --- /dev/null +++ b/Control/AthAllocators/share/ArenaHeapSTLAllocator_test.ref @@ -0,0 +1,3 @@ +test1 +test2 +test3 diff --git a/Control/AthAllocators/share/ArenaPoolAllocator_test.ref b/Control/AthAllocators/share/ArenaPoolAllocator_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/ArenaPoolSTLAllocator_test.ref b/Control/AthAllocators/share/ArenaPoolSTLAllocator_test.ref new file mode 100644 index 0000000000000000000000000000000000000000..fadbf1d8531cefc931988be7e19da5fb524c3e74 --- /dev/null +++ b/Control/AthAllocators/share/ArenaPoolSTLAllocator_test.ref @@ -0,0 +1,4 @@ +test1 +test2 +test3 +test4 diff --git a/Control/AthAllocators/share/ArenaSharedHeapSTLAllocator_test.ref b/Control/AthAllocators/share/ArenaSharedHeapSTLAllocator_test.ref new file mode 100644 index 0000000000000000000000000000000000000000..76983460f7f43b842604ab76921a6ea289362661 --- /dev/null +++ b/Control/AthAllocators/share/ArenaSharedHeapSTLAllocator_test.ref @@ -0,0 +1,3 @@ +test1 +test2 +test3 diff --git a/Control/AthAllocators/share/Arena_test.ref b/Control/AthAllocators/share/Arena_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Control/AthAllocators/share/DataPool_test.ref b/Control/AthAllocators/share/DataPool_test.ref new file mode 100755 index 0000000000000000000000000000000000000000..21159b5cdedac7044fe7546ed698f240706774f5 --- /dev/null +++ b/Control/AthAllocators/share/DataPool_test.ref @@ -0,0 +1,42 @@ + + +Initializing Gaudi ApplicationMgr using job opts ../share/DataPool_test.txt +JobOptionsSvc INFO # =======> /afs/cern.ch/user/s/ssnyder/atlas-work5/Control/DataModel/run/../share/DataPool_test.txt) +JobOptionsSvc INFO # (5,1): ApplicationMgr.DLLs += ["StoreGate"] +JobOptionsSvc INFO # (6,1): MessageSvc.OutputLevel = 2 +JobOptionsSvc INFO # (8,1): ApplicationMgr.ExtSvc += ["IncidentSvc", "ChronoStatSvc", "AuditorSvc"] +JobOptionsSvc INFO Job options successfully read in from ../share/DataPool_test.txt +ApplicationMgr DEBUG Getting my own properties +ApplicationMgr SUCCESS +==================================================================================================================================== + Welcome to ApplicationMgr (GaudiCoreSvc v1r3p3) + running on lxplus446.cern.ch on Mon Apr 22 17:38:11 2013 +==================================================================================================================================== +ApplicationMgr INFO Successfully loaded modules : StoreGate +ApplicationMgr INFO Application Manager Configured successfully +ServiceManager DEBUG Initializing service IncidentSvc +IncidentSvc DEBUG Service base class initialized successfully +ServiceManager DEBUG Initializing service ChronoStatSvc +ChronoStatSvc DEBUG Service base class initialized successfully +ChronoStatSvc INFO Number of skipped events for MemStat-1 +ServiceManager DEBUG Initializing service AuditorSvc +AuditorSvc DEBUG Service base class initialized successfully +ServiceManager DEBUG Initializing service AppMgrRunable +AppMgrRunable DEBUG Service base class initialized successfully +ServiceManager DEBUG Initializing service EventLoopMgr +EventLoopMgr DEBUG Service base class initialized successfully +IncidentSvc DEBUG Adding [AbortEvent] listener '<unknown>' with priority 0 +EventDataSvc DEBUG Service base class initialized successfully +EventPersistenc... DEBUG Service base class initialized successfully +EventLoopMgr WARNING Unable to locate service "EventSelector" +EventLoopMgr WARNING No events will be processed from external input. +HistogramDataSvc DEBUG Service base class initialized successfully +HistogramPersis... DEBUG 'CnvServices':[ 'RootHistSvc' ] +HistogramPersis... DEBUG Service base class initialized successfully +HistogramPersis...WARNING Histograms saving not required. +ApplicationMgr INFO Application Manager Initialized successfully +ApplicationMgr Ready + *** DataPool test in progress: +IncidentSvc DEBUG Adding [BeginEvent] listener '<unknown>' with priority 100 + **** DataPool test successfully completed **** +ChronoStatSvc INFO Time User : Tot= 0 [us] #= 1 diff --git a/Control/AthAllocators/share/DataPool_test.txt b/Control/AthAllocators/share/DataPool_test.txt new file mode 100755 index 0000000000000000000000000000000000000000..16fd9780103d6385ae566a851a76c960c5248f31 --- /dev/null +++ b/Control/AthAllocators/share/DataPool_test.txt @@ -0,0 +1,11 @@ +// common job opts for SG unit tests + +// $Id: DataPool_test.txt,v 1.1 2003-04-02 19:35:10 calaf Exp $ + +ApplicationMgr.DLLs += { "StoreGate" }; +MessageSvc.OutputLevel = 2; + +ApplicationMgr.ExtSvc += {"IncidentSvc", "ChronoStatSvc", "AuditorSvc"}; + +//AuditorSvc.Auditors += {"ChronoAuditor", "MemStatAuditor"}; +//MemStatAuditor.OutputLevel = 4; diff --git a/Control/AthAllocators/src/Arena.cxx b/Control/AthAllocators/src/Arena.cxx new file mode 100755 index 0000000000000000000000000000000000000000..df1c3ec5ff80efbf2a4d4ce30fc4b60e6c738c02 --- /dev/null +++ b/Control/AthAllocators/src/Arena.cxx @@ -0,0 +1,155 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Arena.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/Arena.cxx + * @author scott snyder + * @date May 2007 + * @brief Collection of memory allocators with a common lifetime. + * Out-of-line implementations. + */ + +#include "AthAllocators/Arena.h" +#include "AthAllocators/ArenaAllocatorBase.h" + +namespace SG { + + +/** + * @brief Constructor. + * @param name The name of this @c Arena; to use in reports. + * @param header The header with which this @c Arena is associated. + * If defaulted, the global default @c ArenaHeader will be used. + */ +Arena::Arena (const std::string& name, ArenaHeader* header /*= 0*/) + : m_header (header), + m_name (name) +{ + if (!m_header) + m_header = SG::ArenaHeader::defaultHeader(); + m_header->addArena (this); +} + + +/** + * @brief Destructor. + */ +Arena::~Arena() +{ + m_header->delArena (this); + for (size_t i = 0; i < m_allocs.size(); i++) + delete m_allocs[i]; +} + + +/** + * @brief reset all contained allocators. All elements will be freed. + */ +void Arena::reset() +{ + for (size_t i = 0; i < m_allocs.size(); i++) { + if (m_allocs[i]) + m_allocs[i]->reset(); + } +} + + +/** + * @brief erase all contained allocators. All elements will be freed, + * and the memory returned to the system. + */ +void Arena::erase() +{ + for (size_t i = 0; i < m_allocs.size(); i++) { + if (m_allocs[i]) + m_allocs[i]->erase(); + } +} + + +/** + * @brief Generate a report of the memory in use by this @c Arena. + * @param os The stream to which to write the report. + */ +void Arena::report (std::ostream& os) const +{ + bool first = true; + for (size_t i = 0; i < m_allocs.size(); i++) { + if (m_allocs[i]) { + if (first) { + ArenaAllocatorBase::Stats::header (os); + os << std::endl; + first = false; + } + m_allocs[i]->report (os); + } + } +} + + +/** + * @brief Return statistics summed over all allocators in this @c Arena. + */ +const ArenaAllocatorBase::Stats& Arena::stats () const +{ + m_stats = ArenaAllocatorBase::Stats(); + for (size_t i = 0; i < m_allocs.size(); i++) { + if (m_allocs[i]) { + m_stats += m_allocs[i]->stats(); + } + } + return m_stats; +} + + +/** + * @brief Return the @c ArenaHeader with which this @c Arena is associated. + */ +ArenaHeader* Arena::header() const +{ + return m_header; +} + + +/** + * @brief Return this @c Arena's name. + */ +const std::string& Arena::name() const +{ + return m_name; +} + + +/** + * @brief Make this @c Arena the current one for its @c ArenaHeader. + * @returns The previously current allocator vector. + */ +ArenaHeader::ArenaAllocVec_t* Arena::makeCurrent() +{ + return m_header->setAllocVec (&m_allocs); +} + + +/** + * @brief Constructor. Make @c a current. + * @param a The @c Arena to make current. + */ +Arena::Push::Push (Arena& a) + : m_header (a.header()), + m_allocs (a.makeCurrent()) +{ +} + + +/** + * @brief Destructor. Undoes the effect of the constructor. + */ +Arena::Push::~Push() +{ + m_header->setAllocVec (m_allocs); +} + + +} // namespace SG diff --git a/Control/AthAllocators/src/ArenaAllocatorBase.cxx b/Control/AthAllocators/src/ArenaAllocatorBase.cxx new file mode 100755 index 0000000000000000000000000000000000000000..466807f98bfb97170071664d8c18f2f810a7e071 --- /dev/null +++ b/Control/AthAllocators/src/ArenaAllocatorBase.cxx @@ -0,0 +1,136 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorBase.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaAllocatorBase.cxx + * @author scott snyder + * @date May 2007 + * @brief Common base class for arena allocator classes. + * Out-of-line implementations. + */ + +#include "AthAllocators/ArenaAllocatorBase.h" +#include <ostream> +#include <iomanip> + + +namespace SG { + + +/** + * @brief Constructor for a single statistic. + */ +ArenaAllocatorBase::Stats::Stat::Stat() + : inuse (0), + free (0), + total (0) +{ +} + + +/** + * @brief Zero a statistic. + */ +void ArenaAllocatorBase::Stats::Stat::clear() +{ + inuse = free = total = 0; +} + + +/** + * @brief Accumulate a statistic. + * @param other The statistic to accumulate into this one. + */ +ArenaAllocatorBase::Stats::Stat& +ArenaAllocatorBase::Stats::Stat::operator+= (const Stat& other) +{ + inuse += other.inuse; + free += other.free; + total += other.total; + return *this; +} + + +/* (hide from doxygen) + * @brief Format a statistic structure. + * @param os The stream to which to write. + * @param stat The statistic structure to write. + */ +std::ostream& operator<< (std::ostream& os, + const ArenaAllocatorBase::Stats::Stat& stat) +{ + os << std::setw(7) << stat.inuse << "/" + << std::setw(7) << stat.free << "/" + << std::setw(7) << stat.total; + return os; +} + + +//=========================================================================== + + +/** + * @brief Zero a complete statistics block. + */ +void ArenaAllocatorBase::Stats::clear() +{ + elts.clear(); + bytes.clear(); + blocks.clear(); +} + + +/** + * @brief Accumulate a complete statistics block. + * @param other The statistics block to accumulate into this one. + */ +ArenaAllocatorBase::Stats& +ArenaAllocatorBase::Stats::operator+= (const Stats& other) +{ + elts += other.elts; + bytes += other.bytes; + blocks += other.blocks; + return *this; +} + + +/* (hide from doxygen) + * @brief Format a complete statistics structure. + * @param os The stream to which to write. + * @param stats The statistics structure to write. + */ +std::ostream& operator<< (std::ostream& os, + const ArenaAllocatorBase::Stats& stats) +{ + os << stats.elts << " " << stats.bytes << " " << stats.blocks; + return os; +} + + +/** + * @brief Write a header for the statistics report. + * @param os The stream to which to write. + */ +void ArenaAllocatorBase::Stats::header (std::ostream& os) +{ + os << "Elts InUse/Free/Total" + << " Bytes InUse/Free/Total Blocks InUse/Free/Total"; +} + + +//=========================================================================== + + +/** + * @brief Generate a report on the memory usage of this allocator. + * @param os Stream to which the report should be written. + */ +void ArenaAllocatorBase::report (std::ostream& os) const +{ + os << " " << stats() << " " << name() << std::endl; +} + + +} // namespace SG diff --git a/Control/AthAllocators/src/ArenaAllocatorRegistry.cxx b/Control/AthAllocators/src/ArenaAllocatorRegistry.cxx new file mode 100755 index 0000000000000000000000000000000000000000..48eaeb5c73b3d8aea4df1428ae59488821e67e1e --- /dev/null +++ b/Control/AthAllocators/src/ArenaAllocatorRegistry.cxx @@ -0,0 +1,203 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +/** + * @file AthAllocators/src/ArenaAllocatorRegistry.cxx + * @author scott snyder + * @date May 2007 + * @brief Registry of allocator factories. + * Out-of-line implementation. + */ + +// xxx FIXME: not thread-safe. + +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include "AthAllocators/ArenaAllocatorCreator.h" +#include <vector> +#include <map> +#include <cassert> + + +namespace SG { + + +/** + * @brief ArenaAllocatorRegistry implementation class. + */ +class ArenaAllocatorRegistryImpl +{ +public: + /// Destructor. + ~ArenaAllocatorRegistryImpl(); + + + /** + * @brief Register a new allocator type. + * @param name The name of the allocator type. Must not already exist. + * @param creator The factory object to create instances of this type. + * The registry takes ownership of this pointer. + * @return The new integer index for this allocator type. + */ + size_t registerCreator (const std::string& name, + ArenaAllocatorCreator* creator); + + + /** + * @brief Look up the index for an allocator type name. + * @param name The name of the allocator type to find. + * @return The index corresponding to the type, or @c std::string::npos + * if it hasn't yet been registered. + */ + size_t lookup (const std::string& name); + + + /** + * @brief Create a new instance of an allocator. + * @param i The index of the allocator to create. + * @return A newly-allocated allocator instance. + */ + ArenaAllocatorBase* create (size_t i); + + +private: + /// Map from names to indices. + typedef std::map<std::string, size_t> map_t; + map_t m_map; + + /// Vector of factory instances. + std::vector<ArenaAllocatorCreator*> m_creators; +}; + + +/** + * @brief Destructor. + */ +ArenaAllocatorRegistryImpl::~ArenaAllocatorRegistryImpl() +{ + // Free the saved factory instances. + for (size_t i = 0; i < m_creators.size(); i++) + delete m_creators[i]; +} + + +/** + * @brief Register a new allocator type. + * @param name The name of the allocator type. Must not already exist. + * @param creator The factory object to create instances of this type. + * The registry takes ownership of this pointer. + * @return The new integer index for this allocator type. + */ +size_t +ArenaAllocatorRegistryImpl::registerCreator (const std::string& name, + ArenaAllocatorCreator* creator) +{ + // The name must not already exist. + assert (m_map.count (name) == 0); + + // The new index. + size_t i = m_creators.size(); + + // Remember the index and store the creator. + m_map[name] = i; + m_creators.push_back (creator); + return i; +} + + +/** + * @brief Look up the index for an allocator type name. + * @param name The name of the allocator type to find. + * @return The index corresponding to the type, or @c std::string::npos + * if it hasn't yet been registered. + */ +size_t ArenaAllocatorRegistryImpl::lookup (const std::string& name) +{ + map_t::iterator it = m_map.find (name); + if (it == m_map.end()) + return std::string::npos; + return it->second; +} + + +/** + * @brief Create a new instance of an allocator. + * @param i The index of the allocator to create. + * @return A newly-allocated allocator instance. + */ +ArenaAllocatorBase* ArenaAllocatorRegistryImpl::create (size_t i) +{ + assert (i < m_creators.size()); + return m_creators[i]->create(); +} + + +//========================================================================== + +/** + * @brief Register a new allocator type. + * @param name The name of the allocator type. Must not already exist. + * @param creator The factory object to create instances of this type. + * The registry takes ownership of this pointer. + * @return The new integer index for this allocator type. + */ +size_t +ArenaAllocatorRegistry::registerCreator (const std::string& name, + ArenaAllocatorCreator* creator) +{ + return m_impl->registerCreator (name, creator); +} + + +/** + * @brief Look up the index for an allocator type name. + * @param name The name of the allocator type to find. + * @return The index corresponding to the type, or @c std::string::npos + * if it hasn't yet been registered. + */ +size_t ArenaAllocatorRegistry::lookup (const std::string& name) +{ + return m_impl->lookup (name); +} + + +/** + * @brief Create a new instance of an allocator. + * @param i The index of the allocator to create. + * @return A newly-allocated allocator instance. + */ +ArenaAllocatorBase* ArenaAllocatorRegistry::create (size_t i) +{ + return m_impl->create (i); +} + + +/** + * @brief Return a pointer to the global @c ArenaAllocatorRegistry instance. + */ +ArenaAllocatorRegistry* ArenaAllocatorRegistry::instance() +{ + static ArenaAllocatorRegistry tmp; + return &tmp; +} + + +/** + * @brief Constructor. + */ +ArenaAllocatorRegistry::ArenaAllocatorRegistry() + : m_impl (new ArenaAllocatorRegistryImpl) +{ +} + + +/** + * @brief Destructor. + */ +ArenaAllocatorRegistry::~ArenaAllocatorRegistry() +{ + delete m_impl; +} + + +} // namespace SG diff --git a/Control/AthAllocators/src/ArenaBlock.cxx b/Control/AthAllocators/src/ArenaBlock.cxx new file mode 100755 index 0000000000000000000000000000000000000000..82c675b1b1588a3a24fabf34b49b54c5697d731e --- /dev/null +++ b/Control/AthAllocators/src/ArenaBlock.cxx @@ -0,0 +1,147 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlock.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaBlock.cxx + * @author scott snyder + * @date May 2007 + * @brief These are large blocks of memory that get allocated and + * divided up into smaller, uniform elements. + * Out-of-line implementation. + */ + + +#include "AthAllocators/ArenaBlock.h" +#include <cstdlib> + + +namespace SG { + + +/// Global number of blocks in use. +size_t ArenaBlock::s_nactive = 0; + + +/** + * @brief Create a new block. + * @param n The number of elements in the new block. + * @param elt_size The size in bytes of each element. + * @param ctor If non-null, call this function on each element + * in the new block. + */ +ArenaBlock* +ArenaBlock::newBlock (size_t n, size_t elt_size, func_t* ctor) +{ + size_t tot_size = n*elt_size + ArenaBlockBodyOffset; + ArenaBlock* p = reinterpret_cast<ArenaBlock*> (std::malloc (tot_size)); + ++s_nactive; + p->m_link = 0; + p->m_elt_size = elt_size; + p->m_size = n; + if (ctor) { + for (size_t i = 0; i < n; i++) + ctor (p->index (i, elt_size)); + } + return p; +} + + +/** + * @brief Destroy a block. + * @param p The block to destroy. + * @param dtor If non-null, call this function on each element in the block. + */ +void ArenaBlock::destroy (ArenaBlock* p, func_t* dtor) +{ + if (dtor) { + size_t elt_size = p->eltSize(); + size_t n = p->size(); + for (size_t i = 0; i < n; i++) + dtor (p->index (i, elt_size)); + } + --s_nactive; + std::free (p); +} + + +/** + * @brief Destroy all blocks in a list. + * @param p The first block to destroy. + * @param dtor If non-null, call this function on each element the blocks. + * + * Will destroy all blocks in the linked list headed by @c p. + */ +void +ArenaBlock::destroyList (ArenaBlock* p, func_t* dtor) +{ + while (p) { + ArenaBlock* next = p->link(); + destroy (p, dtor); + p = next; + } +} + + +/** + * @brief Concatenate two lists of blocks. + * @param headp Pointer to pointer to the head of the list. + * @param tail Pointer to list to append to the end. + * + * The list @c tail is appended to the end of the list @c *headp. + * (@c headp is a pointer-to-pointer to be able to handle the case + * of an empty list.) + */ +void ArenaBlock::appendList (ArenaBlock** link, ArenaBlock* tail) +{ + while (*link) + link = &(*link)->link(); + *link = tail; +} + + +/** + * @brief Call a function on elements in a list of blocks. + * @param p Pointer to the head of the list. + * @param func Function to apply. + * @param Number of elements in the first block on which + * to call the function. + * + * This will loop through the elements in all blocks on the list, + * calling @c func. In the first block, we apply the function + * only to the first @c n elements. In subsequent blocks, the + * function is applied to all elements. + */ +void ArenaBlock::applyList (ArenaBlock* p, + func_t* func, + size_t n) +{ + if (!p) return; + size_t elt_size = p->eltSize(); + if (n > p->size()) + n = p->size(); + while (1) { + for (size_t i = 0; i < n; i++) + func (p->index (i, elt_size)); + p = p->link(); + if (!p) break; + n = p->size(); + } +} + + +/** + * @brief Return the per-block memory overhead, in bytes. + * + * This tries to include malloc overhead as well, but that may just + * be an estimate. Don't rely on this to be exact. + */ +size_t ArenaBlock::overhead() +{ + // The extra size_t is a guesstimate of malloc overhead. + return ArenaBlockBodyOffset + sizeof (size_t); +} + + +} // namespace SG diff --git a/Control/AthAllocators/src/ArenaBlockAllocatorBase.cxx b/Control/AthAllocators/src/ArenaBlockAllocatorBase.cxx new file mode 100755 index 0000000000000000000000000000000000000000..de10b43833ce76742a60861dd4eb20f411e4e481 --- /dev/null +++ b/Control/AthAllocators/src/ArenaBlockAllocatorBase.cxx @@ -0,0 +1,185 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlockAllocatorBase.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaBlockAllocatorBase.cxx + * @author scott snyder + * @date May 2007 + * @brief Common functionality for block-oriented allocators. + * Out-of-line implementations. + */ + +#include "AthAllocators/ArenaBlockAllocatorBase.h" +#include "AthAllocators/ArenaBlock.h" + + +namespace SG { + + +/** + * @brief Constructor. + * @param params The parameters structure for this allocator. + * See @c ArenaAllocatorBase.h for the contents. + */ +ArenaBlockAllocatorBase::ArenaBlockAllocatorBase (const Params& params) + : m_params (params), + m_blocks (0), + m_freeblocks (0) +{ +} + + +/** + * @brief Set the total number of elements cached by the allocator. + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +void ArenaBlockAllocatorBase::reserve (size_t size) +{ + if (size > m_stats.elts.total) { + // Growing the pool. + // Make a new block of the required size (but not less than nblock). + size_t sz = size - m_stats.elts.total; + if (sz < m_params.nblock) + sz = m_params.nblock; + ArenaBlock* newblock = ArenaBlock::newBlock (sz, m_params.eltSize, + m_params.constructor); + + // Update statistics (others are derived in stats()). + ++m_stats.blocks.free; + ++m_stats.blocks.total; + m_stats.elts.total += sz; + + // Add to the free list. + newblock->link() = m_freeblocks; + m_freeblocks = newblock; + } + else { + // Shrinking the pool. + // Loop while we can get rid of the first free block. + while (size < m_stats.elts.total && + m_freeblocks && + m_freeblocks->size() <= (m_stats.elts.total - size)) + { + // Remove it from the free list. + ArenaBlock* p = m_freeblocks; + m_freeblocks = m_freeblocks->link(); + + // Update statistics (others are derived in stats()). + m_stats.elts.total -= p->size(); + --m_stats.blocks.free; + --m_stats.blocks.total; + + // Free the block. + ArenaBlock::destroy (p, m_params.destructor); + } + } +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +void ArenaBlockAllocatorBase::erase() +{ + // Do we need to run clear() on the allocated elements? + // If so, do so via reset(). + if (m_params.mustClear && m_params.clear) + reset(); + + // Kill the block lists (both free and in use). + ArenaBlock::destroyList (m_blocks, m_params.destructor); + ArenaBlock::destroyList (m_freeblocks, m_params.destructor); + m_blocks = m_freeblocks = 0; + + // Reset statistics. + m_stats.clear(); +} + + +/** + * @brief Return the statistics block for this allocator. + */ +const ArenaAllocatorBase::Stats& ArenaBlockAllocatorBase::stats() const +{ + // Calculate derived statistics. + m_stats.elts.free = m_stats.elts.total - m_stats.elts.inuse; + m_stats.bytes.inuse = m_stats.elts.inuse * m_params.eltSize + + m_stats.blocks.inuse * ArenaBlock::overhead(); + m_stats.bytes.total = m_stats.elts.total * m_params.eltSize + + m_stats.blocks.total * ArenaBlock::overhead(); + m_stats.bytes.free = m_stats.elts.free * m_params.eltSize + + m_stats.blocks.free * ArenaBlock::overhead(); + return m_stats; +} + + +/** + * @brief Return the name of this allocator. + */ +const std::string& ArenaBlockAllocatorBase::name() const +{ + return m_params.name; +} + + +/** + * @brief Return this allocator's parameters. + */ +const ArenaAllocatorBase::Params& +ArenaBlockAllocatorBase::params() const +{ + return m_params; +} + + +/** + * @brief Return an empty block, either newly-allocated or from the + * free list. Update statistics appropriately. + */ +ArenaBlock* ArenaBlockAllocatorBase::getBlock() +{ + ArenaBlock* newblock = m_freeblocks; + if (newblock) { + // There's something on the free list. Remove it and update statistics. + m_freeblocks = newblock->link(); + --m_stats.blocks.free; + } + else { + // Otherwise, we need to make a new block. + newblock = ArenaBlock::newBlock (m_params.nblock, m_params.eltSize, + m_params.constructor); + m_stats.elts.total += m_params.nblock; + ++m_stats.blocks.total; + } + // Finish updating statistics. + // (Remaining ones are computed in stats().) + ++m_stats.blocks.inuse; + + // Link it into the in-use list and return. + newblock->link() = m_blocks; + m_blocks = newblock; + return newblock; +} + + +} // namespace SG diff --git a/Control/AthAllocators/src/ArenaHandleBase.cxx b/Control/AthAllocators/src/ArenaHandleBase.cxx new file mode 100755 index 0000000000000000000000000000000000000000..c7728e157c70b2411fbb35ec39522b4545f95780 --- /dev/null +++ b/Control/AthAllocators/src/ArenaHandleBase.cxx @@ -0,0 +1,103 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBase.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaHandleBase.cxx + * @author scott snyder + * @date May 2007 + * @brief Base class for all @c Handle classes, containing parts that + * do not depend on the referenced type. + */ + + +#include "AthAllocators/ArenaHandleBase.h" +#include "AthAllocators/ArenaAllocatorBase.h" + + +namespace SG { + + +/** + * @brief Constructor. + * @param header The group of Arenas which this Handle may reference. + * May be null to select the global default. + * @param index The index of this Handle's Allocator type. + */ +ArenaHandleBase::ArenaHandleBase (ArenaHeader* header, size_t index) + : m_header (header), + m_index (index) +{ + // If the supplied header is null, use the global default. + if (!m_header) + m_header = ArenaHeader::defaultHeader(); +} + + +/** + * @brief Free all allocated elements (of this type in the current Arena). + * + * All elements allocated in the current Arena by our associated + * Allocator are returned to the + * free state. @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +void ArenaHandleBase::reset() +{ + return baseAllocator()->reset(); +} + + +/** + * @brief Free all allocated elements and release memory back to the system + * (of this type in the current Arena). + * + * All elements allocated in the current Arena by our associated + * Allocator are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +void ArenaHandleBase::erase() +{ + return baseAllocator()->erase(); +} + + +/** + * @brief Set the total number of elements cached by the allocator + * (in the current Arena). + * @param size The desired pool size. + * + * This allows changing the number of elements that are currently free + * but cached. Any allocated elements are not affected by this call. + * + * If @c size is greater than the total number of elements currently + * cached, then more will be allocated. This will preferably done + * with a single block, but that is not guaranteed; in addition, the + * allocator may allocate more elements than is requested. + * + * If @c size is smaller than the total number of elements currently + * cached, as many blocks as possible will be released back to the system. + * It may not be possible to release the number of elements requested; + * this should be implemented on a best-effort basis. + */ +void ArenaHandleBase::reserve (size_t size) +{ + return baseAllocator()->reserve (size); +} + + +/** + * @brief Return the statistics block for this allocator, + * for the current Arena. + */ +const ArenaAllocatorBase::Stats& ArenaHandleBase::stats() const +{ + return baseAllocator()->stats(); +} + + +} // namespace SG diff --git a/Control/AthAllocators/src/ArenaHeader.cxx b/Control/AthAllocators/src/ArenaHeader.cxx new file mode 100755 index 0000000000000000000000000000000000000000..39452d850e7978a8b88451c843e4ee813d0e7aca --- /dev/null +++ b/Control/AthAllocators/src/ArenaHeader.cxx @@ -0,0 +1,210 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeader.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src//ArenaHeader.cxx + * @author scott snyder + * @date May 2007 + * @brief Proxy for a group of Arenas. + * Out-of-line implementations. + */ + +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaHeaderGaudiClear.h" +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include "AthAllocators/ArenaBase.h" +#include <algorithm> +#include <ostream> +#include <sstream> +#include <cassert> + + +namespace SG { + + +/** + * @brief Constructor. + */ +ArenaHeader::ArenaHeader() + : m_allocvec (0), + m_ownedAllocvec (0) +{ +} + + +/** + * @brief Destructor. + * + * This will clean up any memory allocated in the default Arena. + */ +ArenaHeader::~ArenaHeader() +{ + if (m_ownedAllocvec) { + for (size_t i = 0 ; i < m_ownedAllocvec->size(); i++) + delete (*m_ownedAllocvec)[i]; + delete m_ownedAllocvec; + } +} + + +/** + * @brief Set the current Arena. + * @param allocvec New vector of Allocator instances. + * @return The previous vector. + * + * This sets the notion of the current Arena. + */ +ArenaHeader::ArenaAllocVec_t* +ArenaHeader::setAllocVec (ArenaAllocVec_t* allocvec) +{ + ArenaAllocVec_t* ret = m_allocvec; + m_allocvec = allocvec; + return ret; +} + + +/** + * @brief Add a new Arena to the group. + * @param a The Arena to add. + */ +void ArenaHeader::addArena (ArenaBase* a) +{ + m_arenas.push_back (a); +} + + +/** + * @brief Remove an Arena from the group. + * @param a The Arena to remove. + * + * Will trip an assertion if the Arena is not in the group. + */ +void ArenaHeader::delArena (ArenaBase* a) +{ + std::vector<ArenaBase*>::iterator it = + std::find (m_arenas.begin(), m_arenas.end(), a); + assert (it != m_arenas.end()); + m_arenas.erase (it); +} + + +/** + * @brief Generate a report of all Arenas in the group. + * @param os Stream to which to send a report. + */ +void ArenaHeader::report (std::ostream& os) const +{ + // All Allocators in the group. + for (size_t i = 0; i < m_arenas.size(); i++) { + os << "=== " << m_arenas[i]->name() << " ===" << std::endl; + m_arenas[i]->report (os); + } + + // The default Arena. + if (m_ownedAllocvec) { + os << "=== default ===" << std::endl; + ArenaAllocatorBase::Stats::header (os); + os << std::endl; + for (size_t i = 0; i < m_ownedAllocvec->size(); i++) { + if ((*m_ownedAllocvec)[i]) + (*m_ownedAllocvec)[i]->report (os); + } + } +} + + +/** + * @brief Generate a report of all Arenas in the group, and return + * the result as a string. + * + * We have this in addition to @c report() in order to make it easier + * to call from scripting languages. + */ +std::string ArenaHeader::reportStr() const +{ + std::ostringstream s; + report (s); + return s.str(); +} + + +/** + * @brief Call @c reset on all Allocators in the current Arena. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +void ArenaHeader::reset() +{ + if (m_allocvec) { + for (size_t i = 0; i < m_allocvec->size(); i++) { + if ((*m_allocvec)[i]) + (*m_allocvec)[i]->reset(); + } + } +} + + +/** + * @brief Return the global default Header instance. + */ +ArenaHeader* ArenaHeader::defaultHeader() +{ + // FIXME xxx should be thread-local! + // FIXME xxx don't depend on gaudi here! + static ArenaHeaderGaudiClear head; + head.addRef(); + head.initialize(); + return &head; +} + + +/** + * @brief Make a new Allocator for index i. + * @param i The index of the Allocator. + * + * The Allocator vector was empty for index @c i. Make an appropriate + * new Allocator, store it in the vector, and return it. Will trip + * an assertion if the index is not valid. + */ +ArenaAllocatorBase* ArenaHeader::makeAllocator (size_t i) +{ + // If we don't have an Arena set, use the default one. + if (!m_allocvec) { + + // Create the default Arena if needed. + if (!m_ownedAllocvec) + m_ownedAllocvec = new ArenaAllocVec_t; + + // Install the default Arena. + m_allocvec = m_ownedAllocvec; + + // See if the index is now in the default Arena. + if (i < m_allocvec->size()) { + ArenaAllocatorBase* allocbase = (*m_allocvec)[i]; + if (allocbase) return allocbase; + } + } + + // We have to create a new Allocator. + // Make sure there's room in the vector. + if (m_allocvec->size() <= i) + m_allocvec->resize (i+1); + + // Create the Allocator, using the Registry. + ArenaAllocatorBase* alloc = + ArenaAllocatorRegistry::instance()->create (i); + + // Install it in the vector. + (*m_allocvec)[i] = alloc; + + return alloc; +} + + +} // namespace SG diff --git a/Control/AthAllocators/src/ArenaHeaderGaudiClear.cxx b/Control/AthAllocators/src/ArenaHeaderGaudiClear.cxx new file mode 100755 index 0000000000000000000000000000000000000000..0756156bccb7349df54562b2e9430def25ed7a0c --- /dev/null +++ b/Control/AthAllocators/src/ArenaHeaderGaudiClear.cxx @@ -0,0 +1,131 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeaderGaudiClear.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaHeaderGaudiClear.cxx + * @author scott snyder + * @date May 2007 + * @brief An @c ArenaHeader that's cleared on every Gaudi event. + * Out-of-line implementations. + */ + + +#include "AthAllocators/ArenaHeaderGaudiClear.h" +#include "GaudiKernel/Bootstrap.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/IIncidentSvc.h" +#include <stdexcept> +#include <exception> + + +namespace SG { + + +/// True if @c disable has been called. +bool ArenaHeaderGaudiClear::m_disabled = false; + + +/** + * @brief Constructor. + */ +ArenaHeaderGaudiClear::ArenaHeaderGaudiClear() + : m_initialized (false), + m_instanceCount (0) +{ +} + + +/** + * @brief Register with Gaudi. + */ +void ArenaHeaderGaudiClear::initialize() +{ + // Don't do anything if we're disabled or have already been called. + if (m_initialized || m_disabled) + return; + + // Find the Gaudi incident service. + IIncidentSvc* incsvc; + if (!(Gaudi::svcLocator()->service("IncidentSvc", incsvc)).isSuccess()) + { + throw std::runtime_error("ArenaHeaderGaudiClear: " + "Could not locate Incident Service"); + } + + // Register with the service. + const int PRIORITY = 100; + incsvc->addListener(this, "BeginEvent", PRIORITY); + + m_initialized = true; +} + + +/** + * @brief Handle a Gaudi incident. + * @param inc The incident to handle. + */ +void ArenaHeaderGaudiClear::handle(const Incident& inc) +{ + // Reset on begin-event. + if (inc.type() == "BeginEvent") + reset(); +} + + +/** + * @brief Increase the reference count. (Required by @c IInterface.) + */ +unsigned long ArenaHeaderGaudiClear::addRef() +{ + m_instanceCount++; + return m_instanceCount; +} + + +/** + * @brief Decrease the reference count. (Required by @c IInterface.) + */ +unsigned long ArenaHeaderGaudiClear::release() +{ + m_instanceCount--; + unsigned long count = m_instanceCount; + if (count <= 0) delete this; + return count; +} + + +/** + * @brief Return the Gaudi interface for this object. + * (Required by @c IInterface.) + */ +StatusCode +ArenaHeaderGaudiClear::queryInterface(const InterfaceID& riid, + void** ppvInterface) +{ + if (interfaceID().versionMatch(riid)) { + *ppvInterface = this; + } + else { + return StatusCode::FAILURE; + } + addRef(); + return StatusCode::SUCCESS; +} + + +/** + * @brief Disable the Gaudi functionality. + * + * If this is called before @c initialize(), we will not attempt + * to register ourselves with Gaudi. This can be used for running + * outside of the framework. + */ +void ArenaHeaderGaudiClear::disable() +{ + m_disabled = true; +} + + +} // namespace SG diff --git a/Control/AthAllocators/src/ArenaHeapAllocator.cxx b/Control/AthAllocators/src/ArenaHeapAllocator.cxx new file mode 100755 index 0000000000000000000000000000000000000000..9d9e546dfd44b21b497857438c531cfe99da2e47 --- /dev/null +++ b/Control/AthAllocators/src/ArenaHeapAllocator.cxx @@ -0,0 +1,162 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapAllocator.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaHeapAllocator.cxx + * @author scott snyder + * @date May 2007 + * @brief Heap-based allocator. + * Out-of-line implementations. + */ + +#include "AthAllocators/ArenaHeapAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <vector> +#include <algorithm> +#include <cassert> + + +namespace SG { + + +/** + * @brief Constructor. + * @param params The parameters structure for this allocator. + * See @c ArenaAllocatorBase.h for the contents. + */ +ArenaHeapAllocator::ArenaHeapAllocator (const Params& params) + : ArenaBlockAllocatorBase (params), + m_freeptr (0) +{ + // Consistency check. + assert (params.linkOffset + sizeof (pointer) <= params.eltSize); +} + + +/** + * @brief Destructor. This will free all the Allocator's storage. + */ +ArenaHeapAllocator::~ArenaHeapAllocator() +{ + erase(); +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +void ArenaHeapAllocator::reset() +{ + if (!m_blocks) return; + if (m_params.clear) { + if (m_params.canReclear || m_freeptr == 0) { + // Just call clear() on all blocks --- allocated or not. + ArenaBlock::applyList (m_blocks, m_params.clear, m_blocks->size()); + } + else { + // We can only call clear() on allocated blocks. + slowClear(); + } + } + + // Move all blocks back to the free list. + ArenaBlock::appendList (&m_freeblocks, m_blocks); + + // Reset state. + m_blocks = 0; + m_freeptr = 0; + m_stats.elts.inuse = 0; + m_stats.blocks.free += m_stats.blocks.inuse; + m_stats.blocks.inuse = 0; +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +void ArenaHeapAllocator::erase() +{ + ArenaBlockAllocatorBase::erase(); + m_freeptr = 0; +} + + +/** + * @brief Add more free elements to the pool, and allocate a new element. + */ +ArenaHeapAllocator::pointer ArenaHeapAllocator::refill() +{ + // Get a new block. + ArenaBlock* newblock = getBlock(); + + // Set up the links for the new free elements. + pointer lastelt = 0; + size_t sz = newblock->size(); + size_t elt_size = newblock->eltSize(); + for (size_t i=1; i < sz; i++) { + pointer elt = newblock->index (i, elt_size); + link(elt) = lastelt; + lastelt = elt; + } + // Set the free pointer to the next-to-last one. + m_freeptr = newblock->index (sz-1, elt_size); + + // And return the last one. + return newblock->index (0, elt_size); +} + + +/** + * @brief Call @c clear() for all allocated elements. + */ +void ArenaHeapAllocator::slowClear() +{ + // Make a list of all free elements, in sorted order. + std::vector<pointer> free_ptrs; + free_ptrs.reserve (m_stats.elts.total - m_stats.elts.inuse); + for (pointer p = m_freeptr; p; p = link(p)) + free_ptrs.push_back (p); + std::sort (free_ptrs.begin(), free_ptrs.end()); + + // Make a list of all used blocks, in sorted order. + std::vector<ArenaBlock*> blocks; + for (ArenaBlock* p = m_blocks; p; p = p->link()) + blocks.push_back (p); + std::sort (blocks.begin(), blocks.end()); + + // Walk through both of these lists. + // For each block, walk through its elements, and call @c clear + // for those not on the free list. + std::vector<pointer>::iterator pi = free_ptrs.begin(); + std::vector<pointer>::iterator pi_end = free_ptrs.end(); + std::vector<ArenaBlock*>::iterator bi = blocks.begin(); + std::vector<ArenaBlock*>::iterator bi_end = blocks.end(); + func_t* clear = m_params.clear; + for (; bi != bi_end; bi++) { + ArenaBlock& bl = **bi; + size_t sz = bl.size(); + size_t elt_size = bl.eltSize(); + for (size_t i = 0; i < sz; i++) { + pointer ptr = bl.index (i, elt_size); + if (pi != pi_end && ptr == *pi) + ++pi; + else + clear (ptr); + } + } +} + + +} // namespace SG diff --git a/Control/AthAllocators/src/ArenaPoolAllocator.cxx b/Control/AthAllocators/src/ArenaPoolAllocator.cxx new file mode 100755 index 0000000000000000000000000000000000000000..104520c970a264a20cd86c23d6237790fcd289e5 --- /dev/null +++ b/Control/AthAllocators/src/ArenaPoolAllocator.cxx @@ -0,0 +1,292 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolAllocator.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/src/ArenaPoolAllocator.cxx + * @author scott snyder + * @date May 2007 + * @brief Pool-based allocator. + * Out-of-line implementations. + */ + +#include "AthAllocators/ArenaPoolAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <cassert> + + +namespace SG { + + +/** + * @brief Helper: common code for advancing an iterator. + * @param base Element pointer. + * @param block Block pointer. + */ +inline +ArenaPoolAllocator::pointer +ArenaPoolAllocator_iterator_increment (ArenaPoolAllocator::pointer base, + ArenaBlock* & block) +{ + // If we haven't yet reached the start of this block, move the iterator + // back one. + if (base > block->index(0,0)) + return base - block->eltSize(); + else { + // Move to the previous block. + block = block->link(); + if (block) + return block->index (block->size()-1, block->eltSize()); + else + return 0; + } +} + + +/** + * @brief Move the iterator forward. + */ +void ArenaPoolAllocator::iterator::increment() +{ + this->base_reference() = + ArenaPoolAllocator_iterator_increment (this->base_reference(), m_block); +} + + +/** + * @brief Move the iterator forward. + */ +void ArenaPoolAllocator::const_iterator::increment() +{ + ArenaPoolAllocator::pointer base = + const_cast<ArenaPoolAllocator::pointer> (this->base_reference()); + base = ArenaPoolAllocator_iterator_increment (base, m_block); + this->base_reference() = base; +} + + +/** + * @brief Constructor. + * @param params The parameters structure for this allocator. + * See @c ArenaAllocatorBase.h for the contents. + */ +ArenaPoolAllocator::ArenaPoolAllocator (const Params& params) + : ArenaBlockAllocatorBase (params), + m_ptr (0), + m_end (0) +{ +} + + +/** + * @brief Destructor. This will free all the Allocator's storage. + */ +ArenaPoolAllocator::~ArenaPoolAllocator() +{ + erase(); +} + + +/** + * @brief Free all allocated elements. + * + * All elements allocated are returned to the free state. + * @c clear should be called on them if it was provided. + * The elements may continue to be cached internally, without + * returning to the system. + */ +void ArenaPoolAllocator::reset() +{ + // Clear each block in turn. + while (m_blocks) + clearBlock(); + + // Check that things are consistent. + assert (m_stats.elts.inuse == 0); + assert (m_ptr == 0); + assert (m_end == 0); +} + + +/** + * @brief Free all allocated elements and release memory back to the system. + * + * All elements allocated are freed, and all allocated blocks of memory + * are released back to the system. + * @c destructor should be called on them if it was provided + * (preceded by @c clear if provided and @c mustClear was set). + */ +void ArenaPoolAllocator::erase() +{ + // Delete all the blocks. + ArenaBlockAllocatorBase::erase(); + + // Reset pointers. + m_ptr = m_end = 0; +} + + +/** + * @brief Reset pool back to a previous state. + * @param blk The pointer back to which to reset. + * + * This will free (a la @c reset) the element @c p and all elements + * that have been allocated after it from this allocator. + */ +void ArenaPoolAllocator::resetTo (pointer blk) +{ + // Clear the topmost block, as long as it doesn't contain the sought-after + // pointer. + ArenaBlock* p = m_blocks; + assert (p != 0); + size_t elt_size = p->eltSize(); + while (p && !(blk >= p->index(0, elt_size) && + blk < p->index(p->size(), elt_size))) + { + clearBlock(); + p = m_blocks; + } + + // We'll trip this if the supplied pointer wasn't in any block. + assert (p != 0); + + // If the element is at the beginning of this block, just clear the whole + // thing. + if (blk == p->index(0, elt_size)) + clearBlock(); + else { + // Otherwise, we need to clear some of the elements in this block. + // See if we need to call @c clear. + func_t* clear = m_params.clear; + if (clear) { + // Yeah, we do. Call @c clear on each element in turn. + while (m_ptr > blk) { + m_ptr -= elt_size; + clear (m_ptr); + --m_stats.elts.inuse; + } + // We'll trip this if the supplied pointer wasn't on an element + // boundary. + assert (m_ptr == blk); + } + else { + // We don't need to call @c clear. + // So we can do it the fast way --- just reset pointers. + m_stats.elts.inuse -= (m_ptr - blk) / elt_size; + m_ptr = blk; + } + } +} + + +/** + * @brief Starting pool iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is a @c forward_iterator. + */ +ArenaPoolAllocator::iterator ArenaPoolAllocator::begin() +{ + // If @c m_ptr is one set, it is one more than the last allocated element. + return iterator (m_ptr ? m_ptr - m_params.eltSize : 0, m_blocks); +} + + +/** + * @brief Starting pool const iterator. + * + * This will iterate over all allocated elements (in unspecified order). + * It is a @c forward_iterator. + */ +ArenaPoolAllocator::const_iterator ArenaPoolAllocator::begin() const +{ + // If @c m_ptr is one set, it is one more than the last allocated element. + return const_iterator (m_ptr ? m_ptr - m_params.eltSize : 0, m_blocks); +} + + +/** + * @brief Ending pool iterator. + */ +ArenaPoolAllocator::iterator ArenaPoolAllocator::end() +{ + // Use a null iterator to signal the end. + return iterator (); +} + + +/** + * @brief Ending pool const iterator. + */ +ArenaPoolAllocator::const_iterator ArenaPoolAllocator::end() const +{ + // Use a null iterator to signal the end. + return const_iterator (); +} + + +/** + * @brief Add more free elements to the pool. + */ +void ArenaPoolAllocator::refill() +{ + // Get a new block. + ArenaBlock* newblock = getBlock(); + + // Set the pointers. + m_ptr = newblock->index (0, m_params.eltSize); + m_end = newblock->index (newblock->size(), m_params.eltSize); +} + + +/** + * @brief Reset all elements in the topmost block, and move the block + * to the free list. + */ +void ArenaPoolAllocator::clearBlock() +{ + // The topmost block. + ArenaBlock* p = m_blocks; + + // Nothing to do if there are no allocated blocks! + if (!p) return; + + size_t elt_size = p->eltSize(); + + // The first element of the block. + pointer base = p->index(0, elt_size); + + // Do we need to call @c clear? If so, call it on all allocated elements + // in this block. + func_t* clear = m_params.clear; + if (clear) { + pointer elt = base; + while (elt < m_ptr) { + clear (elt); + elt += elt_size; + } + } + + // Update statistics. + --m_stats.blocks.inuse; + ++m_stats.blocks.free; + m_stats.elts.inuse -= (m_ptr - base) / elt_size; + + // Move the block from the allocated to the free list. + m_blocks = p->link(); + p->link() = m_freeblocks; + m_freeblocks = p; + p = m_blocks; + + // Reset the pointers. + if (p) { + m_ptr = m_end = p->index(p->size()); + } + else { + m_ptr = m_end = 0; + } +} + + +} // namespace SG diff --git a/Control/AthAllocators/src/ArenaSharedHeapSTLAllocator.cxx b/Control/AthAllocators/src/ArenaSharedHeapSTLAllocator.cxx new file mode 100644 index 0000000000000000000000000000000000000000..aa1966fcc63a02a6abbfe9ba76a5e76c5ce056ac --- /dev/null +++ b/Control/AthAllocators/src/ArenaSharedHeapSTLAllocator.cxx @@ -0,0 +1,66 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSharedHeapSTLAllocator.cxx 470825 2011-11-25 23:20:57Z ssnyder $ +/** + * @file AthAllocators/src/ArenaSharedHeapSTLAllocator.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov, 2011 + * @brief STL-style allocator wrapper for @c ArenaHeapAllocator allowing + * the heap to be shared between containers. + */ + + +#include "AthAllocators/ArenaSharedHeapSTLAllocator.h" + + +namespace SG { + + +/** + * @brief Constructor. + * @param owner Address of the object that owns this Header. + * @param nblock Value to set in the parameters structure for the + * number of elements to allocate per block. + * @param name Value to use as the base for the allocator names. + */ +ArenaSharedHeapSTLHeader::ArenaSharedHeapSTLHeader (const void* owner, + int nblock, + const std::string& name) + : m_owner (owner), + m_nblock (nblock), + m_name (name) +{ +} + + +/** + * @brief Destructor. + * + * Destroy all the allocators we own. + */ +ArenaSharedHeapSTLHeader::~ArenaSharedHeapSTLHeader() +{ + size_t sz = m_allocators.size(); + for (size_t i = 0; i < sz; i++) + delete m_allocators[i]; +} + + +/** + * @brief Return allocator statistics summed over all our owned allocators. + */ +ArenaAllocatorBase::Stats ArenaSharedHeapSTLHeader::totstats() const +{ + ArenaAllocatorBase::Stats stats; + size_t sz = m_allocators.size(); + for (size_t i = 0; i < sz; i++) { + if (m_allocators[i]) + stats += m_allocators[i]->stats(); + } + return stats; +} + + +} // namespace SG diff --git a/Control/AthAllocators/test/ArenaAllocatorBase_test.cxx b/Control/AthAllocators/test/ArenaAllocatorBase_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..e266a771105e90d4e26f1f63032979b3bbba3f8e --- /dev/null +++ b/Control/AthAllocators/test/ArenaAllocatorBase_test.cxx @@ -0,0 +1,155 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorBase_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaAllocatorBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaAllocatorBase. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaAllocatorBase.h" +#include <cassert> +#include <sstream> + + +int testcount = 0; + +class Test +{ +public: + Test() { ++testcount; } + ~Test() { --testcount; } + + int x; +}; + +class Test2 + : public Test +{ +public: + void clear() { testcount += 10; } +}; + + +class ArenaTestAllocator + : public SG::ArenaAllocatorBase +{ +public: + virtual void reset() {} + virtual void erase() {} + virtual void reserve (size_t /*size*/) { } + virtual const ArenaAllocatorBase::Stats& stats() const + { return m_stats; } + virtual const std::string& name() const { return m_name; } + ArenaAllocatorBase::Stats m_stats; + std::string m_name; +}; + + +void set_stat (SG::ArenaAllocatorBase::Stats::Stat& stat, int x) +{ + stat.inuse = x; + stat.free = x+1; + stat.total = x+2; +} + +void set_stats (SG::ArenaAllocatorBase::Stats& stats, int x) +{ + set_stat (stats.elts, x); + set_stat (stats.bytes, x + 1000); + set_stat (stats.blocks, x + 2000); +} + + +void check_stat_sum (const SG::ArenaAllocatorBase::Stats::Stat& stat1, + const SG::ArenaAllocatorBase::Stats::Stat& stat2, + const SG::ArenaAllocatorBase::Stats::Stat& stat3) +{ + assert (stat1.inuse + stat2.inuse == stat3.inuse); + assert (stat1.free + stat2.free == stat3.free); + assert (stat1.total + stat2.total == stat3.total); +} +void check_stats_sum (const SG::ArenaAllocatorBase::Stats& stats1, + const SG::ArenaAllocatorBase::Stats& stats2, + const SG::ArenaAllocatorBase::Stats& stats3) +{ + check_stat_sum (stats1.elts, stats2.elts, stats3.elts); + check_stat_sum (stats1.bytes, stats2.bytes, stats3.bytes); + check_stat_sum (stats1.blocks, stats2.blocks, stats3.blocks); +} + +void check_stat_zero (const SG::ArenaAllocatorBase::Stats::Stat& stat) +{ + assert (stat.inuse == 0); + assert (stat.free == 0); + assert (stat.total == 0); +} +void check_stats_zero (const SG::ArenaAllocatorBase::Stats& stats) +{ + check_stat_zero (stats.elts); + check_stat_zero (stats.bytes); + check_stat_zero (stats.blocks); +} + + +int main() +{ + ArenaTestAllocator ata; + ata.reset(); + ata.erase(); + ata.reserve(0); + assert (ata.stats().elts.inuse == 0); + assert (ata.name() == ""); + + SG::ArenaAllocatorBase::Params params = + SG::ArenaAllocatorBase::initParams<Test>(500, "foo"); + assert (params.name == "foo"); + assert (params.nblock == 500); + assert (params.eltSize == sizeof (Test)); + char* p = new char[sizeof(Test)]; + assert (testcount == 0); + params.constructor (p); + assert (testcount == 1); + params.destructor (p); + assert (testcount == 0); + + params = SG::ArenaAllocatorBase::initParams<Test2>(500); + assert (params.clear == 0); + params = SG::ArenaAllocatorBase::initParams<Test2, true>(500); + assert (params.clear != 0); + params.clear (p); + assert (testcount == 10); + + params = SG::ArenaAllocatorBase::initParams<int>(500); + assert (params.constructor == 0); + assert (params.destructor == 0); + + SG::ArenaAllocatorBase::Stats stats1; + SG::ArenaAllocatorBase::Stats stats2; + + set_stats (stats1, 1); + set_stats (stats2, 20); + + SG::ArenaAllocatorBase::Stats stats3 = stats1; + stats3 += stats2; + check_stats_sum (stats1, stats2, stats3); + stats3.clear(); + check_stats_zero (stats3); + + ata.m_name = "foo"; + assert (ata.name() == "foo"); + set_stats (ata.m_stats, 1); + std::ostringstream os; + ata.report (os); + assert (os.str() == " 1/ 2/ 3 1001/ 1002/ 1003 2001/ 2002/ 2003 foo\n"); + std::ostringstream os2; + stats1.header (os2); + assert (os2.str() == "Elts InUse/Free/Total Bytes InUse/Free/Total Blocks InUse/Free/Total"); + + delete [] p; + return 0; +} diff --git a/Control/AthAllocators/test/ArenaAllocatorCreator_test.cxx b/Control/AthAllocators/test/ArenaAllocatorCreator_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..e878e9fa4141e1db4f049143a705476a70dd3bb4 --- /dev/null +++ b/Control/AthAllocators/test/ArenaAllocatorCreator_test.cxx @@ -0,0 +1,30 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorCreator_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaAllocatorCreator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaAllocatorCreator. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaAllocatorCreator.h" +#include <cassert> + +class Test + : public SG::ArenaAllocatorCreator +{ +public: + virtual SG::ArenaAllocatorBase* create() { return 0; } +}; + + +int main() +{ + Test test; + assert (test.create() == 0); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaAllocatorRegistry_test.cxx b/Control/AthAllocators/test/ArenaAllocatorRegistry_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..281f8bcccfec85191f3b5720c4a2d33642dfa22b --- /dev/null +++ b/Control/AthAllocators/test/ArenaAllocatorRegistry_test.cxx @@ -0,0 +1,62 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaAllocatorRegistry_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaAllocatorRegistry_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaAllocatorRegistry. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include "AthAllocators/ArenaAllocatorCreator.h" +#include <cassert> + +class Alloc + : public SG::ArenaAllocatorBase +{ +public: + Alloc(int x) { m_stats.elts.total = x; } + virtual void reset() {} + virtual void erase() {} + virtual void reserve (size_t /*size*/) {} + virtual const std::string& name() const { return m_name; } + virtual const SG::ArenaAllocatorBase::Stats& stats() const + { return m_stats; } +private: + SG::ArenaAllocatorBase::Stats m_stats; + std::string m_name; +}; + +class Creator + : public SG::ArenaAllocatorCreator +{ +public: + Creator (int x) : m_x (x) {} + virtual SG::ArenaAllocatorBase* create() { return new Alloc (m_x); } +private: + int m_x; +}; + +void test1() +{ + SG::ArenaAllocatorRegistry* reg = + SG::ArenaAllocatorRegistry::instance(); + assert (reg->lookup ("foo") == std::string::npos); + assert (reg->registerCreator ("foo", new Creator (0)) == 0); + assert (reg->registerCreator ("bar", new Creator (1)) == 1); + assert (reg->lookup ("foo") == 0); + assert (reg->lookup ("bar") == 1); + assert (reg->create(0)->stats().elts.total == 0); + assert (reg->create(1)->stats().elts.total == 1); +} + +int main() +{ + test1(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaBase_test.cxx b/Control/AthAllocators/test/ArenaBase_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..63f7a021fc03c4fe3acab2defdb18641aea192c8 --- /dev/null +++ b/Control/AthAllocators/test/ArenaBase_test.cxx @@ -0,0 +1,46 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBase_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaBase. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaBase.h" +#include <ostream> +#include <sstream> +#include <cassert> + + +std::string xname = "bar"; + +class TestArena + : public SG::ArenaBase +{ +public: + virtual void report (std::ostream& os) const { os << "foo"; } + virtual const std::string& name() const { return xname; } +}; + + +void test1() +{ + TestArena t; + std::ostringstream s; + t.report (s); + assert (s.str() == "foo"); + assert (t.name() == "bar"); +} + + +int main() +{ + test1(); + return 0; +} + diff --git a/Control/AthAllocators/test/ArenaBlockAllocatorBase_test.cxx b/Control/AthAllocators/test/ArenaBlockAllocatorBase_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..e46534b549be8180f1ecf5415bf9749e90cbb1b6 --- /dev/null +++ b/Control/AthAllocators/test/ArenaBlockAllocatorBase_test.cxx @@ -0,0 +1,111 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlockAllocatorBase_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaBlockAllocatorBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaBlockAllocatorBase. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaBlockAllocatorBase.h" +#include "AthAllocators/ArenaBlock.h" +#include <cassert> + + +struct Payload +{ + Payload(); + ~Payload(); + void clear(); + + int x; + int y; + static int n; + //static std::vector<int> v; +}; + +Payload::Payload() +{ + x = n++; + y = 0; + //v.push_back (x); +} + +Payload::~Payload() +{ + //v.push_back (-x); +} + +void Payload::clear () +{ + y = 0; +} + +int Payload::n = 0; +//std::vector<int> Payload::v; + + +class TestAlloc + : public SG::ArenaBlockAllocatorBase +{ +public: + TestAlloc (const Params& params) : SG::ArenaBlockAllocatorBase (params){} + virtual void reset() {} +}; + + +void test_stats (const SG::ArenaBlockAllocatorBase& bab, + size_t nblock, + size_t nelt) +{ + size_t elt_size = bab.params().eltSize; + size_t block_ov = SG::ArenaBlock::overhead(); + const SG::ArenaAllocatorBase::Stats& stats = bab.stats(); + assert (stats.blocks.total == nblock); + assert (stats.blocks.inuse == 0); + assert (stats.blocks.free == nblock); + assert (stats.elts.total == nelt); + assert (stats.elts.inuse == 0); + assert (stats.elts.free == nelt); + assert (stats.bytes.total == nelt * elt_size + nblock * block_ov); + assert (stats.bytes.inuse == 0); + assert (stats.bytes.free == nelt * elt_size + nblock * block_ov); +} + + +void test1() +{ + TestAlloc bab + (SG::ArenaAllocatorBase::initParams<Payload, true> (100, "foo")); + assert (bab.name() == "foo"); + assert (bab.params().name == "foo"); + test_stats (bab, 0, 0); + + bab.reserve (1000); + test_stats (bab, 1, 1000); + + bab.reserve (500); + test_stats (bab, 1, 1000); + + bab.reserve (0); + test_stats (bab, 0, 0); + + bab.reserve (500); + test_stats (bab, 1, 500); + bab.reserve (1000); + test_stats (bab, 2, 1000); + bab.reserve (500); + test_stats (bab, 1, 500); + bab.erase(); + test_stats (bab, 0, 0); +} + +int main() +{ + test1(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaBlock_test.cxx b/Control/AthAllocators/test/ArenaBlock_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..3c1df22c8c44bfc5ae7865a5e19c65670f34741b --- /dev/null +++ b/Control/AthAllocators/test/ArenaBlock_test.cxx @@ -0,0 +1,144 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaBlock_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaBlock_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaBlock. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaBlock.h" +#include <cassert> +#include <vector> + +//========================================================================== + +struct Payload +{ + Payload(); + ~Payload(); + static void constructor (char*); + static void destructor (char*); + static void scan (char*); + + int x; + static int n; + static std::vector<int> v; +}; + +Payload::Payload() +{ + x = n++; + v.push_back (x); +} + +Payload::~Payload() +{ + v.push_back (-x); +} + +void Payload::constructor (char* p) +{ + new (p) Payload; +} + +void Payload::destructor (char* p) +{ + reinterpret_cast<Payload*>(p)->~Payload(); +} + +void Payload::scan (char* p) +{ + Payload::v.push_back (reinterpret_cast<Payload*>(p)->x); +} + +int Payload::n = 0; +std::vector<int> Payload::v; + +//========================================================================== + +const size_t elt_size = sizeof (Payload); + +int& word (SG::ArenaBlock* bl, size_t i=0) +{ + return *(int*)bl->index (i, elt_size); +} + +Payload& payload (SG::ArenaBlock* bl, size_t i=0) +{ + return *(Payload*)bl->index (i, elt_size); +} + +void test1() +{ + assert (SG::ArenaBlock::nactive() == 0); + SG::ArenaBlock* bl = SG::ArenaBlock::newBlock (20, elt_size, 0); + assert (SG::ArenaBlock::nactive() == 1); + assert (bl->overhead() > 0 && bl->overhead() < 100); + assert (bl->size() == 20); + assert (bl->eltSize() == elt_size); + word(bl, 0) = 0; + word(bl, 1) = 0; + assert ((char*)bl->index(1) - + (char*)bl->index(0) == (int)elt_size); + assert (bl->link() == 0); + bl->link() = bl; + assert (bl->link() == bl); + SG::ArenaBlock::destroy (bl, 0); + assert (SG::ArenaBlock::nactive() == 0); +} + + +void test2() +{ + SG::ArenaBlock* b1 = SG::ArenaBlock::newBlock (20, elt_size, + Payload::constructor); + SG::ArenaBlock* b2 = SG::ArenaBlock::newBlock (20, elt_size, + Payload::constructor); + SG::ArenaBlock* b3 = SG::ArenaBlock::newBlock (20, elt_size, + Payload::constructor); + int i = 0; + for (size_t j = 0; j < b1->size(); j++) { + assert (payload(b1, j).x == i); + assert (Payload::v[i] == i); + ++i; + } + b1->link() = b2; + SG::ArenaBlock::appendList (&b1, b3); + assert (payload(b1).x == 0); + assert (payload(b1->link()).x == 20); + assert (payload(b1->link()->link()).x == 40); + assert(b1->link()->link()->link() == 0); + SG::ArenaBlock* bb = 0; + SG::ArenaBlock::appendList (&bb, b1); + assert (bb == b1); + + Payload::v.clear(); + SG::ArenaBlock::applyList (b1, Payload::scan, 10); + assert (Payload::v.size() == 50); + for (size_t j = 0; j < 10; ++j) { + assert (Payload::v[j] == (int)j); + } + for (size_t j = 10; j < Payload::v.size(); ++j) { + assert (Payload::v[j] == (int)j+10); + } + + Payload::v.clear(); + SG::ArenaBlock::destroyList (b1, Payload::destructor); + assert (Payload::v.size() == 60); + for (size_t j = 0; j < Payload::v.size(); ++j) { + assert (Payload::v[j] == -(int)j); + } +} + + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaCachingHandle_test.cxx b/Control/AthAllocators/test/ArenaCachingHandle_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..acbc8aa905e98ef879a51b0332397a6e8c2a661d --- /dev/null +++ b/Control/AthAllocators/test/ArenaCachingHandle_test.cxx @@ -0,0 +1,242 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaCachingHandle_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaCachingHandle_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaCachingHandle. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaCachingHandle.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaHeaderGaudiClear.h" +#include "AthAllocators/ArenaPoolAllocator.h" +#include "AthAllocators/ArenaHeapAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <cassert> + +int count = 0; +int nctor = 0; +int ndtor = 0; +int nclear = 0; +struct Payload +{ + int x; + int y; + Payload() { x = ++count; y = 0; ++nctor; } + ~Payload() { ++ndtor; } + void clear() { y = 0; ++nclear; } +}; + +void test1() +{ + count = 0; + nctor = 0; + ndtor = 0; + nclear = 0; + + typedef + SG::ArenaCachingHandle<Payload, SG::ArenaPoolAllocator> Handtype; + SG::ArenaHeader head; + SG::Arena arena ("a", &head); + SG::Arena::Push push (arena); + + Handtype hand (&arena, + SG::ArenaPoolAllocator::initParams<Payload, true>(50)); + std::vector<Payload*> ptrs; + for (int i=0; i < 100; i++) { + Payload* p = hand.allocate(); + assert (p->y == 0); + p->y = i+1; + ptrs.push_back (p); + } + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); + size_t elt_size = hand.params().eltSize; + size_t block_ov = SG::ArenaBlock::overhead(); + + std::vector<int> v; + for (Handtype::iterator ii = hand.begin(); + ii != hand.end(); + ++ii) + { + assert (ii->y != 0); + v.push_back (ii->x); + } + assert (v.size() == 100); + for (size_t i = 0; i < v.size(); i++) { + assert (v[i] == 100-(int)i); + } + + const Handtype& chand = hand; + v.clear(); + for (Handtype::const_iterator ii = chand.begin(); + ii != chand.end(); + ++ii) + { + assert (ii->y != 0); + v.push_back (ii->x); + } + assert (v.size() == 100); + for (size_t i = 0; i < v.size(); i++) { + assert (v[i] == 100-(int)i); + } + + v.clear(); + for (Handtype::const_iterator ii = hand.begin(); + ii != hand.end(); + ++ii) + { + assert (ii->y != 0); + v.push_back (ii->x); + } + assert (v.size() == 100); + for (size_t i = 0; i < v.size(); i++) { + assert (v[i] == 100-(int)i); + } + + hand.reset(); + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 100); + assert (hand.stats().elts.inuse == 0); + assert (hand.stats().elts.free == 100); + assert (hand.stats().elts.total == 100); + + ptrs.clear(); + for (int i=0; i < 100; i++) { + Payload* p = hand.allocate(); + assert (p->y == 0); + p->y = i + 1; + ptrs.push_back (p); + } + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 100); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); + + Handtype hand2 (&head, 0); + + hand2.resetTo (ptrs[50]); + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 150); + assert (hand2.stats().elts.inuse == 50); + assert (hand2.stats().elts.free == 50); + assert (hand2.stats().elts.total == 100); + assert (hand2.stats().blocks.inuse == 1); + assert (hand2.stats().blocks.free == 1); + assert (hand2.stats().blocks.total == 2); + assert (hand2.stats().bytes.inuse == 50 * elt_size + block_ov); + assert (hand2.stats().bytes.free == 50 * elt_size + block_ov); + assert (hand2.stats().bytes.total == 100 * elt_size + 2*block_ov); + + hand2.erase(); + assert (nctor == 100); + assert (ndtor == 100); + assert (nclear == 150); + assert (hand2.stats().elts.inuse == 0); + assert (hand2.stats().elts.free == 0); + assert (hand2.stats().elts.total == 0); +} + + +void test2() +{ + count = 0; + nctor = 0; + ndtor = 0; + nclear = 0; + + typedef + SG::ArenaCachingHandle<Payload, SG::ArenaHeapAllocator> Handtype; + + Handtype hand (SG::ArenaHeapAllocator::initParams<Payload, true>(50)); + size_t elt_size = hand.params().eltSize; + assert (elt_size > sizeof (Payload)); + + std::vector<Payload*> ptrs; + for (int i=0; i < 100; i++) { + Payload* p = hand.allocate(); + assert (p->y == 0); + p->y = i+1; + ptrs.push_back (p); + } + //printf ("%d %d %d\n", nctor, ndtor, nclear); + //printf ("%d %d %d\n", hand.stats().elts.inuse, hand.stats().elts.free, hand.stats().elts.total()); + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); + + for (size_t i = 0; i < ptrs.size(); i+=2) { + hand.free (ptrs[i]); + } + + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 50); + assert (hand.stats().elts.inuse == 50); + assert (hand.stats().elts.free == 50); + assert (hand.stats().elts.total == 100); + + hand.reset(); + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 150); + assert (hand.stats().elts.inuse == 0); + assert (hand.stats().elts.free == 100); + assert (hand.stats().elts.total == 100); + + ptrs.clear(); + for (int i=0; i < 100; i++) { + Payload* p = hand.allocate(); + assert (p->y == 0); + p->y = i+1; + ptrs.push_back (p); + } + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 150); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); +} + + +void test3() +{ + typedef + SG::ArenaCachingHandle<Payload, SG::ArenaHeapAllocator> Handtype; + + SG::ArenaHeader head; + Handtype hand (&head, + SG::ArenaHeapAllocator::initParams<Payload, true>(50)); + + hand.reserve (100); + assert (hand.stats().elts.inuse == 0); + assert (hand.stats().elts.free == 100); + assert (hand.stats().elts.total == 100); +} + + +int main() +{ + SG::ArenaHeaderGaudiClear::disable(); + test1(); + test2(); + test3(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaHandleBaseAllocT_test.cxx b/Control/AthAllocators/test/ArenaHandleBaseAllocT_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..e1b3cbdb2716dd5cc3313223ef5ab0201d790d7a --- /dev/null +++ b/Control/AthAllocators/test/ArenaHandleBaseAllocT_test.cxx @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBaseAllocT_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHandleBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaHandleBaseAllocT. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaHandleBaseAllocT.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaHeaderGaudiClear.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include <cassert> + +class TestAlloc + : public SG::ArenaAllocatorBase +{ +public: + TestAlloc (const Params& params) : m_params (params) {} + virtual void reset() {} + virtual void erase() {} + virtual void reserve(size_t) {} + virtual const std::string& name() const { return m_params.name; } + virtual const Stats& stats() const { return m_stats; } + const Params& params() const { return m_params; } + int foo() { return 42; } + + static SG::ArenaAllocatorBase* makeAllocator (const Params& params) + { return new TestAlloc (params); } + +private: + Stats m_stats; + Params m_params; +}; + +class TestHandle + : public SG::ArenaHandleBaseAllocT<TestAlloc> +{ +public: + typedef SG::ArenaHandleBaseAllocT<TestAlloc> Base; + TestHandle (SG::ArenaHeader* header, size_t index) + : Base (header, index) {} + TestHandle (SG::ArenaHeader* header, const Creator& creator) + : Base (header, creator) {} + int foo() { return allocator()->foo(); } +}; + +void test1() +{ + SG::ArenaHeader head; + TestAlloc::Params params; + params.name = "foo"; + TestHandle hand (&head, TestHandle::Creator (static_cast<TestAlloc*>(0), + params)); + assert (hand.params().name == "foo"); + + TestHandle hand2 (&head, 0); + assert (hand2.foo() == 42); +} + +int main() +{ + SG::ArenaHeaderGaudiClear::disable(); + test1(); + return 0; +} + diff --git a/Control/AthAllocators/test/ArenaHandleBaseT_test.cxx b/Control/AthAllocators/test/ArenaHandleBaseT_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..52056a6a3a8a509751c37d277a7c055cb2c538c9 --- /dev/null +++ b/Control/AthAllocators/test/ArenaHandleBaseT_test.cxx @@ -0,0 +1,173 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBaseT_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHandleBaseT_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaHandleBaseT. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaHandleBaseT.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaHeaderGaudiClear.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include <cassert> +#include <iterator> + + +class Payload +{ +public: + Payload (int i) : m_x (i) {} + int m_x; +}; + + +class TestAlloc + : public SG::ArenaAllocatorBase +{ +public: + TestAlloc (const Params& params); + virtual void reset() {} + virtual void erase() {} + virtual void reserve(size_t) {} + virtual const std::string& name() const { return m_params.name; } + virtual const Stats& stats() const { return m_stats; } + const Params& params() const { return m_params; } + int foo() { return 42; } + void free (pointer p) { ptmp = p; } + void resetTo (pointer p) { ptmp = p+1; } + static pointer ptmp; + + class const_iterator; + + class iterator + : public std::iterator<std::forward_iterator_tag, Payload> + { + public: + iterator (std::vector<Payload>::iterator it) + : m_it (it) {} + reference operator*() const { return *m_it; } + iterator& operator++() { m_it++; return *this; } + bool operator== (const iterator& other) const + { return m_it == other.m_it; } + + friend class const_iterator; + + private: + std::vector<Payload>::iterator m_it; + }; + + class const_iterator + : public std::iterator<std::forward_iterator_tag, const Payload> + { + public: + const_iterator (std::vector<Payload>::const_iterator it) + : m_it (it) {} + const_iterator (TestAlloc::iterator it) + : m_it (&*it) {} + reference operator*() const { return *m_it; } + const_iterator& operator++() { m_it++; return *this; } + bool operator== (const const_iterator& other) const + { return m_it == other.m_it; } + bool operator== (const TestAlloc::iterator& other) const + { return m_it == other.m_it; } + + private: + std::vector<Payload>::const_iterator m_it; + }; + + iterator begin() { return iterator (m_vec.begin()); } + iterator end() { return iterator (m_vec.end()); } + const_iterator begin() const { return const_iterator (m_vec.begin()); } + const_iterator end() const { return const_iterator (m_vec.end()); } + + static SG::ArenaAllocatorBase* makeAllocator (const Params& params) + { return new TestAlloc (params); } + +private: + std::vector<Payload> m_vec; + Stats m_stats; + Params m_params; +}; + + +TestAlloc::TestAlloc (const Params& params) + : m_params (params) +{ + for (int i = 0; i < 10; i++) + m_vec.push_back (i); +} + +TestAlloc::pointer TestAlloc::ptmp = 0; + +class TestHandle + : public SG::ArenaHandleBaseT<Payload, TestAlloc> +{ +public: + typedef SG::ArenaHandleBaseT<Payload, TestAlloc> Base; + TestHandle (SG::ArenaHeader* header, size_t index) + : Base (header, index) {} + TestHandle (SG::ArenaHeader* header, const Creator& creator) + : Base (header, creator) {} + int foo() { return allocator()->foo(); } +}; + +void test1() +{ + SG::ArenaHeader head; + TestAlloc::Params params; + params.name = "foo"; + TestHandle hand (&head, TestHandle::Creator (static_cast<TestAlloc*>(0), + params)); + assert (hand.params().name == "foo"); + TestHandle::pointer p = reinterpret_cast<TestHandle::pointer>(0x1234); + hand.free (p); + assert (TestAlloc::ptmp == reinterpret_cast<TestAlloc::pointer>(p)); + hand.resetTo (p); + assert (TestAlloc::ptmp == reinterpret_cast<TestAlloc::pointer>(p)+1); + + TestHandle hand2 (&head, 0); + int i = 0; + for (TestHandle::iterator it = hand2.begin(); + it != hand2.end(); + ++it) + { + assert ((*it).m_x == i); + assert (it->m_x == i); + ++i; + } + + i = 0; + const TestHandle& chand = hand2; + for (TestHandle::const_iterator it = chand.begin(); + it != chand.end(); + ++it) + { + assert ((*it).m_x == i); + assert (it->m_x == i); + ++i; + } + + i = 0; + for (TestHandle::const_iterator it = hand2.begin(); + it != hand2.end(); + ++it) + { + assert ((*it).m_x == i); + assert (it->m_x == i); + ++i; + } +} + + +int main() +{ + SG::ArenaHeaderGaudiClear::disable(); + test1(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaHandleBase_test.cxx b/Control/AthAllocators/test/ArenaHandleBase_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..b0fa7a461d7bc92ea36b2946963d28e055a2bc34 --- /dev/null +++ b/Control/AthAllocators/test/ArenaHandleBase_test.cxx @@ -0,0 +1,74 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandleBase_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHandleBase_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaHandleBase. + */ + + +#undef NDEBUG +#include "AthAllocators/ArenaHandleBase.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaHeaderGaudiClear.h" +#include "AthAllocators/ArenaPoolAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <cassert> + +struct Payload +{ + int x; +}; + +void test1() +{ + SG::ArenaHeader header; + SG::ArenaHeader::ArenaAllocVec_t vec; + vec.push_back (new SG::ArenaPoolAllocator + (SG::ArenaPoolAllocator::initParams<Payload>(1000))); + header.setAllocVec (&vec); + SG::ArenaHandleBase test (&header, 0); + size_t elt_size = + dynamic_cast<SG::ArenaPoolAllocator*>(vec[0])->params().eltSize; + size_t block_ov = SG::ArenaBlock::overhead(); + + assert (test.stats().elts.inuse == 0); + assert (test.stats().elts.free == 0); + assert (test.stats().elts.total == 0); + test.reserve (10); + assert (test.stats().elts.inuse == 0); + assert (test.stats().elts.free == 1000); + assert (test.stats().elts.total == 1000); + assert (test.stats().blocks.inuse == 0); + assert (test.stats().blocks.free == 1); + assert (test.stats().blocks.total == 1); + assert (test.stats().bytes.inuse == 0); + assert (test.stats().bytes.free == 1000 * elt_size + block_ov); + assert (test.stats().bytes.total == 1000 * elt_size + block_ov); + test.reset (); + assert (test.stats().elts.inuse == 0); + assert (test.stats().elts.free == 1000); + assert (test.stats().elts.total == 1000); + test.erase (); + assert (test.stats().elts.inuse == 0); + assert (test.stats().elts.free == 0); + assert (test.stats().elts.total == 0); + + SG::ArenaHandleBase test2 (0, 0); + SG::ArenaHeader::defaultHeader()->setAllocVec (&vec); + test2.reserve (10); + assert (test2.stats().elts.inuse == 0); + assert (test2.stats().elts.free == 1000); + assert (test2.stats().elts.total == 1000); +} + +int main() +{ + SG::ArenaHeaderGaudiClear::disable(); + test1(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaHandle_test.cxx b/Control/AthAllocators/test/ArenaHandle_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..8d8d2c8ed4d284696e95fa1eeda753a73ccc4c66 --- /dev/null +++ b/Control/AthAllocators/test/ArenaHandle_test.cxx @@ -0,0 +1,238 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHandle_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHandle_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaHandle. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaHandle.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaHeaderGaudiClear.h" +#include "AthAllocators/ArenaPoolAllocator.h" +#include "AthAllocators/ArenaHeapAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <cassert> + +int count = 0; +int nctor = 0; +int ndtor = 0; +int nclear = 0; +struct Payload +{ + int x; + int y; + Payload() { x = ++count; y = 0; ++nctor; } + ~Payload() { ++ndtor; } + void clear() { y = 0; ++nclear; } +}; + +void test1() +{ + count = 0; + nctor = 0; + ndtor = 0; + nclear = 0; + + typedef + SG::ArenaHandle<Payload, SG::ArenaPoolAllocator> Handtype; + SG::ArenaHeader head; + SG::Arena arena ("a", &head); + SG::Arena::Push push (arena); + + + Handtype hand (&arena, + SG::ArenaPoolAllocator::initParams<Payload, true>(50)); + std::vector<Payload*> ptrs; + for (int i=0; i < 100; i++) { + Payload* p = new (hand.allocate()) Payload; + assert (p->y == 0); + p->y = i+1; + ptrs.push_back (p); + } + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); + + std::vector<int> v; + for (Handtype::iterator ii = hand.begin(); + ii != hand.end(); + ++ii) + { + assert (ii->y != 0); + v.push_back (ii->x); + } + assert (v.size() == 100); + for (size_t i = 0; i < v.size(); i++) { + assert (v[i] == 100-(int)i); + } + + const Handtype& chand = hand; + v.clear(); + for (Handtype::const_iterator ii = chand.begin(); + ii != chand.end(); + ++ii) + { + assert (ii->y != 0); + v.push_back (ii->x); + } + assert (v.size() == 100); + for (size_t i = 0; i < v.size(); i++) { + assert (v[i] == 100-(int)i); + } + + v.clear(); + for (Handtype::const_iterator ii = hand.begin(); + ii != hand.end(); + ++ii) + { + assert (ii->y != 0); + v.push_back (ii->x); + } + assert (v.size() == 100); + for (size_t i = 0; i < v.size(); i++) { + assert (v[i] == 100-(int)i); + } + + hand.reset(); + assert (nctor == 100); + assert (ndtor == 100); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 0); + assert (hand.stats().elts.free == 100); + assert (hand.stats().elts.total == 100); + + ptrs.clear(); + for (int i=0; i < 100; i++) { + Payload* p = new (hand.allocate()) Payload; + p->y = i + 1; + ptrs.push_back (p); + } + assert (nctor == 200); + assert (ndtor == 100); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); + + Handtype hand2 (&head, 0); + + hand2.resetTo (ptrs[50]); + assert (nctor == 200); + assert (ndtor == 150); + assert (nclear == 00); + assert (hand2.stats().elts.inuse == 50); + assert (hand2.stats().elts.free == 50); + assert (hand2.stats().elts.total == 100); + + hand2.erase(); + assert (nctor == 200); + assert (ndtor == 200); + assert (nclear == 0); + assert (hand2.stats().elts.inuse == 0); + assert (hand2.stats().elts.free == 0); + assert (hand2.stats().elts.total == 0); +} + + +void test2() +{ + count = 0; + nctor = 0; + ndtor = 0; + nclear = 0; + + typedef + SG::ArenaHandle<Payload, SG::ArenaHeapAllocator> Handtype; + + Handtype hand (SG::ArenaHeapAllocator::initParams<Payload, true>(50)); + size_t elt_size = hand.params().eltSize; + assert (elt_size == sizeof (Payload)); + size_t block_ov = SG::ArenaBlock::overhead(); + + std::vector<Payload*> ptrs; + for (int i=0; i < 100; i++) { + Payload* p = new (hand.allocate()) Payload; + assert (p->y == 0); + p->y = i+1; + ptrs.push_back (p); + } + assert (nctor == 100); + assert (ndtor == 0); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); + + for (size_t i = 0; i < ptrs.size(); i+=2) { + hand.free (ptrs[i]); + } + assert (nctor == 100); + assert (ndtor == 50); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 50); + assert (hand.stats().elts.free == 50); + assert (hand.stats().elts.total == 100); + assert (hand.stats().blocks.inuse == 2); + assert (hand.stats().blocks.free == 0); + assert (hand.stats().blocks.total == 2); + assert (hand.stats().bytes.inuse == 50 * elt_size + 2 * block_ov); + assert (hand.stats().bytes.free == 50 * elt_size); + assert (hand.stats().bytes.total == 100 * elt_size + 2 * block_ov); + + hand.reset(); + assert (nctor == 100); + assert (ndtor == 100); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 0); + assert (hand.stats().elts.free == 100); + assert (hand.stats().elts.total == 100); + + ptrs.clear(); + for (int i=0; i < 100; i++) { + Payload* p = new (hand.allocate()) Payload; + assert (p->y == 0); + p->y = i+1; + ptrs.push_back (p); + } + assert (nctor == 200); + assert (ndtor == 100); + assert (nclear == 0); + assert (hand.stats().elts.inuse == 100); + assert (hand.stats().elts.free == 0); + assert (hand.stats().elts.total == 100); +} + + +void test3() +{ + typedef + SG::ArenaHandle<Payload, SG::ArenaHeapAllocator> Handtype; + + SG::ArenaHeader head; + Handtype hand (&head, + SG::ArenaHeapAllocator::initParams<Payload, true>(50)); + + hand.reserve (100); + assert (hand.stats().elts.inuse == 0); + assert (hand.stats().elts.free == 100); + assert (hand.stats().elts.total == 100); +} + + +int main() +{ + SG::ArenaHeaderGaudiClear::disable(); + test1(); + test2(); + test3(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaHeaderGaudiClear_test.cxx b/Control/AthAllocators/test/ArenaHeaderGaudiClear_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..70d9f9b0b11a98fcdc2b9bfe21ca7315ebd85442 --- /dev/null +++ b/Control/AthAllocators/test/ArenaHeaderGaudiClear_test.cxx @@ -0,0 +1,92 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeaderGaudiClear_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHeaderGaudiClear_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jun, 2007 + * @brief Regression tests for ArenaHeaderGaudiClear. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaHeaderGaudiClear.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include <cassert> + + +int nreset = 0; +class TestAlloc + : public SG::ArenaAllocatorBase +{ +public: + virtual void reset() { ++nreset; } + virtual void erase() {} + virtual void reserve (size_t /*size*/) { } + virtual const ArenaAllocatorBase::Stats& stats() const + { return m_stats; } + virtual const std::string& name() const { return m_name; } + ArenaAllocatorBase::Stats m_stats; + std::string m_name; +}; + + +int ndel = 0; +class TestHeader + : public SG::ArenaHeaderGaudiClear +{ +public: + virtual ~TestHeader() { ++ndel; } +}; + + +void test1() +{ + ndel = nreset = 0; + + SG::ArenaHeaderGaudiClear* h = new TestHeader; + h->initialize(); + + SG::ArenaHeader::ArenaAllocVec_t vec; + vec.push_back (new TestAlloc); + h->setAllocVec (&vec); + assert (nreset == 0); + h->handle (Incident ("test", "BeginEvent")); + assert (nreset == 1); + h->handle (Incident ("test", "EndEvent")); + assert (nreset == 1); + h->handle (Incident ("test", "BeginEvent")); + assert (nreset == 2); + + h->addRef(); + assert (ndel == 0); + h->release(); + assert (ndel == 1); +} + + +void test2() +{ + ndel = nreset = 0; + SG::ArenaHeaderGaudiClear* h = new TestHeader; + SG::ArenaHeaderGaudiClear::disable(); + h->initialize(); + + assert (nreset == 0); + h->handle (Incident ("test", "BeginEvent")); + assert (nreset == 0); + + h->addRef(); + assert (ndel == 0); + h->release(); + assert (ndel == 1); +} + + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaHeader_test.cxx b/Control/AthAllocators/test/ArenaHeader_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..6953b0fe190c319f5db6fa4229dc79f788b98853 --- /dev/null +++ b/Control/AthAllocators/test/ArenaHeader_test.cxx @@ -0,0 +1,124 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeader_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHeader_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaHeader. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaHeaderGaudiClear.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include "AthAllocators/ArenaAllocatorCreator.h" +#include "AthAllocators/ArenaBase.h" +#include <cassert> +#include <ostream> + +std::string reset; +class TestAlloc + : public SG::ArenaAllocatorBase +{ +public: + TestAlloc (int x, const std::string& name) + : m_name (name) { m_stats.bytes.total = x; } + virtual void reset() { ::reset = m_name; } + virtual void erase() {} + virtual void reserve (size_t /*size*/) {} + virtual const SG::ArenaAllocatorBase::Stats& stats() const + { return m_stats; } + virtual const std::string& name() const { return m_name; } +private: + SG::ArenaAllocatorBase::Stats m_stats; + std::string m_name; +}; + +class Creator + : public SG::ArenaAllocatorCreator +{ +public: + Creator (int x) : m_x (x) {} + virtual SG::ArenaAllocatorBase* create() + { return new TestAlloc (m_x, "creat"); } +private: + int m_x; +}; + + +class TestArena + : public SG::ArenaBase +{ +public: + TestArena (const std::string& name, int x) : m_name (name), m_x (x) {} + virtual void report (std::ostream& os) const + { os << "foo " << m_x << "\n"; } + virtual const std::string& name() const { return m_name; } +private: + std::string m_name; + int m_x; +}; + + +void test1() +{ + SG::ArenaHeader::ArenaAllocVec_t vec1; + vec1.resize (10); + vec1[2] = new TestAlloc (0, "a"); + SG::ArenaHeader::ArenaAllocVec_t vec2; + vec2.resize (10); + vec2[5] = new TestAlloc (1, "b"); + + SG::ArenaHeader* head = SG::ArenaHeader::defaultHeader(); + assert (head->setAllocVec(&vec1) == 0); + assert (head->allocator(2) == vec1[2]); + assert (head->setAllocVec(&vec2) == &vec1); + assert (head->allocator(5) == vec2[5]); + head->reset(); + assert (reset == "b"); + + SG::ArenaHeader::ArenaAllocVec_t vec3; + assert (head->setAllocVec(0) == &vec2); + SG::ArenaAllocatorRegistry* reg = + SG::ArenaAllocatorRegistry::instance(); + size_t i = reg->registerCreator ("foo", new Creator (1)); + assert (i == 0); + assert (head->allocator(i)->stats().bytes.total == 1); +} + + +void test2() +{ + SG::ArenaHeader head; + TestArena a1 ("a1", 1); + TestArena a2 ("a2", 2); + head.addArena (&a1); + head.addArena (&a2); + std::string s = head.reportStr(); + assert (s == "=== a1 ===\n\ +foo 1\n\ +=== a2 ===\n\ +foo 2\n"); + head.delArena (&a1); + assert (head.allocator(0)->stats().bytes.total == 1); + s = head.reportStr(); + assert (s == "=== a2 ===\n\ +foo 2\n\ +=== default ===\n\ +Elts InUse/Free/Total Bytes InUse/Free/Total Blocks InUse/Free/Total\n\ + 0/ 0/ 0 0/ 0/ 1 0/ 0/ 0 creat\n"); + +} + + +int main() +{ + SG::ArenaHeaderGaudiClear::disable(); + test1(); + test2(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaHeapAllocator_test.cxx b/Control/AthAllocators/test/ArenaHeapAllocator_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..493a64c3bcd4d0f13c47307484c2381e2d512d37 --- /dev/null +++ b/Control/AthAllocators/test/ArenaHeapAllocator_test.cxx @@ -0,0 +1,218 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapAllocator_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaHeapAllocator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaHeapAllocator. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaHeapAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <vector> +#include <cassert> +#include <algorithm> + +//========================================================================== + +int nclear; +struct Payload +{ + Payload(); + ~Payload(); + void clear(); + + int x; + int y; + static int n; + static std::vector<int> v; +}; + +Payload::Payload() +{ + x = n++; + y = 0; + v.push_back (x); +} + +Payload::~Payload() +{ + v.push_back (-x); +} + +void Payload::clear () +{ + y = 0; + ++nclear; +} + +int Payload::n = 0; +std::vector<int> Payload::v; + +//========================================================================== + +void test1() +{ + SG::ArenaHeapAllocator aha + (SG::ArenaHeapAllocator::initParams<Payload, true>(100, "foo")); + assert (aha.name() == "foo"); + assert (aha.stats().elts.inuse == 0); + assert (aha.stats().elts.free == 0); + assert (aha.stats().elts.total == 0); + assert (aha.stats().blocks.inuse == 0); + assert (aha.stats().blocks.free == 0); + assert (aha.stats().blocks.total == 0); + size_t elt_size = aha.params().eltSize; + size_t block_ov = SG::ArenaBlock::overhead(); + + int nptr = 987; + std::vector<Payload*> ptrs; + for (int i=0; i < nptr; i++) { + Payload* p = reinterpret_cast<Payload*> (aha.allocate()); + ptrs.push_back (p); + p->y = 2*p->x; + } + assert (Payload::v.size() == 1000); + for (int i=0; i < 1000; ++i) { + assert (Payload::v[i] == i); + } + assert (aha.stats().elts.inuse == 987); + assert (aha.stats().elts.free == 13); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 10); + assert (aha.stats().blocks.free == 0); + assert (aha.stats().blocks.total == 10); + + for (size_t i = 0; i < ptrs.size(); i += 2) + aha.free ((char*)ptrs[i]); + assert (aha.stats().elts.inuse == 493); + assert (aha.stats().elts.free == 507); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 10); + assert (aha.stats().blocks.free == 0); + assert (aha.stats().blocks.total == 10); + for (size_t i = 0; i < ptrs.size(); i += 2) + assert (ptrs[i]->y == 0); + for (size_t i = 0; i < 300; i++) + ptrs.push_back (reinterpret_cast<Payload*>(aha.allocate())); + //printf ("%d %d %d\n", aha.stats().elts.inuse, aha.stats().elts.free, aha.stats().elts.total); + assert (aha.stats().elts.inuse == 793); + assert (aha.stats().elts.free == 207); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 10); + assert (aha.stats().blocks.free == 0); + assert (aha.stats().blocks.total == 10); + + assert (aha.stats().bytes.inuse == (793 * elt_size + 10 * block_ov)); + assert (aha.stats().bytes.free == 207 * elt_size); + assert (aha.stats().bytes.total == (1000 * elt_size + 10 * block_ov)); + + aha.reset(); + assert (aha.stats().elts.inuse == 0); + assert (aha.stats().elts.free == 1000); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 0); + assert (aha.stats().blocks.free == 10); + assert (aha.stats().blocks.total == 10); + + ptrs.clear(); + for (size_t i = 0; i < 300; i++) + ptrs.push_back (reinterpret_cast<Payload*>(aha.allocate())); + assert (aha.stats().elts.inuse == 300); + assert (aha.stats().elts.free == 700); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 3); + assert (aha.stats().blocks.free == 7); + assert (aha.stats().blocks.total == 10); + + aha.reserve (550); + assert (aha.stats().elts.inuse == 300); + assert (aha.stats().elts.free == 300); + assert (aha.stats().elts.total == 600); + assert (aha.stats().blocks.inuse == 3); + assert (aha.stats().blocks.free == 3); + assert (aha.stats().blocks.total == 6); + + aha.reserve (1000); + //printf ("%d %d %d\n", aha.stats().elts.inuse, aha.stats().elts.free, aha.stats().elts.total); + assert (aha.stats().elts.inuse == 300); + assert (aha.stats().elts.free == 700); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 3); + assert (aha.stats().blocks.free == 4); + assert (aha.stats().blocks.total == 7); + + Payload::v.clear(); + aha.erase(); + assert (aha.stats().elts.inuse == 0); + assert (aha.stats().elts.free == 0); + assert (aha.stats().elts.total == 0); + assert (aha.stats().blocks.inuse == 0); + assert (aha.stats().blocks.free == 0); + assert (aha.stats().blocks.total == 0); + assert (Payload::v.size() == 1000); + std::sort (Payload::v.begin(), Payload::v.end()); + for (size_t i = 0; i < 700; i++) { + assert (Payload::v[i] == (int)i-1399); + //printf ("%d %d\n", Payload::v[i], i); + } + for (size_t i = 700; i < Payload::v.size(); i++) { + assert (Payload::v[i] == (int)i-999); + } +} + + +void test2() +{ + SG::ArenaHeapAllocator::Params params = + SG::ArenaHeapAllocator::initParams<Payload, true>(100); + params.mustClear = true; + params.canReclear = false; + SG::ArenaHeapAllocator aha (params); + assert (aha.stats().elts.inuse == 0); + assert (aha.stats().elts.free == 0); + assert (aha.stats().elts.total == 0); + assert (aha.stats().blocks.inuse == 0); + assert (aha.stats().blocks.free == 0); + assert (aha.stats().blocks.total == 0); + + nclear = 0; + std::vector<Payload*> ptrs; + for (int i=0; i < 987; i++) { + Payload* p = reinterpret_cast<Payload*> (aha.allocate()); + ptrs.push_back (p); + p->y = 2*p->x; + } + for (size_t i = 0; i < ptrs.size(); i+=2) { + aha.free ((char*)ptrs[i]); + assert (ptrs[i]->y == 0); + ptrs[i]->y = 1; + } + aha.reset(); + assert (nclear == 987); + assert (aha.stats().elts.inuse == 0); + assert (aha.stats().elts.free == 1000); + assert (aha.stats().elts.total == 1000); + assert (aha.stats().blocks.inuse == 0); + assert (aha.stats().blocks.free == 10); + assert (aha.stats().blocks.total == 10); + + for (size_t i = 0; i < ptrs.size(); i++) { + if ((i&1) != 0) + assert (ptrs[i]->y == 0); + else + assert (ptrs[i]->y == 1); + } +} + + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaHeapSTLAllocator_test.cxx b/Control/AthAllocators/test/ArenaHeapSTLAllocator_test.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3c573e475ae4bccb4ab5bbf1053903585a7b2fda --- /dev/null +++ b/Control/AthAllocators/test/ArenaHeapSTLAllocator_test.cxx @@ -0,0 +1,265 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaHeapSTLAllocator_test.cxx,v 1.2 2008-08-26 02:12:26 ssnyder Exp $ +/** + * @file AthAllocators/test/ArenaHeapSTLAllocator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov 2011 + * @brief Regression tests for ArenaHeapSTLAllocator. + */ + + +#undef NDEBUG +#include "AthAllocators/ArenaHeapSTLAllocator.h" +#include "boost/assign/list_of.hpp" +#include <list> +#include <vector> +#include <cassert> +#include <iostream> + +using boost::assign::list_of; + + + +//========================================================================== + +struct Payload +{ + Payload(int = 0); + Payload(const Payload& p); + ~Payload(); + void clear(); + + int x; + int y; + static int n; + static std::vector<int> v; +}; + +Payload::Payload(int the_y) +{ + x = n++; + y = the_y; + v.push_back (x); +} + +Payload::Payload (const Payload& p) + : x (p.x), + y (p.y) +{ + v.push_back (x); +} + + +Payload::~Payload() +{ + v.push_back (-x); +} + +void Payload::clear () +{ + y = 0; +} + +int Payload::n = 0; +std::vector<int> Payload::v; + +//========================================================================== + +// Test generic specialization. +void test1() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test1\n"; + + SG::ArenaHeapSTLAllocator<Payload> a1; + assert (a1.nblock() == 1000); + assert (a1.name() == ""); + + SG::ArenaHeapSTLAllocator<Payload> a2 (100, "a2"); + assert (a2.nblock() == 100); + assert (a2.name() == "a2"); + + SG::ArenaHeapSTLAllocator<Payload*, int> a3 (100, "a3"); + assert (a3.nblock() == 100); + assert (a3.name() == "a3"); + + SG::ArenaHeapSTLAllocator<Payload, int> a4 (a3); + assert (a4.nblock() == 100); + assert (a4.name() == "a3"); + assert (a4.poolptr() != 0); + + { + Payload p; + Payload& pr = p; + const Payload& pcr = p; + assert (a4.address (pr) == &p); + assert (a4.address (pcr) == &p); + } + assert (Payload::n == 1); + assert (Payload::v.size() == 2); + Payload::v.clear(); + + std::vector<Payload*> pv; + for (int i=0; i < 10; i++) + pv.push_back (a4.allocate (1)); + + assert (Payload::n == 1); + assert (Payload::v.size() == 0); + + assert (a4.max_size() == 1); + + a4.construct (pv[0], Payload(10)); + a4.destroy (pv[0]); + + assert (Payload::n == 2); + std::vector<int> exp1 = list_of(1)(1)(-1)(-1); + assert (Payload::v == exp1); + Payload::v.clear(); + + for (int i=0; i < 9; i++) { + if (i > 0) + assert (pv[i] != pv[i-1]); + a4.deallocate (pv[i], 1); + } + + assert (a4.stats().elts.inuse == 1); + assert (a4.stats().elts.total == 100); + + a4.reset(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 100); + + a4.erase(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 0); + + a4.reserve(5000); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 5000); + + assert (Payload::n == 2); + assert (Payload::v.size() == 0); +} + + +// Test vetoed specialization. +void test2() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test2\n"; + + SG::ArenaHeapSTLAllocator<int, int> a1; + assert (a1.nblock() == 1000); + assert (a1.name() == ""); + assert (a1.poolptr() == 0); + + SG::ArenaHeapSTLAllocator<int, int> a2 (100, "a2"); + assert (a2.nblock() == 100); + assert (a2.name() == "a2"); + assert (a2.poolptr() == 0); + + a2.reset(); + a2.erase(); + a2.reserve(10); + assert (a2.stats().elts.total == 0); + + SG::ArenaHeapSTLAllocator<Payload, int> a3 (500, "a3"); + a3.reserve (1000); + SG::ArenaHeapSTLAllocator<int> a4 (a3); + assert (a4.nblock() == 500); + assert (a4.name() == "a3"); + assert (a4.poolptr() == a3.poolptr()); + + (void)a3.allocate (1); + assert (a3.stats().elts.inuse == 1); + assert (a3.stats().elts.total == 1000); + + assert (a4.stats().elts.inuse == 1); + assert (a4.stats().elts.total == 1000); + assert (&a3.stats() == &a4.stats()); + + a4.reset(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + a4.erase(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 0); + + a4.reserve(1000); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + int* p = a4.allocate (2, 0); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + a4.deallocate (p, 2); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + assert (Payload::n == 0); + assert (Payload::v.size() == 0); +} + + +// In-situ test. +void test3() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test3\n"; + + typedef std::list<int, SG::ArenaHeapSTLAllocator<int> > list_t; + + list_t::allocator_type allo (500, "allo"); + list_t list (allo); + + for (int i = 0; i < 10; i++) + list.push_back (i); + + assert (list.size() == 10); + assert (list.get_allocator().stats().elts.total == 500); + assert (list.get_allocator().stats().elts.inuse == 10); + + for (list_t::iterator i = list.begin(); + i != list.end(); + ++i) + { + i = list.erase (i); + if (i == list.end()) break; + } + + assert (list.size() == 5); + assert (list.get_allocator().stats().elts.total == 500); + assert (list.get_allocator().stats().elts.inuse == 5); + + list.clear(); + assert (list.size() == 0); + assert (list.get_allocator().stats().elts.total == 500); + assert (list.get_allocator().stats().elts.inuse == 0); + + list.get_allocator().reset(); + assert (list.get_allocator().stats().elts.total == 500); + assert (list.get_allocator().stats().elts.inuse == 0); + + assert (Payload::n == 0); + assert (Payload::v.size() == 0); +} + + +int main() +{ + test1(); + test2(); + test3(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaPoolAllocator_test.cxx b/Control/AthAllocators/test/ArenaPoolAllocator_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..7c705cc13458f4f550e8589c6f812d68d305ad42 --- /dev/null +++ b/Control/AthAllocators/test/ArenaPoolAllocator_test.cxx @@ -0,0 +1,262 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolAllocator_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaPoolAllocator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for ArenaPoolAllocator. + */ + +#undef NDEBUG +#include "AthAllocators/ArenaPoolAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include <vector> +#include <cassert> +#include <algorithm> + +//========================================================================== + +struct Payload +{ + Payload(); + ~Payload(); + void clear(); + + int x; + int y; + static int n; + static std::vector<int> v; +}; + +Payload::Payload() +{ + x = n++; + y = 0; + v.push_back (x); +} + +Payload::~Payload() +{ + v.push_back (-x); +} + +void Payload::clear () +{ + y = 0; +} + +int Payload::n = 0; +std::vector<int> Payload::v; + +//========================================================================== + +void test1() +{ + SG::ArenaPoolAllocator apa + (SG::ArenaPoolAllocator::initParams<Payload, true>(100, "foo")); + assert (apa.name() == "foo"); + assert (apa.stats().elts.inuse == 0); + assert (apa.stats().elts.free == 0); + assert (apa.stats().elts.total == 0); + assert (apa.stats().blocks.inuse == 0); + assert (apa.stats().blocks.free == 0); + assert (apa.stats().blocks.total == 0); + assert (apa.params().eltSize == sizeof (Payload)); + + int nptr = 987; + std::vector<Payload*> ptrs; + for (int i=0; i < nptr; i++) { + Payload* p = reinterpret_cast<Payload*> (apa.allocate()); + ptrs.push_back (p); + p->y = 2*p->x; + } + assert (Payload::v.size() == 1000); + for (int i=0; i < 1000; ++i) { + assert (Payload::v[i] == i); + } + assert (apa.stats().elts.inuse == 987); + assert (apa.stats().elts.free == 13); + assert (apa.stats().elts.total == 1000); + assert (apa.stats().blocks.inuse == 10); + assert (apa.stats().blocks.free == 0); + assert (apa.stats().blocks.total == 10); + + Payload::v.clear(); + apa.reset(); + assert (apa.stats().elts.inuse == 0); + assert (apa.stats().elts.free == 1000); + assert (apa.stats().elts.total == 1000); + assert (apa.stats().blocks.inuse == 0); + assert (apa.stats().blocks.free == 10); + assert (apa.stats().blocks.total == 10); + + for (int i=0; i < 300; i++) { + Payload* p = reinterpret_cast<Payload*> (apa.allocate()); + assert (p->y == 0); + ptrs.push_back (p); + p->y = 2*p->x; + } + assert (Payload::v.size() == 0); + assert (apa.stats().elts.inuse == 300); + assert (apa.stats().elts.free == 700); + assert (apa.stats().elts.total == 1000); + assert (apa.stats().blocks.inuse == 3); + assert (apa.stats().blocks.free == 7); + assert (apa.stats().blocks.total == 10); + + apa.allocate(); + std::vector<int> vv; + for (SG::ArenaPoolAllocator::iterator ii = apa.begin(); + ii != apa.end(); + ++ii) + { + vv.push_back (reinterpret_cast<Payload*> (&*ii)->x); + } + std::sort (vv.begin(), vv.end()); + assert (vv.size() == 301); + for (size_t jj = 0; jj < vv.size(); jj++) { + assert (vv[jj] == (int)jj); + } + + vv.clear(); + const SG::ArenaPoolAllocator& capa = apa; + for (SG::ArenaPoolAllocator::const_iterator ii = capa.begin(); + ii != capa.end(); + ++ii) + { + vv.push_back (reinterpret_cast<const Payload*> (&*ii)->x); + } + std::sort (vv.begin(), vv.end()); + assert (vv.size() == 301); + for (size_t jj = 0; jj < vv.size(); jj++) { + assert (vv[jj] == (int)jj); + } + + vv.clear(); + for (SG::ArenaPoolAllocator::const_iterator ii = apa.begin(); + ii != apa.end(); + ++ii) + { + vv.push_back (reinterpret_cast<const Payload*> (&*ii)->x); + } + std::sort (vv.begin(), vv.end()); + assert (vv.size() == 301); + for (size_t jj = 0; jj < vv.size(); jj++) { + assert (vv[jj] == (int)jj); + } + + Payload::v.clear(); + apa.reset(); + for (int i=0; i < 400; i++) { + Payload* p = reinterpret_cast<Payload*> (apa.allocate()); + assert (p->y == 0); + ptrs.push_back (p); + p->y = 2*p->x; + } + assert (Payload::v.size() == 0); + assert (apa.stats().elts.inuse == 400); + assert (apa.stats().elts.free == 600); + assert (apa.stats().elts.total == 1000); + assert (apa.stats().blocks.inuse == 4); + assert (apa.stats().blocks.free == 6); + assert (apa.stats().blocks.total == 10); + + Payload::v.clear(); + apa.reserve (550); + assert (apa.stats().elts.inuse == 400); + assert (apa.stats().elts.free == 200); + assert (apa.stats().elts.total == 600); + assert (apa.stats().blocks.inuse == 4); + assert (apa.stats().blocks.free == 2); + assert (apa.stats().blocks.total == 6); + assert (Payload::v.size() == 400); + std::sort (Payload::v.begin(), Payload::v.end()); + for (size_t i=0; i < 100; i++) { + assert (Payload::v[i] == (int)i-799); + } + for (size_t i=100; i < Payload::v.size(); i++) { + assert (Payload::v[i] == (int)i-799); + } + + Payload::v.clear(); + apa.reserve (950); + assert (apa.stats().elts.inuse == 400); + assert (apa.stats().elts.free == 550); + assert (apa.stats().elts.total == 950); + assert (apa.stats().blocks.inuse == 4); + assert (apa.stats().blocks.free == 3); + assert (apa.stats().blocks.total == 7); + assert (Payload::v.size() == 350); + std::sort (Payload::v.begin(), Payload::v.end()); + for (size_t i=0; i < Payload::v.size(); i++) { + assert (Payload::v[i] == (int)i+1000); + } + + Payload::v.clear(); + apa.erase(); + assert (Payload::v.size() == 950); + std::sort (Payload::v.begin(), Payload::v.end()); + for (size_t i=0; i < 550; i++) { + assert (Payload::v[i] == (int)i-1349); + } + for (size_t i=550; i < Payload::v.size(); i++) { + assert (Payload::v[i] == (int)i-949); + } + assert (apa.stats().elts.inuse == 0); + assert (apa.stats().elts.free == 0); + assert (apa.stats().elts.total == 0); + assert (apa.stats().blocks.inuse == 0); + assert (apa.stats().blocks.free == 0); + assert (apa.stats().blocks.total == 0); +} + + +void test2() +{ + Payload::v.clear(); + SG::ArenaPoolAllocator apa + (SG::ArenaPoolAllocator::initParams<Payload, true>(100)); + for (int i=0; i < 150; i++) { + apa.allocate(); + } + assert (Payload::v.size() == 200); + SG::ArenaPoolAllocator::pointer p = apa.allocate(); + assert (Payload::v.size() == 200); + for (int i=0; i < 150; i++) { + apa.allocate(); + } + assert (Payload::v.size() == 400); + assert (apa.stats().elts.inuse == 301); + assert (apa.stats().elts.free == 99); + assert (apa.stats().elts.total == 400); + assert (apa.stats().blocks.inuse == 4); + assert (apa.stats().blocks.free == 0); + assert (apa.stats().blocks.total == 4); + + size_t elt_size = apa.params().eltSize; + size_t block_ov = SG::ArenaBlock::overhead(); + + apa.resetTo (p); + + assert (apa.stats().elts.inuse == 150); + assert (apa.stats().elts.free == 250); + assert (apa.stats().elts.total == 400); + assert (apa.stats().blocks.inuse == 2); + assert (apa.stats().blocks.free == 2); + assert (apa.stats().blocks.total == 4); + + assert (apa.stats().bytes.inuse == (150 * elt_size + 2 * block_ov)); + assert (apa.stats().bytes.free == (250 * elt_size + 2 * block_ov)); + assert (apa.stats().bytes.total == (400 * elt_size + 4 * block_ov)); +} + + +int main() +{ + test1(); + test2(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaPoolSTLAllocator_test.cxx b/Control/AthAllocators/test/ArenaPoolSTLAllocator_test.cxx new file mode 100644 index 0000000000000000000000000000000000000000..050e8d6c399b65fca5c0cb29ebe1a5c9a85956bd --- /dev/null +++ b/Control/AthAllocators/test/ArenaPoolSTLAllocator_test.cxx @@ -0,0 +1,318 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaPoolSTLAllocator_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/ArenaPoolAllocator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Jul, 2008 + * @brief Regression tests for ArenaPoolSTLAllocator. + */ + + +#undef NDEBUG +#include "AthAllocators/ArenaPoolSTLAllocator.h" +#include "CxxUtils/unordered_map.h" +#include "boost/assign/list_of.hpp" +#include <vector> +#include <cassert> +#include <iostream> + +using boost::assign::list_of; + + + +//========================================================================== + +struct Payload +{ + Payload(int = 0); + Payload(const Payload& p); + ~Payload(); + void clear(); + + int x; + int y; + static int n; + static std::vector<int> v; +}; + +Payload::Payload(int the_y) +{ + x = n++; + y = the_y; + v.push_back (x); +} + +Payload::Payload (const Payload& p) + : x (p.x), + y (p.y) +{ + v.push_back (x); +} + + +Payload::~Payload() +{ + v.push_back (-x); +} + +void Payload::clear () +{ + y = 0; +} + +int Payload::n = 0; +std::vector<int> Payload::v; + +//========================================================================== + +// Test generic specialization. +void test1() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test1\n"; + + SG::ArenaPoolSTLAllocator<Payload> a1; + assert (a1.nblock() == 1000); + assert (a1.name() == ""); + + SG::ArenaPoolSTLAllocator<Payload> a2 (100, "a2"); + assert (a2.nblock() == 100); + assert (a2.name() == "a2"); + + SG::ArenaPoolSTLAllocator<Payload*, int> a3 (100, "a3"); + assert (a3.nblock() == 100); + assert (a3.name() == "a3"); + + SG::ArenaPoolSTLAllocator<Payload, int> a4 (a3); + assert (a4.nblock() == 100); + assert (a4.name() == "a3"); + assert (a4.poolptr() != 0); + + { + Payload p; + Payload& pr = p; + const Payload& pcr = p; + assert (a4.address (pr) == &p); + assert (a4.address (pcr) == &p); + } + assert (Payload::n == 1); + assert (Payload::v.size() == 2); + Payload::v.clear(); + + std::vector<Payload*> pv; + for (int i=0; i < 10; i++) + pv.push_back (a4.allocate (1)); + + assert (Payload::n == 1); + assert (Payload::v.size() == 0); + + assert (a4.max_size() == 1); + + a4.construct (pv[0], Payload(10)); + a4.destroy (pv[0]); + + assert (Payload::n == 2); + std::vector<int> exp1 = list_of(1)(1)(-1)(-1); + assert (Payload::v == exp1); + Payload::v.clear(); + + for (int i=0; i < 10; i++) { + if (i > 0) + assert (pv[i] != pv[i-1]); + a4.deallocate (pv[i], 1); + } + + assert (a4.stats().elts.inuse == 10); + assert (a4.stats().elts.total == 100); + + a4.reset(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 100); + + a4.erase(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 0); + + a4.reserve(5000); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 5000); + + assert (Payload::n == 2); + assert (Payload::v.size() == 0); +} + + +// Test pointer specialization. +void test2() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test2\n"; + + SG::ArenaPoolSTLAllocator<Payload*, int> a1; + assert (a1.nblock() == 1000); + assert (a1.name() == ""); + assert (a1.poolptr() == 0); + + SG::ArenaPoolSTLAllocator<Payload*, int> a2 (100, "a2"); + assert (a2.nblock() == 100); + assert (a2.name() == "a2"); + assert (a2.poolptr() == 0); + + a2.reset(); + a2.erase(); + a2.reserve(10); + assert (a2.stats().elts.total == 0); + + SG::ArenaPoolSTLAllocator<Payload, int> a3 (500, "a3"); + a3.reserve (1000); + SG::ArenaPoolSTLAllocator<Payload*, int> a4 (a3); + assert (a4.nblock() == 500); + assert (a4.name() == "a3"); + assert (a4.poolptr() == a3.poolptr()); + + (void)a3.allocate (1); + assert (a3.stats().elts.inuse == 1); + assert (a3.stats().elts.total == 1000); + + assert (a4.stats().elts.inuse == 1); + assert (a4.stats().elts.total == 1000); + assert (&a3.stats() == &a4.stats()); + + a4.reset(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + a4.erase(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 0); + + a4.reserve(1000); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + Payload** p = a4.allocate (2, 0); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + a4.deallocate (p, 2); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + assert (Payload::n == 0); + assert (Payload::v.size() == 0); +} + + +// Test vetoed specialization. +void test3() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test3\n"; + + SG::ArenaPoolSTLAllocator<int, int> a1; + assert (a1.nblock() == 1000); + assert (a1.name() == ""); + assert (a1.poolptr() == 0); + + SG::ArenaPoolSTLAllocator<int, int> a2 (100, "a2"); + assert (a2.nblock() == 100); + assert (a2.name() == "a2"); + assert (a2.poolptr() == 0); + + a2.reset(); + a2.erase(); + a2.reserve(10); + assert (a2.stats().elts.total == 0); + + SG::ArenaPoolSTLAllocator<Payload, int> a3 (500, "a3"); + a3.reserve (1000); + SG::ArenaPoolSTLAllocator<int> a4 (a3); + assert (a4.nblock() == 500); + assert (a4.name() == "a3"); + assert (a4.poolptr() == a3.poolptr()); + + (void)a3.allocate (1); + assert (a3.stats().elts.inuse == 1); + assert (a3.stats().elts.total == 1000); + + assert (a4.stats().elts.inuse == 1); + assert (a4.stats().elts.total == 1000); + assert (&a3.stats() == &a4.stats()); + + a4.reset(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + a4.erase(); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 0); + + a4.reserve(1000); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + int* p = a4.allocate (2, 0); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + a4.deallocate (p, 2); + assert (a4.stats().elts.inuse == 0); + assert (a4.stats().elts.total == 1000); + + assert (Payload::n == 0); + assert (Payload::v.size() == 0); +} + + +// In-situ test. +void test4() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test4\n"; + + typedef SG::unordered_map<int, int, SG::hash<int>, std::equal_to<int>, + SG::ArenaPoolSTLAllocator<std::pair<const int, int> > > map_t; + + map_t::allocator_type allo (500, "allo"); + map_t map (10, map_t::hasher(), map_t::key_equal(), allo); + + for (int i = 0; i < 10; i++) + map[i] = i; + + assert (map.size() == 10); + assert (map.get_allocator().stats().elts.total == 500); + assert (map.get_allocator().stats().elts.inuse == 10); + + map.clear(); + assert (map.size() == 0); + assert (map.get_allocator().stats().elts.total == 500); + assert (map.get_allocator().stats().elts.inuse == 10); + + map.get_allocator().reset(); + assert (map.get_allocator().stats().elts.total == 500); + assert (map.get_allocator().stats().elts.inuse == 0); + + assert (Payload::n == 0); + assert (Payload::v.size() == 0); +} + + +int main() +{ + test1(); + test2(); + test3(); + test4(); + return 0; +} diff --git a/Control/AthAllocators/test/ArenaSharedHeapSTLAllocator_test.cxx b/Control/AthAllocators/test/ArenaSharedHeapSTLAllocator_test.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ef3025b1956344c35a5d74a54ecf18e1e6140abc --- /dev/null +++ b/Control/AthAllocators/test/ArenaSharedHeapSTLAllocator_test.cxx @@ -0,0 +1,283 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: ArenaSharedHeapSTLAllocator_test.cxx 470825 2011-11-25 23:20:57Z ssnyder $ +/** + * @file AthAllocators/test/ArenaSharedHeapSTLAllocator_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Nov 2011 + * @brief Regression tests for ArenaSharedHeapSTLAllocator. + */ + + +#undef NDEBUG +#include "AthAllocators/ArenaSharedHeapSTLAllocator.h" +#include "AthAllocators/ArenaBlock.h" +#include "boost/assign/list_of.hpp" +#include <list> +#include <vector> +#include <cassert> +#include <iostream> + +using boost::assign::list_of; + + + +//========================================================================== + +struct Payload +{ + Payload(int = 0); + Payload(const Payload& p); + ~Payload(); + void clear(); + + int x; + int y; + static int n; + static std::vector<int> v; +}; + +Payload::Payload(int the_y) +{ + x = n++; + y = the_y; + v.push_back (x); +} + +Payload::Payload (const Payload& p) + : x (p.x), + y (p.y) +{ + v.push_back (x); +} + + +Payload::~Payload() +{ + v.push_back (-x); +} + +void Payload::clear () +{ + y = 0; +} + +int Payload::n = 0; +std::vector<int> Payload::v; + + +struct Payload2 : public Payload +{ + Payload2() {} + Payload2(int y) : Payload(y) {} +}; + +//========================================================================== + +// Test generic specialization. +void test1() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test1\n"; + + SG::ArenaSharedHeapSTLAllocator<Payload> a1; + assert (a1.nblock() == 1000); + assert (a1.name() == "::ArenaSharedHeapSTLAllocator<Payload>"); + + SG::ArenaSharedHeapSTLAllocator<Payload> a2 (100, "a2"); + assert (a2.nblock() == 100); + assert (a2.name() == "a2::ArenaSharedHeapSTLAllocator<Payload>"); + + { + Payload p; + Payload& pr = p; + const Payload& pcr = p; + assert (a2.address (pr) == &p); + assert (a2.address (pcr) == &p); + } + assert (Payload::n == 1); + assert (Payload::v.size() == 2); + Payload::v.clear(); + + std::vector<Payload*> pv; + for (int i=0; i < 10; i++) + pv.push_back (a2.allocate (1)); + + assert (Payload::n == 1); + assert (Payload::v.size() == 0); + + assert (a2.max_size() == 1); + + a2.construct (pv[0], Payload(10)); + a2.destroy (pv[0]); + + assert (Payload::n == 2); + std::vector<int> exp1 = list_of(1)(1)(-1)(-1); + assert (Payload::v == exp1); + Payload::v.clear(); + + for (int i=0; i < 9; i++) { + if (i > 0) + assert (pv[i] != pv[i-1]); + a2.deallocate (pv[i], 1); + } + + assert (a2.stats().elts.inuse == 1); + assert (a2.stats().elts.total == 100); + + a2.reset(); + assert (a2.stats().elts.inuse == 0); + assert (a2.stats().elts.total == 100); + + a2.erase(); + assert (a2.stats().elts.inuse == 0); + assert (a2.stats().elts.total == 0); + + a2.reserve(5000); + assert (a2.stats().elts.inuse == 0); + assert (a2.stats().elts.total == 5000); + + assert (Payload::n == 2); + assert (Payload::v.size() == 0); + + SG::ArenaSharedHeapSTLAllocator<Payload> a3 (a2); + assert (a2.nblock() == 100); + assert (a2.name() == "a2::ArenaSharedHeapSTLAllocator<Payload>"); + + Payload* p1 = a2.allocate (1); + assert (a2.stats().elts.inuse == 1); + assert (a2.stats().elts.total == 5000); + + Payload* p2 = a3.allocate (1); + assert (a3.stats().elts.inuse == 2); + assert (a3.stats().elts.total == 5000); + + SG::ArenaSharedHeapSTLAllocator<int> a4 (a2); + assert (a4.nblock() == 100); + assert (a4.name() == "a2::ArenaSharedHeapSTLAllocator<int>"); + + int* p3 = a4.allocate(1); + assert (a3.stats().elts.inuse == 2); + assert (a3.stats().elts.total == 5000); + assert (a4.stats().elts.inuse == 1); + assert (a4.stats().elts.total == 100); + + a2.deallocate (p1, 1); + a3.deallocate (p2, 1); + a4.deallocate (p3, 1); + } + + +// Test deallocation. +void test2() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test2\n"; + + //Payload* p1; + //Payload2* p2; + + { + SG::ArenaSharedHeapSTLAllocator<Payload> a1; + SG::ArenaSharedHeapSTLAllocator<Payload2> a2 (a1); + + a1.allocate(1); + a2.allocate(1); + } +} + + +// In-situ test. +void test3() +{ + Payload::v.clear(); + Payload::n = 0; + + std::cout << "test3\n"; + + typedef std::list<int, SG::ArenaSharedHeapSTLAllocator<int> > list_t; + + list_t::allocator_type allo (500, "allo"); + list_t list (allo); + + for (int i = 0; i < 10; i++) + list.push_back (i); + + assert (list.size() == 10); + SG::ArenaAllocatorBase::Stats stats; + stats = list.get_allocator().totstats(); + assert (stats.elts.total == 500); + assert (stats.elts.inuse == 10); + + for (list_t::iterator i = list.begin(); + i != list.end(); + ++i) + { + i = list.erase (i); + if (i == list.end()) break; + } + + assert (list.size() == 5); + stats = list.get_allocator().totstats(); + assert (stats.elts.total == 500); + assert (stats.elts.inuse == 5); + + list_t list2 (allo); + list2.push_back (10); + stats = list2.get_allocator().totstats(); + assert (stats.elts.inuse == 6); + + list_t list3 (list2); + stats = list2.get_allocator().totstats(); + assert (stats.elts.inuse == 7); + + list.clear(); + assert (list.size() == 0); + stats = list.get_allocator().totstats(); + assert (stats.elts.total == 500); + assert (stats.elts.inuse == 2); + + list2.clear(); + stats = list.get_allocator().totstats(); + assert (stats.elts.inuse == 1); + + list3.clear(); + stats = list.get_allocator().totstats(); + assert (stats.elts.inuse == 0); + + list.get_allocator().reset(); + stats = list.get_allocator().totstats(); + assert (stats.elts.total == 500); + assert (stats.elts.inuse == 0); + + list.push_back(1); + stats = list.get_allocator().totstats(); + assert (stats.elts.inuse == 1); + + list2 = list; + stats = list.get_allocator().totstats(); + assert (stats.elts.inuse == 2); + + list.swap(list2); + stats = list.get_allocator().totstats(); + assert (stats.elts.inuse == 2); + + assert (Payload::n == 0); + assert (Payload::v.size() == 0); +} + + +int main() +{ + test1(); + test2(); + test3(); + assert (SG::ArenaBlock::nactive() == 0); + return 0; +} diff --git a/Control/AthAllocators/test/Arena_test.cxx b/Control/AthAllocators/test/Arena_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..632d1bf17239b00e7ef45e9f65c9e242c218273a --- /dev/null +++ b/Control/AthAllocators/test/Arena_test.cxx @@ -0,0 +1,102 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// $Id: Arena_test.cxx 470529 2011-11-24 23:54:22Z ssnyder $ +/** + * @file AthAllocators/test/Arena_test.cxx + * @author scott snyder <snyder@bnl.gov> + * @date May, 2007 + * @brief Regression tests for Arena. + */ + +#undef NDEBUG +#include "AthAllocators/Arena.h" +#include "AthAllocators/ArenaHeader.h" +#include "AthAllocators/ArenaHeaderGaudiClear.h" +#include "AthAllocators/ArenaAllocatorBase.h" +#include "AthAllocators/ArenaAllocatorCreator.h" +#include "AthAllocators/ArenaAllocatorRegistry.h" +#include <cassert> +#include <sstream> + + +int xxx = 0; +class Alloc + : public SG::ArenaAllocatorBase +{ +public: + Alloc(int x); + virtual void reset() { xxx += m_x; } + virtual void erase() { xxx += 2*m_x; } + virtual void reserve (size_t /*size*/) {} + virtual const SG::ArenaAllocatorBase::Stats& stats() const + { return m_stats; } + virtual const std::string& name() const { return m_name; } +private: + std::string m_name; + int m_x; + SG::ArenaAllocatorBase::Stats m_stats; +}; + +Alloc::Alloc (int x) + : m_x (x) +{ + m_stats.bytes.inuse = x; + m_stats.bytes.free = 2*x; + m_stats.bytes.total = 3*x; + + std::ostringstream os; + os << "alloc" << x; + m_name = os.str(); +} + +class Creator + : public SG::ArenaAllocatorCreator +{ +public: + Creator (int x) : m_x (x) {} + virtual SG::ArenaAllocatorBase* create() { return new Alloc (m_x); } +private: + int m_x; +}; + +void test1() +{ + SG::ArenaHeader head; + SG::Arena a ("a", &head); + { + SG::Arena::Push p (a); + SG::ArenaAllocatorRegistry* reg = + SG::ArenaAllocatorRegistry::instance(); + assert (reg->registerCreator ("1", new Creator(1)) == 0); + assert (reg->registerCreator ("2", new Creator(2)) == 1); + assert (head.allocator(0)->stats().bytes.inuse == 1); + assert (head.allocator(1)->stats().bytes.inuse == 2); + + assert (a.stats().bytes.inuse == 3); + assert (a.stats().bytes.free == 6); + assert (a.stats().bytes.total == 9); + + std::ostringstream os; + a.report (os); + assert (os.str() == "Elts InUse/Free/Total Bytes InUse/Free/Total Blocks InUse/Free/Total\n\ + 0/ 0/ 0 1/ 2/ 3 0/ 0/ 0 alloc1\n\ + 0/ 0/ 0 2/ 4/ 6 0/ 0/ 0 alloc2\n"); + + assert (xxx == 0); + a.reset(); + assert (xxx == 3); + a.erase(); + assert (xxx == 9); + } +} + + +int main() +{ + SG::ArenaHeaderGaudiClear::disable(); + test1(); + return 0; +} + diff --git a/Control/AthAllocators/test/AthAllocators.xml b/Control/AthAllocators/test/AthAllocators.xml new file mode 100755 index 0000000000000000000000000000000000000000..df18d25030babd6f3468c9b1d7875b77a8860f1e --- /dev/null +++ b/Control/AthAllocators/test/AthAllocators.xml @@ -0,0 +1,16 @@ +<?xml version="1.0"?> +<atn> + <TEST name="AthAllocatorsTest" type="makecheck" suite="Examples"> + <package>Control/AthAllocators</package> + <timelimit>40</timelimit> + <author> Paolo Calafiura </author> + <mailto> pcalafiura@lbl.gov, snyder@fnal.gov, binet@cern.ch</mailto> + <expectations> + <errorMessage>Athena exited abnormally</errorMessage> + <errorMessage>differ</errorMessage> + <warningMessage> # WARNING_MESSAGE : post.sh> ERROR</warningMessage> + <successMessage>check ok</successMessage> + <returnValue>0</returnValue> + </expectations> + </TEST> +</atn> diff --git a/Control/AthAllocators/test/DataPool_test.cxx b/Control/AthAllocators/test/DataPool_test.cxx new file mode 100755 index 0000000000000000000000000000000000000000..b6d91e12bcf0bdd65e8da7ee54d4b73363e5af64 --- /dev/null +++ b/Control/AthAllocators/test/DataPool_test.cxx @@ -0,0 +1,143 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#undef NDEBUG + +#include "AthAllocators/DataPool.h" +#include "GaudiKernel/ISvcLocator.h" +#include "GaudiKernel/IChronoStatSvc.h" +#include "TestTools/initGaudi.h" + +#include <cassert> +#include <iostream> +#include <string> +#include <vector> + +using namespace std; + +class Fluff +{ + public: + virtual ~Fluff() { } + Fluff() : m_int(1), m_float(-379.456f), + m_string("this is the Fluff struct") + { + } + + Fluff(const Fluff& f) + { + m_int = f.m_int; + m_float = f.m_float; + m_string = f.m_string; + } + + void setPar(int j) { m_int = j; } + int value() const { return m_int; } + + private: + + int m_int; + float m_float; + string m_string; + +}; + +int main () +{ + + ISvcLocator* pSvcLoc; + if (!Athena_test::initGaudi("DataPool_test.txt", pSvcLoc)) + { + std::cerr << " This test cannot be run without init Gaudi" << endl; + } + assert(pSvcLoc); + + IChronoStatSvc* p_svc; + if ((pSvcLoc->service("ChronoStatSvc", p_svc)).isSuccess()) + { + p_svc->chronoStart("ChronoStatSvc"); + } + + std::cout << " *** DataPool test in progress: " << std::endl; + + // ask for 10 Fluff's in memory, but default is 1024! + DataPool<Fluff>* df = new DataPool<Fluff>(10); + DataPool<Fluff>::const_iterator iter = df->begin(); + DataPool<Fluff>::const_iterator iend = df->end(); + assert(iter == iend); // because pool ain't accessed yet. + assert (0 == df->allocated()); + // check pool capacity: default is 1024 even though we asked for 10 + assert (1024 == df->capacity()); + + // Now use the first 5 of these Fluff's + for (int j = 10; j < 15; j++) + { + Fluff* f = df->nextElementPtr(); + f->setPar(j); + } + assert (5 == df->allocated()); + + // loop again and check whether the first five are set: + int k = 10; + DataPool<Fluff>::const_iterator iter2 = df->begin(); + DataPool<Fluff>::const_iterator iend2 = df->end(); + for (; iter2 != iend2; iter2++) + { + assert(0 != (*iter2)); + // Note: we iterate backwards... + assert(24-k == (*iter2)->value()); + k++; + } + + + df->reset(); // reset DataPool + DataPool<Fluff>::const_iterator iter3 = df->begin(); + DataPool<Fluff>::const_iterator iend3 = df->end(); + assert (iter3 == iend3); // after reset + assert (0 == df->allocated()); + assert (1024 == df->capacity()); // should be same + + // Now use 1500 of these Fluff's.. should automatically resize + //cout << "You should see a message on automatic increase of pool size" << endl; + + for (int j = 0; j < 1500; j++) + { + Fluff* f = df->nextElementPtr(); + f->setPar(j); + } + + assert(1500 == df->allocated()); // up by 2 automatically + + assert(2048 == df->capacity()); + + // check that resizing to less than m_refCount doesn't work + df->reserve(1000); + assert(2048==df->capacity()); + assert(1500==df->allocated()); + + // check that resizing to less than m_maxRefCount works + // changes related to m_maxRefCount are not visible in capacity() or allocated(). + df->reserve(1600); + + assert(2048==df->capacity()); + assert(1500==df->allocated()); + + // this is test by cheating. We reset the data pool (objects are not deleted + // we go to the memory location and check if all values are still ok. + df->reset(); + for (int j = 0; j < 1500; j++) + { + Fluff* f = static_cast<Fluff*>(df->mem()); + assert(j == f->value()); + } + + // call the pool destructor + delete df; + + cout << " **** DataPool test successfully completed **** " << endl; + p_svc->chronoStop("ChronoStatSvc"); + p_svc->chronoPrint("ChronoStatSvc"); + + return 0; +}