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:
Austin Horstman
2026-03-02 21:51:32 -06:00
parent fd086d0f33
commit 4c71b2bf9f
24 changed files with 43 additions and 38 deletions

View File

@@ -92,7 +92,7 @@ auto waybar::modules::Disk::update() -> void {
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") {
return 1000.0;
} else if (divisor == "kiB") {

View File

@@ -19,7 +19,7 @@ WindowCreationPayload::WindowCreationPayload(Json::Value const& client_data)
clearWorkspaceName();
}
WindowCreationPayload::WindowCreationPayload(std::string workspace_name,
WindowCreationPayload::WindowCreationPayload(const std::string& workspace_name,
WindowAddress window_address, WindowRepr window_repr)
: m_window(std::move(window_repr)),
m_windowAddress(std::move(window_address)),
@@ -28,9 +28,10 @@ WindowCreationPayload::WindowCreationPayload(std::string workspace_name,
clearWorkspaceName();
}
WindowCreationPayload::WindowCreationPayload(std::string workspace_name,
WindowAddress window_address, std::string window_class,
std::string window_title, bool is_active)
WindowCreationPayload::WindowCreationPayload(const std::string& workspace_name,
WindowAddress window_address,
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_windowAddress(std::move(window_address)),
m_workspaceName(std::move(workspace_name)),

View File

@@ -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;
if (windowRewriteConfigUsesTitle()) {
windowReprKey = fmt::format("class<{}> title<{}>", window_class, window_title);

View File

@@ -85,7 +85,8 @@ auto getInhibitors(const Json::Value& config) -> std::string {
if (config["what"].isArray()) {
inhibitors = checkInhibitor(config["what"][0].asString());
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;
}

View File

@@ -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()) {
return "";
}

View File

@@ -321,6 +321,7 @@ auto waybar::modules::Network::update() -> void {
} else if (addr_pref_ == ip_addr_pref::IPV6) {
final_ipaddr_ = ipaddr6_;
} else if (addr_pref_ == ip_addr_pref::IPV4_6) {
final_ipaddr_.reserve(ipaddr_.length() + ipaddr6_.length() + 1);
final_ipaddr_ = ipaddr_;
final_ipaddr_ += '\n';
final_ipaddr_ += ipaddr6_;

View File

@@ -132,7 +132,7 @@ std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(const std::st
return {service, "/StatusNotifierItem"};
}
void Host::addRegisteredItem(std::string service) {
void Host::addRegisteredItem(const std::string& service) {
std::string bus_name, object_path;
std::tie(bus_name, object_path) = getBusNameAndObjectPath(service);
auto it = std::find_if(items_.begin(), items_.end(), [&bus_name, &object_path](const auto& item) {

View File

@@ -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"}) {
if (const auto& modules = bar_.config.get(section, {}); modules.isArray()) {
for (const auto& module : modules) {

View File

@@ -124,7 +124,7 @@ auto Language::update() -> void {
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);
layout_ = layouts_map_[current_layout];
label_.get_style_context()->add_class(layout_.short_name);

View File

@@ -184,9 +184,9 @@ std::tuple<std::string, std::string, std::string, std::string> getWindowInfo(
continue;
}
if (!marks.empty()) {
marks += ',';
marks.append(",");
}
marks += m.asString();
marks.append(m.asString());
}
}
return {app_id, app_class, shell, marks};

View File

@@ -10,7 +10,7 @@ namespace waybar::modules::sway {
// Helper function to assign a number to a workspace, just like sway. In fact
// 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) {
errno = 0;
char* endptr = nullptr;
@@ -487,7 +487,7 @@ std::string Workspaces::getCycleWorkspace(std::vector<Json::Value>::iterator it,
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(':');
if (found != std::string::npos) {
return name.substr(found + 1);

View File

@@ -95,7 +95,7 @@ UPower::~UPower() {
removeDevices();
}
static const std::string getDeviceStatus(UpDeviceState& state) {
static std::string_view getDeviceStatus(UpDeviceState& state) {
switch (state) {
case UP_DEVICE_STATE_CHARGING:
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) {
case UP_DEVICE_KIND_LINE_POWER:
return "ac-adapter-symbolic";
@@ -212,7 +212,8 @@ auto UPower::update() -> void {
// Remove last status if it exists
if (!lastStatus_.empty() && box_.get_style_context()->has_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;
if (devices_.size() == 0 && !upDeviceValid && hideIfEmpty_) {