Skip to content

Commit 55d3bda

Browse files
committed
[DSC] Performance improvements and clean-up in SymbolTableView
Avoid copying the vector of symbols where possible. When no filter string is applied we no longer copy the entire vector symbols by having the symbols used for display be indirected via a pointer. It points either to the unfiltered symbols or the filtered symbols. Some unncessary copies have been removed by using `std::move` where appropriate. Filtering has been updated to avoid `std::vector::reserve` / `std::vector::shrink_to_fit` in favor of letting the filtered vector control its own growth and reuse its buffer. This avoids allocating a ~100MB buffer every time we update the filter only to later reallocate and move the contents into a smaller buffer. Instead the buffer grows via `std::vector`'s usual growth algorithm and it is preserved across filter calls to avoid unnecessarily reallocating it, and only shrink the buffer if it has shrunk significantly vs previous iterations.
1 parent 83684ec commit 55d3bda

File tree

2 files changed

+42
-31
lines changed

2 files changed

+42
-31
lines changed

view/sharedcache/ui/symboltable.cpp

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@ using namespace BinaryNinja;
1111
using namespace SharedCacheAPI;
1212

1313

14-
SymbolTableModel::SymbolTableModel(SymbolTableView* parent)
15-
: QAbstractTableModel(parent), m_parent(parent) {
14+
SymbolTableModel::SymbolTableModel(SymbolTableView* parent) :
15+
QAbstractTableModel(parent), m_parent(parent), m_displaySymbols(&m_symbols)
16+
{
1617
// TODO: Need to implement updating this font if it is changed by the user
1718
m_font = getMonospaceFont(parent);
1819
}
1920

2021

2122
int SymbolTableModel::rowCount(const QModelIndex& parent) const {
2223
Q_UNUSED(parent);
23-
return static_cast<int>(m_modelSymbols.size());
24+
return static_cast<int>(m_displaySymbols->size());
2425
}
2526

2627

@@ -111,61 +112,69 @@ void SymbolTableModel::sort(int column, Qt::SortOrder order)
111112

112113
if (order == Qt::DescendingOrder)
113114
{
114-
std::sort(m_modelSymbols.begin(), m_modelSymbols.end(),
115-
[&comparator](const CacheSymbol& a, const CacheSymbol& b) {
116-
return comparator(b, a);
117-
});
115+
std::sort(m_displaySymbols->begin(), m_displaySymbols->end(),
116+
[&comparator](const CacheSymbol& a, const CacheSymbol& b) { return comparator(b, a); });
118117
}
119118
else
120119
{
121-
std::sort(m_modelSymbols.begin(), m_modelSymbols.end(), comparator);
120+
std::sort(m_displaySymbols->begin(), m_displaySymbols->end(), comparator);
122121
}
123122

124123
endResetModel();
125124
}
126125

127126

128-
void SymbolTableModel::updateSymbols(std::vector<CacheSymbol>&& symbols)
127+
void SymbolTableModel::updateSymbols(std::vector<CacheSymbol> symbols)
129128
{
130-
m_preparedSymbols = symbols;
129+
m_symbols = std::move(symbols);
131130
setFilter(m_filter);
132131
}
133132

134133

135134
const CacheSymbol& SymbolTableModel::symbolAt(int row) const
136135
{
137-
return m_modelSymbols.at(row);
136+
return m_displaySymbols->at(row);
138137
}
139138

140139

141140
void SymbolTableModel::setFilter(std::string text)
142141
{
143142
beginResetModel();
144143

145-
m_filter = text;
146-
m_modelSymbols = {};
144+
m_filter = std::move(text);
147145

148146
// Skip filtering if no filter applied.
149-
if (!m_filter.empty())
147+
if (m_filter.empty())
150148
{
151-
m_modelSymbols.reserve(m_preparedSymbols.size());
152-
for (const auto& symbol : m_preparedSymbols)
153-
if (((std::string_view)symbol.name).find(m_filter) != std::string::npos)
154-
m_modelSymbols.push_back(symbol);
155-
m_modelSymbols.shrink_to_fit();
149+
m_filteredSymbols = {};
150+
m_displaySymbols = &m_symbols;
156151
}
157152
else
158153
{
159-
m_modelSymbols = m_preparedSymbols;
154+
// Clear the filtered symbols while preserving the capacity
155+
m_filteredSymbols.clear();
156+
157+
for (const auto& symbol : m_symbols)
158+
{
159+
if (symbol.name.find(m_filter) != std::string::npos)
160+
m_filteredSymbols.push_back(symbol);
161+
}
162+
163+
// If the filtered vector is using less than 25% of its capacity,
164+
// shrink it to reduce memory usage.
165+
if (m_filteredSymbols.size() < m_filteredSymbols.capacity() / 4)
166+
m_filteredSymbols.shrink_to_fit();
167+
168+
m_displaySymbols = &m_filteredSymbols;
160169
}
161170

162171
endResetModel();
163172
}
164173

165174

166-
SymbolTableView::SymbolTableView(QWidget* parent)
167-
: QTableView(parent), m_model(new SymbolTableModel(this)) {
168-
175+
SymbolTableView::SymbolTableView(QWidget* parent) :
176+
QTableView(parent), m_model(new SymbolTableModel(this))
177+
{
169178
// Set up the filter model
170179
setModel(m_model);
171180

@@ -181,9 +190,7 @@ SymbolTableView::SymbolTableView(QWidget* parent)
181190
setSortingEnabled(true);
182191
}
183192

184-
SymbolTableView::~SymbolTableView() {
185-
delete m_model;
186-
}
193+
SymbolTableView::~SymbolTableView() = default;
187194

188195
void SymbolTableView::populateSymbols(BinaryView &view)
189196
{

view/sharedcache/ui/symboltable.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@ Q_OBJECT
1919
SymbolTableView* m_parent;
2020
QFont m_font;
2121
std::string m_filter;
22-
std::vector<SharedCacheAPI::CacheSymbol> m_preparedSymbols{};
23-
// These are the symbols we actually use
24-
std::vector<SharedCacheAPI::CacheSymbol> m_modelSymbols{};
22+
23+
std::vector<SharedCacheAPI::CacheSymbol> m_symbols;
24+
std::vector<SharedCacheAPI::CacheSymbol> m_filteredSymbols;
25+
26+
// A pointer to either m_symbols or m_filteredSymbols, depending on whether a filter is applied.
27+
std::vector<SharedCacheAPI::CacheSymbol> *m_displaySymbols = nullptr;
2528

2629
public:
2730
explicit SymbolTableModel(SymbolTableView* parent);
@@ -31,10 +34,11 @@ Q_OBJECT
3134
QVariant data(const QModelIndex& index, int role) const override;
3235
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
3336
void sort(int column, Qt::SortOrder order) override;
34-
void updateSymbols(std::vector<SharedCacheAPI::CacheSymbol>&& symbols);
37+
38+
void updateSymbols(std::vector<SharedCacheAPI::CacheSymbol> symbols);
3539
void setFilter(std::string text);
36-
const SharedCacheAPI::CacheSymbol& symbolAt(int row) const;
3740

41+
const SharedCacheAPI::CacheSymbol& symbolAt(int row) const;
3842
};
3943

4044

0 commit comments

Comments
 (0)