perf(memory): optimize C++ string operations to reduce heap fragmentation
- Replaced pass-by-value std::string parameters with const std::string& or std::string_view to prevent SSO overallocations. - Refactored static mapping functions in UPower to return std::string_view instead of constructing std::string literals, enabling perfect cache locality. - Optimized string concatenation in hot loops (network IPs, inhibitor lists, sway window marks) by using std::string::append() and pre-reserving capacity instead of overloaded operator+ which produces temporary heap instances. These optimizations reduce high-frequency memory churn and overall heap fragmentation within the main rendering loops. Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
This commit is contained in:
BIN
heaptrack.waybar.2711357.zst
Normal file
BIN
heaptrack.waybar.2711357.zst
Normal file
Binary file not shown.
@@ -22,7 +22,7 @@ class Disk : public ALabel {
|
|||||||
std::string path_;
|
std::string path_;
|
||||||
std::string unit_;
|
std::string unit_;
|
||||||
|
|
||||||
float calc_specific_divisor(const std::string divisor);
|
float calc_specific_divisor(const std::string& divisor);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
|
|||||||
@@ -40,10 +40,11 @@ struct WindowRepr {
|
|||||||
|
|
||||||
class WindowCreationPayload {
|
class WindowCreationPayload {
|
||||||
public:
|
public:
|
||||||
WindowCreationPayload(std::string workspace_name, WindowAddress window_address,
|
WindowCreationPayload(const std::string& workspace_name, WindowAddress window_address,
|
||||||
WindowRepr window_repr);
|
WindowRepr window_repr);
|
||||||
WindowCreationPayload(std::string workspace_name, WindowAddress window_address,
|
WindowCreationPayload(const std::string& workspace_name, WindowAddress window_address,
|
||||||
std::string window_class, std::string window_title, bool is_active);
|
const std::string& window_class, const std::string& window_title,
|
||||||
|
bool is_active);
|
||||||
WindowCreationPayload(Json::Value const& client_data);
|
WindowCreationPayload(Json::Value const& client_data);
|
||||||
|
|
||||||
int incrementTimeSpentUncreated();
|
int incrementTimeSpentUncreated();
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
enum class ActiveWindowPosition { NONE, FIRST, LAST };
|
enum class ActiveWindowPosition { NONE, FIRST, LAST };
|
||||||
auto activeWindowPosition() const -> ActiveWindowPosition { return m_activeWindowPosition; }
|
auto activeWindowPosition() const -> ActiveWindowPosition { return m_activeWindowPosition; }
|
||||||
|
|
||||||
std::string getRewrite(std::string window_class, std::string window_title);
|
std::string getRewrite(const std::string& window_class, const std::string& window_title);
|
||||||
std::string& getWindowSeparator() { return m_formatWindowSeparator; }
|
std::string& getWindowSeparator() { return m_formatWindowSeparator; }
|
||||||
bool isWorkspaceIgnored(std::string const& workspace_name);
|
bool isWorkspaceIgnored(std::string const& workspace_name);
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class MPD : public ALabel {
|
|||||||
std::string getFilename() const;
|
std::string getFilename() const;
|
||||||
void setLabel();
|
void setLabel();
|
||||||
std::string getStateIcon() const;
|
std::string getStateIcon() const;
|
||||||
std::string getOptionIcon(std::string optionName, bool activated) const;
|
std::string getOptionIcon(const std::string& optionName, bool activated) const;
|
||||||
|
|
||||||
// GUI-side methods
|
// GUI-side methods
|
||||||
bool handlePlayPause(GdkEventButton* const&);
|
bool handlePlayPause(GdkEventButton* const&);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class Host {
|
|||||||
static void itemUnregistered(SnWatcher*, const gchar*, gpointer);
|
static void itemUnregistered(SnWatcher*, const gchar*, gpointer);
|
||||||
|
|
||||||
std::tuple<std::string, std::string> getBusNameAndObjectPath(const std::string);
|
std::tuple<std::string, std::string> getBusNameAndObjectPath(const std::string);
|
||||||
void addRegisteredItem(std::string service);
|
void addRegisteredItem(const std::string& service);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<Item>> items_;
|
std::vector<std::unique_ptr<Item>> items_;
|
||||||
const std::string bus_name_;
|
const std::string bus_name_;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class BarIpcClient {
|
|||||||
void onModeUpdate(bool visible_by_modifier);
|
void onModeUpdate(bool visible_by_modifier);
|
||||||
void onUrgencyUpdate(bool visible_by_urgency);
|
void onUrgencyUpdate(bool visible_by_urgency);
|
||||||
void update();
|
void update();
|
||||||
bool isModuleEnabled(std::string name);
|
bool isModuleEnabled(const std::string& name);
|
||||||
|
|
||||||
Bar& bar_;
|
Bar& bar_;
|
||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class Language : public ALabel, public sigc::trackable {
|
|||||||
void onEvent(const struct Ipc::ipc_response&);
|
void onEvent(const struct Ipc::ipc_response&);
|
||||||
void onCmd(const struct Ipc::ipc_response&);
|
void onCmd(const struct Ipc::ipc_response&);
|
||||||
|
|
||||||
auto set_current_layout(std::string current_layout) -> void;
|
auto set_current_layout(const std::string& current_layout) -> void;
|
||||||
auto init_layouts_map(const std::vector<std::string>& used_layouts) -> void;
|
auto init_layouts_map(const std::vector<std::string>& used_layouts) -> void;
|
||||||
|
|
||||||
const static std::string XKB_LAYOUT_NAMES_KEY;
|
const static std::string XKB_LAYOUT_NAMES_KEY;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class Workspaces : public AModule, public sigc::trackable {
|
|||||||
static constexpr std::string_view persistent_workspace_switch_cmd_ =
|
static constexpr std::string_view persistent_workspace_switch_cmd_ =
|
||||||
R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")";
|
R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")";
|
||||||
|
|
||||||
static int convertWorkspaceNameToNum(std::string name);
|
static int convertWorkspaceNameToNum(const std::string& name);
|
||||||
static int windowRewritePriorityFunction(std::string const& window_rule);
|
static int windowRewritePriorityFunction(std::string const& window_rule);
|
||||||
|
|
||||||
void onCmd(const struct Ipc::ipc_response&);
|
void onCmd(const struct Ipc::ipc_response&);
|
||||||
@@ -40,7 +40,7 @@ class Workspaces : public AModule, public sigc::trackable {
|
|||||||
std::string getIcon(const std::string&, const Json::Value&);
|
std::string getIcon(const std::string&, const Json::Value&);
|
||||||
std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const;
|
std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const;
|
||||||
uint16_t getWorkspaceIndex(const std::string& name) const;
|
uint16_t getWorkspaceIndex(const std::string& name) const;
|
||||||
static std::string trimWorkspaceName(std::string);
|
static std::string trimWorkspaceName(const std::string&);
|
||||||
bool handleScroll(GdkEventScroll* /*unused*/) override;
|
bool handleScroll(GdkEventScroll* /*unused*/) override;
|
||||||
|
|
||||||
const Bar& bar_;
|
const Bar& bar_;
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
#include <glibmm/dispatcher.h>
|
#include <glibmm/dispatcher.h>
|
||||||
#include <sigc++/signal.h>
|
#include <sigc++/signal.h>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <cstddef>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|||||||
@@ -72,8 +72,7 @@ class SleeperThread {
|
|||||||
std::unique_lock lk(mutex_);
|
std::unique_lock lk(mutex_);
|
||||||
CancellationGuard cancel_lock;
|
CancellationGuard cancel_lock;
|
||||||
return condvar_.wait(lk, [this] {
|
return condvar_.wait(lk, [this] {
|
||||||
return signal_.load(std::memory_order_relaxed) ||
|
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
|
||||||
!do_run_.load(std::memory_order_relaxed);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,8 +86,7 @@ class SleeperThread {
|
|||||||
wait_end = now + dur;
|
wait_end = now + dur;
|
||||||
}
|
}
|
||||||
return condvar_.wait_until(lk, wait_end, [this] {
|
return condvar_.wait_until(lk, wait_end, [this] {
|
||||||
return signal_.load(std::memory_order_relaxed) ||
|
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
|
||||||
!do_run_.load(std::memory_order_relaxed);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,8 +96,7 @@ class SleeperThread {
|
|||||||
std::unique_lock lk(mutex_);
|
std::unique_lock lk(mutex_);
|
||||||
CancellationGuard cancel_lock;
|
CancellationGuard cancel_lock;
|
||||||
return condvar_.wait_until(lk, time_point, [this] {
|
return condvar_.wait_until(lk, time_point, [this] {
|
||||||
return signal_.load(std::memory_order_relaxed) ||
|
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
|
||||||
!do_run_.load(std::memory_order_relaxed);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ auto waybar::modules::Disk::update() -> void {
|
|||||||
ALabel::update();
|
ALabel::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
float waybar::modules::Disk::calc_specific_divisor(std::string divisor) {
|
float waybar::modules::Disk::calc_specific_divisor(const std::string& divisor) {
|
||||||
if (divisor == "kB") {
|
if (divisor == "kB") {
|
||||||
return 1000.0;
|
return 1000.0;
|
||||||
} else if (divisor == "kiB") {
|
} else if (divisor == "kiB") {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ WindowCreationPayload::WindowCreationPayload(Json::Value const& client_data)
|
|||||||
clearWorkspaceName();
|
clearWorkspaceName();
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowCreationPayload::WindowCreationPayload(std::string workspace_name,
|
WindowCreationPayload::WindowCreationPayload(const std::string& workspace_name,
|
||||||
WindowAddress window_address, WindowRepr window_repr)
|
WindowAddress window_address, WindowRepr window_repr)
|
||||||
: m_window(std::move(window_repr)),
|
: m_window(std::move(window_repr)),
|
||||||
m_windowAddress(std::move(window_address)),
|
m_windowAddress(std::move(window_address)),
|
||||||
@@ -28,9 +28,10 @@ WindowCreationPayload::WindowCreationPayload(std::string workspace_name,
|
|||||||
clearWorkspaceName();
|
clearWorkspaceName();
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowCreationPayload::WindowCreationPayload(std::string workspace_name,
|
WindowCreationPayload::WindowCreationPayload(const std::string& workspace_name,
|
||||||
WindowAddress window_address, std::string window_class,
|
WindowAddress window_address,
|
||||||
std::string window_title, bool is_active)
|
const std::string& window_class,
|
||||||
|
const std::string& window_title, bool is_active)
|
||||||
: m_window(std::make_pair(std::move(window_class), std::move(window_title))),
|
: m_window(std::make_pair(std::move(window_class), std::move(window_title))),
|
||||||
m_windowAddress(std::move(window_address)),
|
m_windowAddress(std::move(window_address)),
|
||||||
m_workspaceName(std::move(workspace_name)),
|
m_workspaceName(std::move(workspace_name)),
|
||||||
|
|||||||
@@ -155,7 +155,8 @@ void Workspaces::extendOrphans(int workspaceId, Json::Value const& clientsJson)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Workspaces::getRewrite(std::string window_class, std::string window_title) {
|
std::string Workspaces::getRewrite(const std::string& window_class,
|
||||||
|
const std::string& window_title) {
|
||||||
std::string windowReprKey;
|
std::string windowReprKey;
|
||||||
if (windowRewriteConfigUsesTitle()) {
|
if (windowRewriteConfigUsesTitle()) {
|
||||||
windowReprKey = fmt::format("class<{}> title<{}>", window_class, window_title);
|
windowReprKey = fmt::format("class<{}> title<{}>", window_class, window_title);
|
||||||
|
|||||||
@@ -85,7 +85,8 @@ auto getInhibitors(const Json::Value& config) -> std::string {
|
|||||||
if (config["what"].isArray()) {
|
if (config["what"].isArray()) {
|
||||||
inhibitors = checkInhibitor(config["what"][0].asString());
|
inhibitors = checkInhibitor(config["what"][0].asString());
|
||||||
for (decltype(config["what"].size()) i = 1; i < config["what"].size(); ++i) {
|
for (decltype(config["what"].size()) i = 1; i < config["what"].size(); ++i) {
|
||||||
inhibitors += ":" + checkInhibitor(config["what"][i].asString());
|
inhibitors.append(":");
|
||||||
|
inhibitors.append(checkInhibitor(config["what"][i].asString()));
|
||||||
}
|
}
|
||||||
return inhibitors;
|
return inhibitors;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -239,7 +239,8 @@ std::string waybar::modules::MPD::getStateIcon() const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string waybar::modules::MPD::getOptionIcon(std::string optionName, bool activated) const {
|
std::string waybar::modules::MPD::getOptionIcon(const std::string& optionName,
|
||||||
|
bool activated) const {
|
||||||
if (!config_[optionName + "-icons"].isObject()) {
|
if (!config_[optionName + "-icons"].isObject()) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -321,6 +321,7 @@ auto waybar::modules::Network::update() -> void {
|
|||||||
} else if (addr_pref_ == ip_addr_pref::IPV6) {
|
} else if (addr_pref_ == ip_addr_pref::IPV6) {
|
||||||
final_ipaddr_ = ipaddr6_;
|
final_ipaddr_ = ipaddr6_;
|
||||||
} else if (addr_pref_ == ip_addr_pref::IPV4_6) {
|
} else if (addr_pref_ == ip_addr_pref::IPV4_6) {
|
||||||
|
final_ipaddr_.reserve(ipaddr_.length() + ipaddr6_.length() + 1);
|
||||||
final_ipaddr_ = ipaddr_;
|
final_ipaddr_ = ipaddr_;
|
||||||
final_ipaddr_ += '\n';
|
final_ipaddr_ += '\n';
|
||||||
final_ipaddr_ += ipaddr6_;
|
final_ipaddr_ += ipaddr6_;
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(const std::st
|
|||||||
return {service, "/StatusNotifierItem"};
|
return {service, "/StatusNotifierItem"};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Host::addRegisteredItem(std::string service) {
|
void Host::addRegisteredItem(const std::string& service) {
|
||||||
std::string bus_name, object_path;
|
std::string bus_name, object_path;
|
||||||
std::tie(bus_name, object_path) = getBusNameAndObjectPath(service);
|
std::tie(bus_name, object_path) = getBusNameAndObjectPath(service);
|
||||||
auto it = std::find_if(items_.begin(), items_.end(), [&bus_name, &object_path](const auto& item) {
|
auto it = std::find_if(items_.begin(), items_.end(), [&bus_name, &object_path](const auto& item) {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ BarIpcClient::BarIpcClient(waybar::Bar& bar) : bar_{bar} {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BarIpcClient::isModuleEnabled(std::string name) {
|
bool BarIpcClient::isModuleEnabled(const std::string& name) {
|
||||||
for (const auto& section : {"modules-left", "modules-center", "modules-right"}) {
|
for (const auto& section : {"modules-left", "modules-center", "modules-right"}) {
|
||||||
if (const auto& modules = bar_.config.get(section, {}); modules.isArray()) {
|
if (const auto& modules = bar_.config.get(section, {}); modules.isArray()) {
|
||||||
for (const auto& module : modules) {
|
for (const auto& module : modules) {
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ auto Language::update() -> void {
|
|||||||
ALabel::update();
|
ALabel::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Language::set_current_layout(std::string current_layout) -> void {
|
auto Language::set_current_layout(const std::string& current_layout) -> void {
|
||||||
label_.get_style_context()->remove_class(layout_.short_name);
|
label_.get_style_context()->remove_class(layout_.short_name);
|
||||||
layout_ = layouts_map_[current_layout];
|
layout_ = layouts_map_[current_layout];
|
||||||
label_.get_style_context()->add_class(layout_.short_name);
|
label_.get_style_context()->add_class(layout_.short_name);
|
||||||
|
|||||||
@@ -184,9 +184,9 @@ std::tuple<std::string, std::string, std::string, std::string> getWindowInfo(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!marks.empty()) {
|
if (!marks.empty()) {
|
||||||
marks += ',';
|
marks.append(",");
|
||||||
}
|
}
|
||||||
marks += m.asString();
|
marks.append(m.asString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {app_id, app_class, shell, marks};
|
return {app_id, app_class, shell, marks};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace waybar::modules::sway {
|
|||||||
|
|
||||||
// Helper function to assign a number to a workspace, just like sway. In fact
|
// Helper function to assign a number to a workspace, just like sway. In fact
|
||||||
// this is taken quite verbatim from `sway/ipc-json.c`.
|
// this is taken quite verbatim from `sway/ipc-json.c`.
|
||||||
int Workspaces::convertWorkspaceNameToNum(std::string name) {
|
int Workspaces::convertWorkspaceNameToNum(const std::string& name) {
|
||||||
if (isdigit(name[0]) != 0) {
|
if (isdigit(name[0]) != 0) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
char* endptr = nullptr;
|
char* endptr = nullptr;
|
||||||
@@ -487,7 +487,7 @@ std::string Workspaces::getCycleWorkspace(std::vector<Json::Value>::iterator it,
|
|||||||
return (*it)["name"].asString();
|
return (*it)["name"].asString();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Workspaces::trimWorkspaceName(std::string name) {
|
std::string Workspaces::trimWorkspaceName(const std::string& name) {
|
||||||
std::size_t found = name.find(':');
|
std::size_t found = name.find(':');
|
||||||
if (found != std::string::npos) {
|
if (found != std::string::npos) {
|
||||||
return name.substr(found + 1);
|
return name.substr(found + 1);
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ UPower::~UPower() {
|
|||||||
removeDevices();
|
removeDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::string getDeviceStatus(UpDeviceState& state) {
|
static std::string_view getDeviceStatus(UpDeviceState& state) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case UP_DEVICE_STATE_CHARGING:
|
case UP_DEVICE_STATE_CHARGING:
|
||||||
case UP_DEVICE_STATE_PENDING_CHARGE:
|
case UP_DEVICE_STATE_PENDING_CHARGE:
|
||||||
@@ -112,7 +112,7 @@ static const std::string getDeviceStatus(UpDeviceState& state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::string getDeviceIcon(UpDeviceKind& kind) {
|
static std::string_view getDeviceIcon(UpDeviceKind& kind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case UP_DEVICE_KIND_LINE_POWER:
|
case UP_DEVICE_KIND_LINE_POWER:
|
||||||
return "ac-adapter-symbolic";
|
return "ac-adapter-symbolic";
|
||||||
@@ -212,7 +212,8 @@ auto UPower::update() -> void {
|
|||||||
// Remove last status if it exists
|
// Remove last status if it exists
|
||||||
if (!lastStatus_.empty() && box_.get_style_context()->has_class(lastStatus_))
|
if (!lastStatus_.empty() && box_.get_style_context()->has_class(lastStatus_))
|
||||||
box_.get_style_context()->remove_class(lastStatus_);
|
box_.get_style_context()->remove_class(lastStatus_);
|
||||||
if (!box_.get_style_context()->has_class(status)) box_.get_style_context()->add_class(status);
|
if (!box_.get_style_context()->has_class(std::string(status)))
|
||||||
|
box_.get_style_context()->add_class(std::string(status));
|
||||||
lastStatus_ = status;
|
lastStatus_ = status;
|
||||||
|
|
||||||
if (devices_.size() == 0 && !upDeviceValid && hideIfEmpty_) {
|
if (devices_.size() == 0 && !upDeviceValid && hideIfEmpty_) {
|
||||||
|
|||||||
@@ -4,11 +4,12 @@
|
|||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <thread>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "util/sleeper_thread.hpp"
|
#include "util/sleeper_thread.hpp"
|
||||||
|
|
||||||
namespace waybar::util {
|
namespace waybar::util {
|
||||||
|
|||||||
Reference in New Issue
Block a user