I have made this program to simulate polybar's bspwm
module. So far, it works flawlessly; however, it consumes too much RAM and CPU (16-30%). I suspect it is the while
loop causing the trouble, but what can be done to reduce resource usage?
use strict;
use warnings;
use Switch;
use List::MoreUtils qw(first_index);
$SIG{INT}=sub{ die "goodnight !\n $!"; };
my $underline='#ffffff';
my $default_background='#51002f';
my $default_workspace_background='#727272';
my $default_workspace_foreground='#ffffff';
my $default_foreground='#ffffff';
my $focussed_background='#000000';
my $focussed_foreground='#ffffff';
my $occupied_background='#3a3a3a';
my $occupied_foreground='#ffffff';
my @desktops=qx/ bspc query -D /;
my @lemonbar_array=();
my $lemonbar_string="%{B$default_background}%{F$default_foreground}%{+u} 0x00400004 %{-u}%{B-}%{F-}";
my $date_string="%{c}%{B$focussed_background}%{F$default_foreground}%{+u} %date %{-u}%{B-}%{F-}";
my $add_this="%{+u}%{B$default_background}%{F$default_foreground} %{A:firefox:} web %{A} %{B-}%{F-} %{B$default_background}%{F$default_foreground} %{A:evince:} pdf %{A} %{B-}%{F-} %{B$default_background}%{F$default_foreground} %{A:libreoffice:} doc %{A} %{B-}%{F-} %{B$default_background}%{F$default_foreground} %{A:firefox youtube.com:} youtube %{A} %{B-}%{F-} %{B$default_background}%{F$default_foreground} %{A:firefox netflix.com:} netflix %{A} %{B-}%{F-} %{B$default_background}%{F$default_foreground} %{A:firefox gmail.com:} gmail %{A} %{B-}%{F-} %{B$default_background}%{F$default_foreground} %{A:firefox protonmail.com:} protonmail %{A} %{B-}%{F-} %{B$default_background}%{F$default_foreground} %{A:nautilus:} files %{A} %{B-}%{F-} %{B$default_background}%{F$default_foreground} %{A:urxvt:} terminal %{A} %{B-}%{F-}%{-u}";
for(my $i=0;$i<=9;$i++){
push(@lemonbar_array,$lemonbar_string);
}
my $current_monitor='';
while() {
my $date=gmtime();
$date_string=~s/%date/$date/;
$current_monitor=qx/bspc query -D -d/;
my $index_current_monitor=first_index { $_ eq $current_monitor } @desktops;
my $index_print=$index_current_monitor+1;
$lemonbar_array[$index_current_monitor]=~s/(?<=B)#.{6}/$focussed_background/;
$lemonbar_array[$index_current_monitor]=~s/(?<=F)#.{6}/$focussed_foreground/;
$lemonbar_array[$index_current_monitor]=~s/0x00.{6}/$index_print/;
for(my $i=0;$i<10;$i++){
if($desktops[$i] ne $current_monitor){
my $i1=$i+1;
$lemonbar_array[$i]=~s/0x00.{6}/$i1/;
if(scalar(my @n=qx/bspc query -N -d $desktops[$i]/) gt 0){
$lemonbar_array[$i]=~s/(?<=B)#\w{6}/$occupied_background/;
$lemonbar_array[$i]=~s/(?<=F)#\w{6}/$occupied_foreground/;
}
else{
$lemonbar_array[$i]=~s/(?<=B)#\w{6}/$default_workspace_background/;
$lemonbar_array[$i]=~s/(?<=F)#\w{6}/$default_workspace_foreground/;
}
}
}
print "%{l}@lemonbar_array $date_string %{r}$add_this\n";
}
-
1\$\begingroup\$ As for cpu, cut down number of shell calls per minute. \$\endgroup\$mpapec– mpapec2018年10月27日 18:52:13 +00:00Commented Oct 27, 2018 at 18:52
1 Answer 1
Overview
It is great that you:
- Used
strict
andwarnings
- Leveraged other people's code by using the
List::MoreUtils
module - Minimized namespace population by importing only needed functions
- Used meaningful names for variables
Performance
It is wasteful to execute these lines inside the while
loop:
my $date=gmtime;
$date_string=~s/%date/$date/;
The substitution only happens once during the first time though the loop.
That is when the literal %date
string is replaced with the
return value of gmtime
. Every other time thorough the loop,
the match never occurs.
Before the loop, store the return value from gmtime
, then interpolate it
directly into the $date_string
, rather than doing a substitution with s///
:
my $date = gmtime;
my $date_string = "%{c}%{B$focussed_background}%{F$default_foreground}%{+u} $date %{-u}%{B-}%{F-}";
Unused code
Remove this line:
use Switch;
The module is not used, and it is notorious for causing problems.
DRY
Since you execute this external command several times, store it in a variable:
my $cmd = 'bspc query ';
Be explicit
The while
has an empty expression:
while()
Although it is documented that
this results in an infinite loop, it is not obvious when looking at the code. It is clearer to use 1
as the expression:
while (1)
Perlish
It is considered more "Perlish" to use map
instead of the for/push
combination for
simple code:
my @lemonbar_array=();
for(my $i=0;$i<=9;$i++){
push(@lemonbar_array,$lemonbar_string);
}
Consider this instead:
my @lemonbar_array = map { $lemonbar_string } 1 .. 10;
Also, instead of the C-style for
loop:
for(my $i=0;$i<10;$i++){
Consider this instead:
for my $i (0 .. 9) {
Long line
Long lines are hard to understand and maintain. This should be broken up:
my $add_this="%{+u}%{B$default_background}%{F$default_foreground} %{A:firefox:} ...
Whitespace
Add a single space before and after these operators for better readability: =
and =~
.
perltidy can be used
to add consistent formatting to your code.
Delete the extra blank lines in the inner for
loop.
else{
$lemonbar_array[$i]=~s/(?<=B)#\w{6}/$default_workspace_background/;
$lemonbar_array[$i]=~s/(?<=F)#\w{6}/$default_workspace_foreground/;
}
Linting
perlcritic identifies some issues.
Trailing whitespace is unnecessary and can be annoying. It should be removed.
Don't use parentheses with built-in functions like gmtime
.
Documentation
Consider adding some usage notes at the top of the file as plain old documentation (POD), something as simple as:
=pod
Simulate polybar's bspwm module.
=cut