xref: /aosp_15_r20/external/OpenCSD/decoder/source/mem_acc/trc_mem_acc_cache.cpp (revision 02ca8ccacfba7e0df68f3332a95f3180334d6649)
1 /*!
2 * \file       trc_mem_acc_cache.cpp
3 * \brief      OpenCSD : Memory accessor cache.
4 *
5 * \copyright  Copyright (c) 2018, ARM Limited. All Rights Reserved.
6 */
7 
8 /*
9 * Redistribution and use in source and binary forms, with or without modification,
10 * are permitted provided that the following conditions are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the copyright holder nor the names of its contributors
20 * may be used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34 
35 #include <cstring>
36 #include <sstream>
37 #include <iomanip>
38 #include "mem_acc/trc_mem_acc_cache.h"
39 #include "mem_acc/trc_mem_acc_base.h"
40 #include "interfaces/trc_error_log_i.h"
41 #include "common/ocsd_error.h"
42 
43 #ifdef LOG_CACHE_STATS
44 #define INC_HITS_RL(idx) m_hits++; m_hit_rl[m_mru_idx]++;
45 #define INC_MISS() m_misses++;
46 #define INC_PAGES() m_pages++;
47 #define SET_MAX_RL(idx)                         \
48     {                                           \
49         if (m_hit_rl_max[idx] < m_hit_rl[idx])  \
50             m_hit_rl_max[idx] = m_hit_rl[idx];  \
51         m_hit_rl[idx] = 0;                      \
52     }
53 #define INC_RL(idx) m_hit_rl[m_mru_idx]++;
54 #else
55 #define INC_HITS_RL(idx)
56 #define INC_MISS()
57 #define INC_PAGES()
58 #define SET_MAX_RL(idx)
59 #define INC_RL(idx)
60 #endif
61 
62 // uncomment to log cache ops
63 // #define LOG_CACHE_OPS
64 // #define LOG_CACHE_CREATION
65 
createCaches()66 ocsd_err_t TrcMemAccCache::createCaches()
67 {
68     if (m_mru)
69         destroyCaches();
70     m_mru = (cache_block_t*) new (std::nothrow) cache_block_t[m_mru_num_pages];
71     if (!m_mru)
72         return OCSD_ERR_MEM;
73     for (int i = 0; i < m_mru_num_pages; i++) {
74         m_mru[i].data = new (std::nothrow) uint8_t[m_mru_page_size];
75         if (!m_mru[i].data)
76             return OCSD_ERR_MEM;
77         clearPage(&m_mru[i]);
78     }
79 #ifdef LOG_CACHE_STATS
80     m_hit_rl = (uint32_t *) new (std::nothrow) uint32_t[m_mru_num_pages];
81     m_hit_rl_max = (uint32_t*) new (std::nothrow) uint32_t[m_mru_num_pages];
82     if (!m_hit_rl || !m_hit_rl_max)
83         return OCSD_ERR_MEM;
84     for (int j = 0; j < m_mru_num_pages; j++) {
85         m_hit_rl[j] = 0;
86         m_hit_rl_max[j] = 0;
87     }
88 #endif
89 #ifdef LOG_CACHE_CREATION
90     std::ostringstream oss;
91     oss << "MemAcc Caches: Num Pages=" << m_mru_num_pages << "; Page size=" << m_mru_page_size << ";\n";
92     logMsg(oss.str());
93 #endif
94     return OCSD_OK;
95 }
96 
destroyCaches()97 void TrcMemAccCache::destroyCaches()
98 {
99     if (m_mru) {
100         for (int i = 0; i < m_mru_num_pages; i++)
101             delete[] m_mru[i].data;
102         delete[] m_mru;
103         m_mru = 0;
104     }
105 #ifdef LOG_CACHE_STATS
106     if (m_hit_rl)
107         delete[] m_hit_rl;
108     if (m_hit_rl_max)
109         delete[] m_hit_rl_max;
110     m_hit_rl = 0;
111     m_hit_rl_max = 0;
112 #endif
113 
114 }
115 
getenvMemaccCacheSizes(bool & enable,int & page_size,int & num_pages)116 void TrcMemAccCache::getenvMemaccCacheSizes(bool& enable, int& page_size, int& num_pages)
117 {
118     char* env_var;
119     long env_val;
120 
121     /* set defaults */
122     enable = true;
123     page_size = MEM_ACC_CACHE_DEFAULT_PAGE_SIZE;
124     num_pages = MEM_ACC_CACHE_DEFAULT_MRU_SIZE;
125 
126     /* check environment for adjustments */
127 
128     /* override the default on switch? if so no need to look further */
129     if ((env_var = getenv(OCSD_ENV_MEMACC_CACHE_OFF)) != NULL)
130     {
131         enable = false;
132         return;
133     }
134 
135     /* check for tweak in page size */
136     if ((env_var = getenv(OCSD_ENV_MEMACC_CACHE_PG_SIZE)) != NULL)
137     {
138         env_val = strtol(env_var, NULL, 0);
139         /*
140          * if no valid conversion then env_val = 0,
141          * otherwise set val and allow TrcMemAccCache::setCacheSizes
142          * fn to ensure the value in bounds
143          */
144         if (env_val > 0)
145             page_size = (int)env_val;
146     }
147 
148     /* check for tweak in number of pages */
149     if ((env_var = getenv(OCSD_ENV_MEMACC_CACHE_PG_NUM)) != NULL)
150     {
151         env_val = strtol(env_var, NULL, 0);
152         /*
153          * if no valid conversion then env_val = 0,
154          * otherwise set val and allow TrcMemAccCache::setCacheSizes
155          * fn to ensure the value in bounds
156          */
157         if (env_val > 0)
158             num_pages = (int)env_val;
159     }
160 
161 }
162 
enableCaching(bool bEnable)163 ocsd_err_t TrcMemAccCache::enableCaching(bool bEnable)
164 {
165     ocsd_err_t err = OCSD_OK;
166 
167     if (bEnable)
168     {
169         // don't create caches if they are done already.
170         if (!m_mru)
171             err = createCaches();
172     }
173     else
174         destroyCaches();
175     m_bCacheEnabled = bEnable;
176 
177 #ifdef LOG_CACHE_CREATION
178     std::ostringstream oss;
179     oss << "MemAcc Caches: " << (bEnable ? "Enabled" : "Disabled") << ";\n";
180     logMsg(oss.str());
181 #endif
182 
183     return err;
184 }
185 
setCacheSizes(const uint16_t page_size,const int nr_pages,const bool err_on_limit)186 ocsd_err_t TrcMemAccCache::setCacheSizes(const uint16_t page_size, const int nr_pages, const bool err_on_limit /*= false*/)
187 {
188     // do't re-create what we already have.
189     if (m_mru &&
190         (m_mru_num_pages == nr_pages) &&
191         (m_mru_page_size == page_size))
192         return OCSD_OK;
193 
194     /* remove any caches with the existing sizes */
195     destroyCaches();
196 
197     /* set page size within Max/Min range */
198     if (page_size > MEM_ACC_CACHE_PAGE_SIZE_MAX)
199     {
200         if (err_on_limit)
201         {
202             logMsg("MemAcc Caching: page size too large", OCSD_ERR_INVALID_PARAM_VAL);
203             return OCSD_ERR_INVALID_PARAM_VAL;
204         }
205         m_mru_page_size = MEM_ACC_CACHE_PAGE_SIZE_MAX;
206     }
207     else if (page_size < MEM_ACC_CACHE_PAGE_SIZE_MIN)
208     {
209         if (err_on_limit)
210         {
211             logMsg("MemAcc Caching: page size too small", OCSD_ERR_INVALID_PARAM_VAL);
212             return OCSD_ERR_INVALID_PARAM_VAL;
213         }
214         m_mru_page_size = MEM_ACC_CACHE_PAGE_SIZE_MIN;
215     }
216     else
217         m_mru_page_size = page_size;
218 
219     /* set num pages within max/min range */
220     if (nr_pages > MEM_ACC_CACHE_MRU_SIZE_MAX)
221     {
222         if (err_on_limit)
223         {
224             logMsg("MemAcc Caching: number of pages too large", OCSD_ERR_INVALID_PARAM_VAL);
225             return OCSD_ERR_INVALID_PARAM_VAL;
226         }
227         m_mru_num_pages = MEM_ACC_CACHE_MRU_SIZE_MAX;
228     }
229     else if (nr_pages < MEM_ACC_CACHE_MRU_SIZE_MIN)
230     {
231         if (err_on_limit)
232         {
233             logMsg("MemAcc Caching: number of pages too small", OCSD_ERR_INVALID_PARAM_VAL);
234             return OCSD_ERR_INVALID_PARAM_VAL;
235         }
236         m_mru_num_pages = MEM_ACC_CACHE_MRU_SIZE_MIN;
237     }
238     else
239         m_mru_num_pages = nr_pages;
240 
241     /* re-create with new sizes */
242     return createCaches();
243 }
244 
245 /* return index of unused page, or oldest used page by sequence number */
findNewPage()246 int TrcMemAccCache::findNewPage()
247 {
248     uint32_t oldest_seq;
249     int current_idx, oldest_idx;
250 #ifdef LOG_CACHE_OPS
251     std::ostringstream oss;
252 #endif
253 
254     /* set up search indexes and check the current search index has not wrapped. */
255     current_idx = m_mru_idx + 1;
256     oldest_idx = m_mru_idx;
257     oldest_seq = 0;
258     if (current_idx >= m_mru_num_pages)
259         current_idx = 0;
260 
261     /* search forwards from m_mru_idx + 1 until we wrap and hit the index again */
262     while (current_idx != m_mru_idx) {
263         if (m_mru[current_idx].use_sequence == 0) {
264 #ifdef LOG_CACHE_OPS
265             oss << "TrcMemAccCache:: ALI-allocate clean page:  [page: " << std::dec << current_idx << "]\n";
266             logMsg(oss.str());
267 #endif
268             return current_idx;
269         }
270 
271         // if we find a page with a lower use sequence, that is older.
272         if ((oldest_seq == 0) || (oldest_seq > m_mru[current_idx].use_sequence)) {
273             oldest_seq = m_mru[current_idx].use_sequence;
274             oldest_idx = current_idx;
275         }
276 
277         current_idx++;
278 
279         // wrap around?
280         if (current_idx >= m_mru_num_pages)
281             current_idx = 0;
282     }
283 #ifdef LOG_CACHE_OPS
284     oss << "TrcMemAccCache:: ALI-evict and allocate old page:  [page: " << std::dec << oldest_idx << "]\n";
285     logMsg(oss.str());
286 #endif
287     return oldest_idx;
288 }
289 
incSequence()290 void TrcMemAccCache::incSequence()
291 {
292     m_mru[m_mru_idx].use_sequence = m_mru_sequence++;
293     if (m_mru_sequence == 0) {
294         // wrapped which throws out the oldest algorithm - oldest will now appear newer - so not evicted.
295         // arbitrarily re-sequence all in use..
296         m_mru_sequence = 1;
297         for (int i = 0; i < m_mru_num_pages; i++)
298             if (m_mru[i].use_sequence != 0)
299                 m_mru[i].use_sequence = m_mru_sequence++;
300 
301         // ensure newest still newest...
302         m_mru[m_mru_idx].use_sequence = m_mru_sequence++;
303     }
304 }
305 
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)306 ocsd_err_t TrcMemAccCache::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)
307 {
308     uint32_t bytesRead = 0, reqBytes = *numBytes;
309     ocsd_err_t err = OCSD_OK;
310 
311 
312 #ifdef LOG_CACHE_OPS
313     std::ostringstream oss;
314     std::string memSpaceStr;
315 #endif
316 
317     if (m_bCacheEnabled)
318     {
319         if (blockInCache(address, reqBytes, trcID))
320         {
321             bytesRead = reqBytes;
322             memcpy(byteBuffer, &m_mru[m_mru_idx].data[address - m_mru[m_mru_idx].st_addr], reqBytes);
323             incSequence();
324 #ifdef LOG_CACHE_OPS
325             oss << "TrcMemAccCache:: hit {page: " << std::dec << m_mru_idx << "; seq: " << m_mru[m_mru_idx].use_sequence << " CSID: " << std::hex << (int)m_mru[m_mru_idx].trcID;
326             oss << "} [addr:0x" << std::hex << address << ", bytes: " << std::dec << reqBytes << "]\n";
327             logMsg(oss.str());
328 #endif
329             INC_HITS_RL(m_mru_idx);
330         }
331         else
332         {
333 #ifdef LOG_CACHE_OPS
334             oss << "TrcMemAccCache:: miss [addr:0x" << std::hex << address << ", bytes: " << std::dec << reqBytes << "]\n";
335             logMsg(oss.str());
336 #endif
337             /* need a new cache page - check the underlying accessor for the data */
338             m_mru_idx = findNewPage();
339             m_mru[m_mru_idx].valid_len = p_accessor->readBytes(address, mem_space, trcID, m_mru_page_size, &m_mru[m_mru_idx].data[0]);
340 
341             /* check return length valid - v bad if return length more than request */
342             if (m_mru[m_mru_idx].valid_len > m_mru_page_size)
343             {
344                 m_mru[m_mru_idx].valid_len = 0; // set to nothing returned.
345                 err = OCSD_ERR_MEM_ACC_BAD_LEN;
346             }
347 
348             if (m_mru[m_mru_idx].valid_len > 0)
349             {
350                 // got some data - so save the details
351                 m_mru[m_mru_idx].st_addr = address;
352                 m_mru[m_mru_idx].trcID = trcID;
353                 incSequence();
354 
355                 // log the run length hit counts
356                 SET_MAX_RL(m_mru_idx);
357 
358 #ifdef LOG_CACHE_OPS
359                 TrcMemAccessorBase::getMemAccSpaceString(memSpaceStr, mem_space);
360                 oss.str("");
361                 oss << "TrcMemAccCache:: ALI-load {page: " << std::dec << m_mru_idx << "; seq: " << m_mru[m_mru_idx].use_sequence << " CSID: " << std::hex << (int)m_mru[m_mru_idx].trcID;
362                 oss << "} [mem space: " << memSpaceStr << ", addr:0x" << std::hex << address << ", bytes: " << std::dec << m_mru[m_mru_idx].valid_len << "]\n";
363                 logMsg(oss.str());
364 #endif
365                 INC_PAGES();
366 
367                 if (blockInPage(address, reqBytes, trcID)) /* check we got the data we needed */
368                 {
369                     bytesRead = reqBytes;
370                     memcpy(byteBuffer, &m_mru[m_mru_idx].data[address - m_mru[m_mru_idx].st_addr], reqBytes);
371                     INC_RL(m_mru_idx);
372                 }
373                 else
374                 {
375 #ifdef LOG_CACHE_OPS
376                     oss.str("");
377                     oss << "TrcMemAccCache:: miss-after-load {page: " << std::dec << m_mru_idx << " } [addr:0x" << std::hex << address << ", bytes: " << std::dec << m_mru[m_mru_idx].valid_len << "]\n";
378                     logMsg(oss.str());
379 #endif
380                     INC_MISS();
381                 }
382             }
383         }
384     }
385     *numBytes = bytesRead;
386     return err;
387 }
388 
invalidateAll()389 void TrcMemAccCache::invalidateAll()
390 {
391 #ifdef LOG_CACHE_OPS
392     std::ostringstream oss;
393     oss << "TrcMemAccCache:: ALI-invalidate All\n";
394     logMsg(oss.str());
395 #endif
396 
397     for (int i = 0; i < m_mru_num_pages; i++)
398         clearPage(&m_mru[i]);
399     m_mru_idx = 0;
400 }
401 
invalidateByTraceID(int8_t trcID)402 void TrcMemAccCache::invalidateByTraceID(int8_t trcID)
403 {
404 #ifdef LOG_CACHE_OPS
405     std::ostringstream oss;
406     oss << "TrcMemAccCache:: ALI-invalidate by ID request {CSID: " << std::hex << (int)trcID << "}\n";
407     logMsg(oss.str());
408 #endif
409 
410     for (int i = 0; i < m_mru_num_pages; i++)
411     {
412         if (m_mru[i].trcID == trcID)
413         {
414 #ifdef LOG_CACHE_OPS
415             oss.str("");
416             oss << "TrcMemAccCache:: ALI-invalidate page {page: " << std::dec << i << "; seq: " << m_mru[i].use_sequence << " CSID: " << std::hex << (int)m_mru[i].trcID;
417             oss << "} [addr:0x" << std::hex << m_mru[i].st_addr << ", bytes: " << std::dec << m_mru[i].valid_len << "]\n";
418             logMsg(oss.str());
419 #endif
420             clearPage(&m_mru[i]);
421         }
422     }
423 }
424 
logMsg(const std::string & szMsg,ocsd_err_t err)425 void TrcMemAccCache::logMsg(const std::string &szMsg, ocsd_err_t err /*= OCSD_OK */ )
426 {
427     if (m_err_log)
428     {
429         if (err == OCSD_OK)
430             m_err_log->LogMessage(ITraceErrorLog::HANDLE_GEN_INFO, OCSD_ERR_SEV_INFO, szMsg);
431         else
432         {
433             ocsdError ocsd_err( OCSD_ERR_SEV_ERROR, err, szMsg);
434             m_err_log->LogError(ITraceErrorLog::HANDLE_GEN_INFO, &ocsd_err);
435         }
436     }
437 }
438 
setErrorLog(ITraceErrorLog * log)439 void TrcMemAccCache::setErrorLog(ITraceErrorLog *log)
440 {
441     m_err_log = log;
442 }
443 
logAndClearCounts()444 void TrcMemAccCache::logAndClearCounts()
445 {
446 #ifdef LOG_CACHE_STATS
447     std::ostringstream oss;
448 
449     oss << "TrcMemAccCache:: cache performance: Page Size: 0x" << std::hex << m_mru_page_size << "; Number of Pages: " << std::dec << m_mru_num_pages << "\n";
450     oss << "Cache hits(" << std::dec << m_hits << "), misses(" << m_misses << "), new pages(" << m_pages << ")\n";
451     logMsg(oss.str());
452     for (int i = 0; i < m_mru_num_pages; i++)
453     {
454         if (m_hit_rl_max[i] < m_hit_rl[i])
455             m_hit_rl_max[i] = m_hit_rl[i];
456         oss.str("");
457         oss << "Run length max page " << std::dec << i << ": " << m_hit_rl_max[i] << "\n";
458         logMsg(oss.str());
459     }
460     m_hits = m_misses = m_pages = 0;
461 #endif
462 }
463 
464 /* End of File trc_mem_acc_cache.cpp */
465