From a51f08e5324252a7aafb94a2c901ee8af46f6eca Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Sat, 27 Jan 2024 09:33:12 -0600 Subject: [PATCH] perf: prefer small containers (#6542) * perf: make pref_is_savable() constexpr * refactor: use std::vector in tr_torrents::removedSince() * chore: remove unused typedef in OptionsDialog * perf: use std::vector in tr_num_parse_range() * perf: use small::max_size_set in FileTreeItem::update() * perf: use small:set in Wishlist::next() * perf: use small:map in FilterBar * perf: use small::map for counts in tr_logAddMessage() * perf: use small::max_size_map in FileTreeModel::twiddleWanted() perf: use small::max_size_map in FileTreeModel::twiddlePriority() * perf: use a std::array instead of std::map in TorrentFilter::update() * perf: use a std::array instead of std::map in TorrentSorter::set_mode() * perf: use a std::array instead of std::map in TorrentSorter::update() * perf: use small::set in Application::Impl::on_rpc_changed_idle() * perf: use std::array for MessageLogColumnsModel::level_names_ * fixup! perf: use std::array for MessageLogColumnsModel::level_names_ * fixup! perf: use small::map for counts in tr_logAddMessage() --- gtk/.clang-format | 2 +- gtk/Application.cc | 7 +++++-- gtk/MessageLogWindow.cc | 27 +++++++++++++++---------- gtk/TorrentFilter.cc | 14 +++++++++---- gtk/TorrentSorter.cc | 30 ++++++++++++++++------------ libtransmission/log.cc | 16 +++++++-------- libtransmission/peer-mgr-wishlist.cc | 8 +++++--- libtransmission/torrents.cc | 10 ++++++---- libtransmission/utils.cc | 8 +++++--- qt/FileTreeItem.cc | 5 +++-- qt/FileTreeModel.cc | 7 ++++--- qt/FilterBar.cc | 2 +- qt/FilterBar.h | 5 +++-- qt/OptionsDialog.h | 2 -- qt/Prefs.cc | 19 +++++++++++++----- qt/Prefs.h | 1 - 16 files changed, 97 insertions(+), 66 deletions(-) diff --git a/gtk/.clang-format b/gtk/.clang-format index 2799fd6a6..d5b141488 100644 --- a/gtk/.clang-format +++ b/gtk/.clang-format @@ -11,7 +11,7 @@ IncludeCategories: SortPriority: 4 - Regex: '^<(cairo|gdk|gio|glib|gtk|pango)mm([-./]|config)' Priority: 5 - - Regex: '^<(fmt)/' + - Regex: '^<(fmt|small)/' Priority: 6 - Regex: '^<(cairo|gdk|gio|glib|gtk|pango)[-./]' Priority: 8 diff --git a/gtk/Application.cc b/gtk/Application.cc index 7540ae9b0..1835c0f3f 100644 --- a/gtk/Application.cc +++ b/gtk/Application.cc @@ -52,6 +52,8 @@ #include #include +#include + #if GTKMM_CHECK_VERSION(4, 0, 0) #include #include @@ -70,7 +72,6 @@ #include // std::back_inserter #include #include -#include #include #include #include @@ -478,11 +479,13 @@ bool Application::Impl::on_rpc_changed_idle(tr_rpc_callback_type type, tr_torren auto const newvals = tr_sessionGetSettings(session); // determine which settings changed - auto changed_keys = std::set{}; + auto changed_keys = small::set{}; auto& oldvals = gtr_pref_get_all(); auto const serde = tr_variant_serde::benc(); if (auto const* const newvals_map = newvals.get_if(); newvals_map != nullptr) { + changed_keys.reserve(std::size(*newvals_map)); + for (auto const& [key, newval] : *newvals_map) { bool changed = true; diff --git a/gtk/MessageLogWindow.cc b/gtk/MessageLogWindow.cc index 5d1f4b198..1f3289465 100644 --- a/gtk/MessageLogWindow.cc +++ b/gtk/MessageLogWindow.cc @@ -36,9 +36,10 @@ #include #include +#include #include -#include #include +#include class MessageLogColumnsModel : public Gtk::TreeModelColumnRecord { @@ -95,7 +96,14 @@ private: tr_log_level maxLevel_ = TR_LOG_INFO; bool isPaused_ = false; sigc::connection refresh_tag_; - std::map const level_names_; + + static auto const inline level_names_ = std::array, 5U>{ { + { TR_LOG_CRITICAL, C_("Logging level", "Critical") }, + { TR_LOG_ERROR, C_("Logging level", "Error") }, + { TR_LOG_WARN, C_("Logging level", "Warning") }, + { TR_LOG_INFO, C_("Logging level", "Information") }, + { TR_LOG_DEBUG, C_("Logging level", "Debug") }, + } }; }; namespace @@ -163,6 +171,7 @@ void MessageLogWindow::Impl::level_combo_init(Gtk::ComboBox* level_combo) const auto has_pref_level = false; auto items = std::vector>{}; + items.reserve(std::size(level_names_)); for (auto const& [level, name] : level_names_) { items.emplace_back(name, level); @@ -213,8 +222,11 @@ void MessageLogWindow::Impl::doSave(std::string const& filename) auto const* const node = row.get_value(message_log_cols.tr_msg); auto const date = gtr_asctime(node->when); - auto const it = level_names_.find(node->level); - auto const* const level_str = it != std::end(level_names_) ? it->second : "???"; + auto const iter = std::find_if( + std::begin(level_names_), + std::end(level_names_), + [key = node->level](auto const& item) { return item.first == key; }); + auto const* const level_str = iter != std::end(level_names_) ? iter->second : "???"; fmt::print(stream, "{}\t{}\t{}\t{}\n", date, level_str, node->name, node->message); } @@ -477,13 +489,6 @@ MessageLogWindow::Impl::Impl( , refresh_tag_(Glib::signal_timeout().connect_seconds( sigc::mem_fun(*this, &Impl::onRefresh), SECONDARY_WINDOW_REFRESH_INTERVAL_SECONDS)) - , level_names_{ { - { TR_LOG_CRITICAL, C_("Logging level", "Critical") }, - { TR_LOG_ERROR, C_("Logging level", "Error") }, - { TR_LOG_WARN, C_("Logging level", "Warning") }, - { TR_LOG_INFO, C_("Logging level", "Information") }, - { TR_LOG_DEBUG, C_("Logging level", "Debug") }, - } } { /** *** toolbar diff --git a/gtk/TorrentFilter.cc b/gtk/TorrentFilter.cc index e53d9eeae..8e9c519f7 100644 --- a/gtk/TorrentFilter.cc +++ b/gtk/TorrentFilter.cc @@ -10,6 +10,9 @@ #include +#include +#include + TorrentFilter::TorrentFilter() : Glib::ObjectBase(typeid(TorrentFilter)) { @@ -127,7 +130,7 @@ void TorrentFilter::update(Torrent::ChangeFlags changes) if (activity_type_ != Activity::ALL) { - static auto const activity_flags = std::map({ + static constexpr auto ActivityFlags = std::array, 7U>{ { { Activity::DOWNLOADING, Flag::ACTIVITY }, { Activity::SEEDING, Flag::ACTIVITY }, { Activity::ACTIVE, Flag::ACTIVE_PEER_COUNT | Flag::ACTIVITY }, @@ -135,10 +138,13 @@ void TorrentFilter::update(Torrent::ChangeFlags changes) { Activity::FINISHED, Flag::FINISHED }, { Activity::VERIFYING, Flag::ACTIVITY }, { Activity::ERROR, Flag::ERROR_CODE }, - }); + } }; - auto const activity_flags_it = activity_flags.find(activity_type_); - refilter_needed = activity_flags_it != activity_flags.end() && changes.test(activity_flags_it->second); + auto const iter = std::find_if( + std::begin(ActivityFlags), + std::end(ActivityFlags), + [key = activity_type_](auto const& row) { return row.first == key; }); + refilter_needed = iter != std::end(ActivityFlags) && changes.test(iter->second); } if (!refilter_needed) diff --git a/gtk/TorrentSorter.cc b/gtk/TorrentSorter.cc index b9cf9f890..106b635fc 100644 --- a/gtk/TorrentSorter.cc +++ b/gtk/TorrentSorter.cc @@ -13,6 +13,8 @@ #include #include +#include +#include using namespace std::string_view_literals; @@ -178,7 +180,8 @@ TorrentSorter::TorrentSorter() void TorrentSorter::set_mode(std::string_view mode) { - static auto const compare_funcs = std::map({ + static auto constexpr DefaultCompareFunc = &compare_by_name; + static auto constexpr CompareFuncs = std::array, 9U>{ { { "sort-by-activity"sv, &compare_by_activity }, { "sort-by-age"sv, &compare_by_age }, { "sort-by-name"sv, &compare_by_name }, @@ -188,14 +191,13 @@ void TorrentSorter::set_mode(std::string_view mode) { "sort-by-size"sv, &compare_by_size }, { "sort-by-state"sv, &compare_by_state }, { "sort-by-time-left"sv, &compare_by_eta }, - }); - - auto compare_func = &compare_by_name; - if (auto const compare_func_it = compare_funcs.find(mode); compare_func_it != compare_funcs.end()) - { - compare_func = compare_func_it->second; - } + } }; + auto const iter = std::find_if( + std::begin(CompareFuncs), + std::end(CompareFuncs), + [key = mode](auto const& row) { return row.first == key; }); + auto const compare_func = iter != std::end(CompareFuncs) ? iter->second : DefaultCompareFunc; if (compare_func_ == compare_func) { return; @@ -224,8 +226,7 @@ int TorrentSorter::compare(Torrent const& lhs, Torrent const& rhs) const void TorrentSorter::update(Torrent::ChangeFlags changes) { using Flag = Torrent::ChangeFlag; - - static auto const compare_flags = std::map({ + static auto constexpr CompareFlags = std::array, 9U>{ { { &compare_by_activity, Flag::ACTIVE_PEER_COUNT | Flag::QUEUE_POSITION | Flag::SPEED_DOWN | Flag::SPEED_UP }, { &compare_by_age, Flag::ADDED_DATE | Flag::NAME }, { &compare_by_eta, Flag::ETA | Flag::NAME }, @@ -235,10 +236,13 @@ void TorrentSorter::update(Torrent::ChangeFlags changes) { &compare_by_ratio, Flag::QUEUE_POSITION | Flag::RATIO }, { &compare_by_size, Flag::NAME | Flag::TOTAL_SIZE }, { &compare_by_state, Flag::ACTIVITY | Flag::QUEUE_POSITION }, - }); + } }; - if (auto const compare_flags_it = compare_flags.find(compare_func_); - compare_flags_it != compare_flags.end() && changes.test(compare_flags_it->second)) + if (auto const iter = std::find_if( + std::begin(CompareFlags), + std::end(CompareFlags), + [key = compare_func_](auto const& row) { return row.first == key; }); + iter != std::end(CompareFlags) && changes.test(iter->second)) { changed(Change::DIFFERENT); } diff --git a/libtransmission/log.cc b/libtransmission/log.cc index 62f53233b..92115c928 100644 --- a/libtransmission/log.cc +++ b/libtransmission/log.cc @@ -8,7 +8,7 @@ #include #include // size_t #include // back_insert_iterator, empty -#include +#include #include #include #include @@ -22,6 +22,8 @@ #include #include +#include + #include "libtransmission/file.h" #include "libtransmission/log.h" #include "libtransmission/tr-assert.h" @@ -246,12 +248,12 @@ void tr_logAddMessage(char const* file, long line, tr_log_level level, std::stri auto const lock = log_state.unique_lock(); // don't log the same warning ad infinitum. - // it's not useful after some point. + // at some point, it stops being useful. bool last_one = false; if (level == TR_LOG_CRITICAL || level == TR_LOG_ERROR || level == TR_LOG_WARN) { static auto constexpr MaxRepeat = size_t{ 30 }; - static auto counts = new std::map, size_t>{}; + static auto* const counts = new small::map, size_t>{}; auto& count = (*counts)[std::make_pair(filename, line)]; ++count; @@ -267,12 +269,8 @@ void tr_logAddMessage(char const* file, long line, tr_log_level level, std::stri logAddImpl(filename, line, level, std::move(msg), name); if (last_one) { - logAddImpl( - filename, - line, - level, - _("Too many messages like this! I won't log this message anymore this session."), - name); + char const* final_msg = _("Too many messages like this! I won't log this message anymore this session."); + logAddImpl(filename, line, level, final_msg, name); } errno = err; diff --git a/libtransmission/peer-mgr-wishlist.cc b/libtransmission/peer-mgr-wishlist.cc index 96250e788..0a9993ffe 100644 --- a/libtransmission/peer-mgr-wishlist.cc +++ b/libtransmission/peer-mgr-wishlist.cc @@ -5,10 +5,11 @@ #include // std::min, std::partial_sort #include -#include #include #include +#include + #define LIBTRANSMISSION_PEER_MODULE #include "libtransmission/transmission.h" @@ -136,11 +137,12 @@ std::vector Wishlist::next(size_t n_wanted_blocks) // We usually won't need all the candidates to be sorted until endgame, so don't // waste cycles sorting all of them here. partial sort is enough. - static auto constexpr MaxSortedPieces = size_t{ 30 }; + static auto constexpr MaxSortedPieces = size_t{ 30U }; auto const middle = std::min(std::size(candidates), MaxSortedPieces); std::partial_sort(std::begin(candidates), std::begin(candidates) + middle, std::end(candidates)); - auto blocks = std::set{}; + auto blocks = small::set{}; + blocks.reserve(n_wanted_blocks); for (auto const& candidate : candidates) { // do we have enough? diff --git a/libtransmission/torrents.cc b/libtransmission/torrents.cc index a4552c66a..d27e5bc27 100644 --- a/libtransmission/torrents.cc +++ b/libtransmission/torrents.cc @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -91,15 +90,18 @@ void tr_torrents::remove(tr_torrent const* tor, time_t current_time) std::vector tr_torrents::removedSince(time_t timestamp) const { - auto ids = std::set{}; + auto ids = std::vector{}; + ids.reserve(std::size(removed_)); for (auto const& [id, removed_at] : removed_) { if (removed_at >= timestamp) { - ids.insert(id); + ids.emplace_back(id); } } - return { std::begin(ids), std::end(ids) }; + std::sort(std::begin(ids), std::end(ids)); + ids.erase(std::unique(std::begin(ids), std::end(ids)), std::end(ids)); + return ids; } diff --git a/libtransmission/utils.cc b/libtransmission/utils.cc index c685b0840..5ba1d4190 100644 --- a/libtransmission/utils.cc +++ b/libtransmission/utils.cc @@ -493,18 +493,20 @@ std::vector tr_num_parse_range(std::string_view str) { using namespace tr_num_parse_range_impl; - auto values = std::set{}; + auto values = std::vector{}; auto token = std::string_view{}; auto range = number_range{}; while (tr_strv_sep(&str, &token, ',') && parseNumberSection(token, range)) { for (auto i = range.low; i <= range.high; ++i) { - values.insert(i); + values.emplace_back(i); } } - return { std::begin(values), std::end(values) }; + std::sort(std::begin(values), std::end(values)); + values.erase(std::unique(std::begin(values), std::end(values)), std::end(values)); + return values; } // --- diff --git a/qt/FileTreeItem.cc b/qt/FileTreeItem.cc index 35e71bf02..5cc874cbd 100644 --- a/qt/FileTreeItem.cc +++ b/qt/FileTreeItem.cc @@ -5,9 +5,10 @@ #include #include -#include #include +#include + #include #include @@ -223,7 +224,7 @@ uint64_t FileTreeItem::size() const std::pair FileTreeItem::update(QString const& name, bool wanted, int priority, uint64_t have_size, bool update_fields) { - auto changed_columns = std::set{}; + auto changed_columns = small::max_size_set{}; if (name_ != name) { diff --git a/qt/FileTreeModel.cc b/qt/FileTreeModel.cc index ef45ced11..bd31a290f 100644 --- a/qt/FileTreeModel.cc +++ b/qt/FileTreeModel.cc @@ -7,10 +7,11 @@ #include #include #include -#include #include #include +#include + #include // priorities #include @@ -470,7 +471,7 @@ void FileTreeModel::emitSubtreeChanged(QModelIndex const& idx, int first_column, void FileTreeModel::twiddleWanted(QModelIndexList const& indices) { - std::map wanted_indices; + auto wanted_indices = small::max_size_map{}; for (QModelIndex const& i : getOrphanIndices(indices)) { @@ -489,7 +490,7 @@ void FileTreeModel::twiddleWanted(QModelIndexList const& indices) void FileTreeModel::twiddlePriority(QModelIndexList const& indices) { - std::map priority_indices; + auto priority_indices = small::max_size_map{}; for (QModelIndex const& i : getOrphanIndices(indices)) { diff --git a/qt/FilterBar.cc b/qt/FilterBar.cc index 44d5042e2..f1952c215 100644 --- a/qt/FilterBar.cc +++ b/qt/FilterBar.cc @@ -155,7 +155,7 @@ void FilterBar::refreshTrackers() return i; }; - auto new_trackers = std::map(torrents_per_sitename.begin(), torrents_per_sitename.end()); + auto new_trackers = small::map{ torrents_per_sitename.begin(), torrents_per_sitename.end() }; auto old_it = sitename_counts_.cbegin(); auto new_it = new_trackers.cbegin(); auto const old_end = sitename_counts_.cend(); diff --git a/qt/FilterBar.h b/qt/FilterBar.h index 4591f9785..0a5bf291e 100644 --- a/qt/FilterBar.h +++ b/qt/FilterBar.h @@ -6,7 +6,8 @@ #pragma once #include -#include + +#include #include #include @@ -63,7 +64,7 @@ private: FilterBarComboBox* const tracker_combo_ = createTrackerCombo(tracker_model_); QLineEdit* const line_edit_ = new QLineEdit{ this }; - std::map sitename_counts_; + small::map sitename_counts_; QTimer recount_timer_; Pending pending_ = {}; bool is_bootstrapping_ = {}; diff --git a/qt/OptionsDialog.h b/qt/OptionsDialog.h index 741289d2a..b723be999 100644 --- a/qt/OptionsDialog.h +++ b/qt/OptionsDialog.h @@ -54,8 +54,6 @@ private slots: void onSessionUpdated(); private: - using mybins_t = std::map; - void reload(); void updateWidgetsLocality(); void clearInfo(); diff --git a/qt/Prefs.cc b/qt/Prefs.cc index 47c738eff..5a8436003 100644 --- a/qt/Prefs.cc +++ b/qt/Prefs.cc @@ -201,6 +201,19 @@ bool isValidUtf8(QByteArray const& byteArray) #endif } +[[nodiscard]] constexpr auto pref_is_savable(int pref) +{ + switch (pref) + { + // these are the prefs that don't get saved to settings.json + // when the application exits. + case Prefs::FILTER_TEXT: + return false; + + default: + return true; + } +} } // namespace /*** @@ -220,10 +233,6 @@ Prefs::Prefs(QString config_dir) #endif - // these are the prefs that don't get saved to settings.json - // when the application exits. - temporary_prefs_.insert(FILTER_TEXT); - auto const app_defaults = get_default_app_settings(); auto settings = tr_sessionLoadSettings(&app_defaults, config_dir_.toUtf8().constData(), nullptr); ensureSoundCommandIsAList(&settings); @@ -323,7 +332,7 @@ Prefs::~Prefs() for (int i = 0; i < PREFS_COUNT; ++i) { - if (temporary_prefs_.count(i) != 0U) + if (!pref_is_savable(i)) { continue; } diff --git a/qt/Prefs.h b/qt/Prefs.h index 01870734b..62bdb2d5a 100644 --- a/qt/Prefs.h +++ b/qt/Prefs.h @@ -204,7 +204,6 @@ private: QString const config_dir_; - std::set temporary_prefs_; std::array mutable values_; static std::array const Items;