File indexing completed on 2024-05-12 17:15:55

0001 /*
0002     SPDX-FileCopyrightText: 2014-2017 Milian Wolff <mail@milianw.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #ifndef TRACETREE_H
0008 #define TRACETREE_H
0009 
0010 /**
0011  * @file tracetree.h
0012  * @brief Efficiently combine and store the data of multiple Traces.
0013  */
0014 
0015 #include <algorithm>
0016 #include <vector>
0017 
0018 #include "trace.h"
0019 
0020 struct TraceEdge
0021 {
0022     Trace::ip_t instructionPointer;
0023     // index associated to the backtrace up to this instruction pointer
0024     // the evaluation process can then reverse-map the index to the parent ip
0025     // to rebuild the backtrace from the bottom-up
0026     uint32_t index;
0027     // sorted list of children, assumed to be small
0028     std::vector<TraceEdge> children;
0029 };
0030 
0031 /**
0032  * Top-down tree of backtrace instruction pointers.
0033  *
0034  * This is supposed to be a memory efficient storage of all instruction pointers
0035  * ever encountered in any backtrace.
0036  */
0037 class TraceTree
0038 {
0039 public:
0040     void clear()
0041     {
0042         m_root.children.clear();
0043         m_index = 1;
0044     }
0045 
0046     /**
0047      * Index the data in @p trace and return the index of the last instruction
0048      * pointer.
0049      *
0050      * Unknown instruction pointers will be handled by the @p callback
0051      */
0052     template <typename Fun>
0053     uint32_t index(const Trace& trace, Fun callback)
0054     {
0055         uint32_t index = 0;
0056         TraceEdge* parent = &m_root;
0057         for (int i = trace.size() - 1; i >= 0; --i) {
0058             const auto ip = trace[i];
0059             if (!ip) {
0060                 continue;
0061             }
0062             auto it =
0063                 std::lower_bound(parent->children.begin(), parent->children.end(), ip,
0064                                  [](const TraceEdge& l, const Trace::ip_t ip) { return l.instructionPointer < ip; });
0065             if (it == parent->children.end() || it->instructionPointer != ip) {
0066                 index = m_index++;
0067                 it = parent->children.insert(it, {ip, index, {}});
0068                 if (!callback(reinterpret_cast<uintptr_t>(ip), parent->index)) {
0069                     return 0;
0070                 }
0071             }
0072             index = it->index;
0073             parent = &(*it);
0074         }
0075         return index;
0076     }
0077 
0078 private:
0079     TraceEdge m_root = {0, 0, {}};
0080     uint32_t m_index = 1;
0081 };
0082 
0083 #endif // TRACETREE_H