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 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
|
/*!
* \file trc_mem_acc_cache.h
* \brief OpenCSD : Memory accessor cache.
*
* \copyright Copyright (c) 2018, ARM Limited. All Rights Reserved.
*/
/*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ARM_TRC_MEM_ACC_CACHE_H_INCLUDED
#define ARM_TRC_MEM_ACC_CACHE_H_INCLUDED
#include <string>
#include "opencsd/ocsd_if_types.h"
#define MEM_ACC_CACHE_DEFAULT_PAGE_SIZE 2048
#define MEM_ACC_CACHE_DEFAULT_MRU_SIZE 16
#define MEM_ACC_CACHE_PAGE_SIZE_MAX 16384
#define MEM_ACC_CACHE_MRU_SIZE_MAX 256
#define MEM_ACC_CACHE_PAGE_SIZE_MIN 64
#define MEM_ACC_CACHE_MRU_SIZE_MIN 4
#define OCSD_ENV_MEMACC_CACHE_OFF "OPENCSD_MEMACC_CACHE_OFF"
#define OCSD_ENV_MEMACC_CACHE_PG_SIZE "OPENCSD_MEMACC_CACHE_PAGE_SIZE"
#define OCSD_ENV_MEMACC_CACHE_PG_NUM "OPENCSD_MEMACC_CACHE_PAGE_NUM"
class TrcMemAccessorBase;
class ITraceErrorLog;
typedef struct cache_block {
ocsd_vaddr_t st_addr;
uint32_t valid_len;
uint8_t* data;
uint8_t trcID; // trace ID associated with the page
uint32_t use_sequence; // number representing the sequence of allocation to evict oldest page.
} cache_block_t;
// enable define to collect stats for debugging / cache performance tests
// #define LOG_CACHE_STATS
/** class TrcMemAccCache - cache small amounts of data from accessors to speed up decode.
*
* Reduce the need to read files / make callbacks into clients when walking memory images.
*
* Caching is done on a per Core/Trace ID basis - all caches from that ID are invalidated when a context
* switch appears on the core. This means that we do not account for memory spaces in the cache pages as
* these only change via a context switch.
*
* Memory space is used on cache miss if reading data from the underlying accessor (file / callback).
*/
class TrcMemAccCache
{
public:
TrcMemAccCache();
~TrcMemAccCache();
/* cache enabling and usage */
ocsd_err_t enableCaching(bool bEnable);
// optionally error if outside limits - otherwise set to max / min automatically
ocsd_err_t setCacheSizes(const uint16_t page_size, const int nr_pages, const bool err_on_limit = false);
const bool enabled() const { return m_bCacheEnabled; };
const bool enabled_for_size(const uint32_t reqSize) const
{
return (m_bCacheEnabled && (reqSize <= m_mru_page_size));
}
/* cache invalidation */
void invalidateAll();
void invalidateByTraceID(int8_t trcID);
void clearPage(cache_block_t* page);
/** read bytes from cache if possible - load new page if needed from underlying accessor, bail out if data not available */
ocsd_err_t readBytesFromCache(TrcMemAccessorBase *p_accessor, const ocsd_vaddr_t address, const ocsd_mem_space_acc_t mem_space, const uint8_t trcID, uint32_t *numBytes, uint8_t *byteBuffer);
void setErrorLog(ITraceErrorLog *log);
void logAndClearCounts();
/* look for runtime cache tuning vars */
static void getenvMemaccCacheSizes(bool& enable, int& page_size, int& num_pages);
private:
bool blockInCache(const ocsd_vaddr_t address, const uint32_t reqBytes, const uint8_t trcID); // run through each page to look for data.
bool blockInPage(const ocsd_vaddr_t address, const uint32_t reqBytes, const uint8_t trcID);
void logMsg(const std::string &szMsg, ocsd_err_t err = OCSD_OK);
int findNewPage();
void incSequence(); // increment sequence on current block
ocsd_err_t createCaches(); // create caches according to current sizes
void destroyCaches(); // destroy the cache blocks
cache_block_t *m_mru; // cache pages
int m_mru_idx = 0; // in use index - most recently used page
uint16_t m_mru_page_size; // page size
int m_mru_num_pages; // number of pages
uint32_t m_mru_sequence; // allocation & use sequence number
bool m_bCacheEnabled = false;
#ifdef LOG_CACHE_STATS
uint32_t m_hits = 0;
uint32_t m_misses = 0;
uint32_t m_pages = 0;
uint32_t* m_hit_rl = 0;
uint32_t* m_hit_rl_max = 0;
#endif
ITraceErrorLog *m_err_log = 0;
};
inline TrcMemAccCache::TrcMemAccCache() :
m_mru(0), m_mru_sequence(1)
{
/* set default cache sizes */
m_mru_page_size = MEM_ACC_CACHE_DEFAULT_PAGE_SIZE;
m_mru_num_pages = MEM_ACC_CACHE_DEFAULT_MRU_SIZE;
}
inline TrcMemAccCache::~TrcMemAccCache()
{
destroyCaches();
}
inline bool TrcMemAccCache::blockInPage(const ocsd_vaddr_t address, const uint32_t reqBytes, const uint8_t trcID)
{
/* check has data, trcID and mem space */
if ((m_mru[m_mru_idx].trcID != trcID) ||
(m_mru[m_mru_idx].valid_len == 0)
)
return false;
/* check block is in this page */
if ((m_mru[m_mru_idx].st_addr <= address) &&
m_mru[m_mru_idx].st_addr + m_mru[m_mru_idx].valid_len >= (address + reqBytes))
return true;
return false;
}
inline bool TrcMemAccCache::blockInCache(const ocsd_vaddr_t address, const uint32_t reqBytes, const uint8_t trcID)
{
int tests = m_mru_num_pages;
while (tests)
{
if (blockInPage(address, reqBytes, trcID))
return true; // found address in page
#ifdef LOG_CACHE_STATS
// miss counts of current page only - to determine if we hit other page
if (tests == m_mru_num_pages)
m_misses++;
#endif
tests--;
m_mru_idx++;
if (m_mru_idx == m_mru_num_pages)
m_mru_idx = 0;
}
return false;
}
// zero out page parameters rendering it empty
inline void TrcMemAccCache::clearPage(cache_block_t* page)
{
page->use_sequence = 0;
page->st_addr = 0;
page->valid_len = 0;
page->trcID = OCSD_BAD_CS_SRC_ID;
}
#endif // ARM_TRC_MEM_ACC_CACHE_H_INCLUDED
/* End of File trc_mem_acc_cache.h */
|