summaryrefslogtreecommitdiffstats
path: root/vespamalloc/src/vespamalloc/malloc/datasegment.h
blob: cefa961852fdf434cfa3e56c960af5aa6a01e1d4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once

#include <climits>
#include <memory>
#include <vespamalloc/malloc/common.h>
#include <vespamalloc/util/traceutil.h>
#include <vespamalloc/util/stream.h>

namespace vespamalloc {

template<typename MemBlockPtrT>
class DataSegment
{
public:
    using BlockIdT = uint32_t;
    enum { UNMAPPED_BLOCK=-4, UNUSED_BLOCK=-3, FREE_BLOCK=-2, SYSTEM_BLOCK=-1, NUM_ADMIN_CLASSES=4 };
    DataSegment() __attribute__((noinline));
    ~DataSegment() __attribute__((noinline));

    void * getBlock(size_t & oldBlockSize, SizeClassT sc) __attribute__((noinline));
    void returnBlock(void *ptr) __attribute__((noinline));
    SizeClassT sizeClass(const void * ptr)    const { return _blockList[blockId(ptr)].sizeClass(); }
    bool containsPtr(const void * ptr)        const { return blockId(ptr) < BlockCount; }
    size_t getMaxSize(const void * ptr)       const { return _blockList[blockId(ptr)].getMaxSize(); }
    const void * start()                      const { return _osMemory.getStart(); }
    const void * end()                        const { return _osMemory.getEnd(); }
    static SizeClassT adjustedSizeClass(size_t sz)  { return (sz >> 16) + 0x400; }
    static size_t adjustedClassSize(SizeClassT sc)  { return (sc > 0x400) ? (sc - 0x400) << 16 : sc; }
    size_t dataSize()                         const { return (const char*)end() - (const char*)start(); }
    size_t freeSize() const;
    size_t infoThread(FILE * os, int level, uint32_t thread, SizeClassT sct, uint32_t maxThreadId=0) const __attribute__((noinline));
    void info(FILE * os, size_t level) __attribute__((noinline));
    void setupLog(size_t bigMemLogLevel, size_t bigLimit, size_t bigIncrement, size_t allocs2Show)
    {
        _bigSegmentLogLevel = bigMemLogLevel;
        if ((size_t(end()) < _nextLogLimit) || (size_t(end()) < (size_t(start()) + bigLimit))) {
            _nextLogLimit = size_t(start()) + bigLimit;
        }
        _bigIncrement = bigIncrement;
        _allocs2Show = allocs2Show;
        checkAndLogBigSegment();
    }
    void enableThreadSupport() { _mutex.init(); }
    static BlockIdT blockId(const void * ptr)       {
        return (size_t(ptr) - Memory::getMinPreferredStartAddress())/BlockSize;
    }
    static void * fromBlockId(size_t id) {
        return reinterpret_cast<void *>(id*BlockSize + Memory::getMinPreferredStartAddress());
    }
private:
    const char * getAdminClassName(int id) {
        switch (id) {
          case UNMAPPED_BLOCK: return "UNMAPPED";
          case   UNUSED_BLOCK: return "UNUSED";
          case     FREE_BLOCK: return "FREE";
          case   SYSTEM_BLOCK: return "SYSTEM";
          default:             return "UNKNOWN";
        }
    }
    DataSegment(const DataSegment & rhs);
    DataSegment & operator = (const DataSegment & rhs);

    // Allow for 1T heap
    static constexpr size_t BlockSize = 0x200000ul;
    static constexpr BlockIdT BlockCount = 0x80000;

    class BlockT
    {
    public:
        BlockT(SizeClassT szClass = UNUSED_BLOCK, BlockIdT numBlocks = 0)
            : _sizeClass(szClass), _freeChainLength(0), _realNumBlocks(numBlocks)
        { }
        SizeClassT sizeClass()            const { return _sizeClass; }
        BlockIdT realNumBlocks()          const { return _realNumBlocks; }
        BlockIdT freeChainLength()        const { return _freeChainLength; }
        void sizeClass(SizeClassT sc)           { _sizeClass = sc; }
        void realNumBlocks(BlockIdT fc)         { _realNumBlocks = fc; }
        void freeChainLength(BlockIdT fc)       { _freeChainLength = fc; }
        size_t getMaxSize()               const {
            return MemBlockPtrT::unAdjustSize(std::min(MemBlockPtrT::classSize(_sizeClass),
                                                       size_t(_realNumBlocks) * BlockSize));
        }
    private:
        SizeClassT _sizeClass;
        /// Number of blocks free from here and on. For memory reuse, big blocks only.
        BlockIdT _freeChainLength;
        /// Real number of blocks used. Used to avoid rounding for big blocks.
        BlockIdT _realNumBlocks;
    };

    template <int MaxCount>
    class FreeListT {
    public:
        using Index = BlockIdT;
        FreeListT(BlockT * blockList) __attribute__((noinline));
        FreeListT(const FreeListT &) = delete;
        FreeListT & operator =(const FreeListT &) = delete;
        FreeListT(FreeListT &&) = delete;
        FreeListT & operator =(FreeListT &&) = delete;
        ~FreeListT();
        void add(Index startIndex) __attribute__((noinline));
        void * sub(Index numBlocks) __attribute__((noinline));
        Index lastBlock(Index nextBlock) __attribute__((noinline));
        void removeLastBlock() {
            if (_count > 0) {
                _count--;
            }
        }
        Index numFreeBlocks() const;
        void info(FILE * os) __attribute__((noinline));
    private:
        void * linkOut(Index findex, Index left) __attribute__((noinline));
        BlockT *_blockList;
        Index  _count;
        Index  _freeStartIndex[MaxCount];
    };

    void checkAndLogBigSegment() __attribute__((noinline));

    typedef BlockT BlockList[BlockCount];
    typedef FreeListT<BlockCount/2> FreeList;
    OSMemory     _osMemory;
    size_t       _bigSegmentLogLevel;
    size_t       _bigIncrement;
    size_t       _allocs2Show;
    size_t       _unmapSize;

    size_t       _nextLogLimit;
    size_t       _partialExtension;
    Mutex        _mutex;
    BlockList    _blockList;
    FreeList     _freeList;
    FreeList     _unMappedList;
};

}