Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG]: Maybe a perf issue (high CPU & fan speed) #862

Closed
KevinNitroG opened this issue Jun 2, 2024 · 55 comments
Closed

[BUG]: Maybe a perf issue (high CPU & fan speed) #862

KevinNitroG opened this issue Jun 2, 2024 · 55 comments
Labels
bug Something isn't working

Comments

@KevinNitroG
Copy link

Describe the bug

I think the version 0.1.26 has a performance issue. I have noticed many times that after using komorebi for a while, my computer's fan goes up and my CPU is about higher + 3-5%. It will end up by restarting komorebi (komorebi stop and then komorebi start), and the issue comes back after using for a while again.

To Reproduce

Steps to reproduce the behavior:

  1. Use for a while (about > 30 mins)

Expected behaviour

No High CPU and Fan speed

Screenshots and Videos

In the video, we cannot see clearly the amount of CPU that komorebi took. But it affects my computer's CPU and Fan speed that I can feel it.

Video

Operating System

OS Name:                   Microsoft Windows 11 Home
OS Version:                10.0.22631 N/A Build 22631

komorebic check Output

KOMOREBI_CONFIG_HOME detected: C:\Users\kevinnitro\.config\komorebi

Looking for configuration files in C:\Users\kevinnitro\.config\komorebi

Found komorebi.json; this file can be passed to the start command with the --config flag

Found C:\Users\kevinnitro\.config\whkdrc; key bindings will be loaded from here when whkd is started, and you can start it automatically using the --whkd flag

Additional context

I use AHK. There are few more unrelated config, but I just want to let you know for a more details analysis. My full AHK script is:

#SingleInstance Force

SetTitleMatchMode 3
DetectHiddenWindows true

; #Warn All, Off

; # Left Win
; ^ Ctrl
; ! Alt
; + Shift

#Include "komorebi/komorebic.lib.ahk"

; --- CONFIG ---

#Backspace::try ControlSend "!{F4}",, "ahk_class Progman"
^#!r::Reload

; --- RUN APP VIA KEYBOARD SHORTCUT ---

#Enter::Run "wt.exe"
#t::Run "alacritty.exe"
#c::Run "code.exe"
#b::Run "chrome.exe"
#s::Run "C:\Users\kevinnitro\AppData\Roaming\Spotify\Spotify.exe"

; --- ALT TO SWITCH TAB IN BROWSER ---

GroupAdd "Browser", "ahk_exe arc.exe"
GroupAdd "Browser", "ahk_exe brave.exe"
GroupAdd "Browser", "ahk_exe chrome.exe"
GroupAdd "Browser", "ahk_exe chromium.exe"
GroupAdd "Browser", "ahk_exe edge.exe"
GroupAdd "Browser", "ahk_exe firefox.exe"
GroupAdd "Browser", "ahk_exe thorium.exe"

#HotIf WinActive("ahk_group Browser")

!1::^1
!2::^2
!3::^3
!4::^4
!5::^5
!6::^6
!7::^7
!8::^8
!9::^9

#HotIf

; --- UNIKEY ---

#space::!z

; Cannot use bellow :v, UniKeyNT doesn't read the key
; #space::try ControlSend "!z",, "ahk_exe UniKeyNT.exe"

; --- KOMOREBI ---

#^o::ReloadConfiguration()
#^+r:: {
  try RunWait("komorebic.exe stop", , "Hide")
  RunWait("komorebic.exe start", , "Hide")
}

#1::FocusWorkspace(0)
#2::FocusWorkspace(1)
#3::FocusWorkspace(2)
#4::FocusWorkspace(3)
#5::FocusWorkspace(4)
#6::FocusWorkspace(5)
#7::FocusWorkspace(6)
#8::FocusWorkspace(7)
#9::FocusWorkspace(8)
#0::FocusWorkspace(9)

#[::CycleWorkspace("previous")
#]::CycleWorkspace("next")

#+1::MoveToWorkspace(0)
#+2::MoveToWorkspace(1)
#+3::MoveToWorkspace(2)
#+4::MoveToWorkspace(3)
#+5::MoveToWorkspace(4)
#+6::MoveToWorkspace(5)
#+7::MoveToWorkspace(6)
#+8::MoveToWorkspace(7)
#+9::MoveToWorkspace(8)
#+0::MoveToWorkspace(9)

#+[::CycleMoveToWorkspace("previous")
#+]::CycleMoveToWorkspace("next")

#Left::Focus("left")
#Down::Focus("down")
#Up::Focus("up")
#Right::Focus("right")
^#+[::CycleFocus("previous")
^#+]::CycleFocus("next")

^#+Left::Move("left")
^#+Down::Move("down")
^#+Up::Move("up")
^#+Right::Move("right")
^#p::Promote()

#+Right::ResizeAxis("horizontal", "increase")
#+Left::ResizeAxis("horizontal", "decrease")
#+Up::ResizeAxis("vertical", "increase")
#+Down::ResizeAxis("vertical", "decrease")

#w::ToggleFloat()
#m::Minimize()
#q::Close()
^#t::ToggleTiling() ; avoid with opening terminal
#z::ToggleMonocle()
; !Enter::F11 ; Toggle fullscreen
^#r::Retile()
^#+p::TogglePause()

^#h::Stack("left")
^#l::Stack("right")
^#k::Stack("up")
^#j::Stack("down")
^#;::Unstack()

#x::FlipLayout("horizontal")
#y::FlipLayout("vertical")

My full komorebi.json:

{
  "app_specific_configuration_path": "$Env:USERPROFILE/.config/komorebi/applications.yaml",
  "window_border": true,
  "border_style": "System",
  "border_colours": {
    "monocle": "#F9E2AF",
    "single": "#B4BEFE",
    "stack": "#CBA6F7",
    "unfocused": "#45475A"
  },
  "border_offset": -2,
  "border_width": 6,
  "cross_monitor_move_behaviour": "Insert",
  "default_container_padding": 0,
  "default_workspace_padding": 0,
  "manage_rules": [
    {
      "id": "Messenger.exe",
      "kind": "Exe"
    },
    {
      "id": "MicrosoftWhiteboard.exe",
      "kind": "Exe"
    }
  ],
  "float_rules": [
    {
      "id": "Authy Desktop.exe",
      "kind": "Exe",
      "matching_strategy": "Equals"
    },
    {
      "id": "Cloudflare WARP.exe",
      "kind": "Exe",
      "matching_strategy": "Equals"
    }
  ],
  "border_overflow_applications": [],
  "monitors": [
    {
      "workspaces": [
        {
          "name": "0",
          "layout": "BSP",
          "workspace_rules": [
            {
              "id": "arc.exe",
              "kind": "Exe"
            },
            {
              "id": "chrome.exe",
              "kind": "Exe"
            },
            {
              "id": "edge.exe",
              "kind": "Exe"
            },
            {
              "id": "firefox.exe",
              "kind": "Exe"
            },
            {
              "id": "opera.exe",
              "kind": "Exe"
            }
          ]
        },
        {
          "layout": "BSP",
          "name": "1",
          "workspace_rules": [
            {
              "id": "explorer.exe",
              "kind": "Exe"
            }
          ]
        },
        {
          "name": "2",
          "layout": "BSP"
        },
        {
          "name": "3",
          "layout": "BSP"
        },
        {
          "name": "4",
          "layout": "BSP"
        },
        {
          "name": "5",
          "layout": "BSP"
        },
        {
          "name": "6",
          "layout": "BSP"
        },
        {
          "name": "7",
          "layout": "BSP",
          "workspace_rules": [
            {
              "id": "obs64.exe",
              "kind": "Exe"
            },
            {
              "id": "obs32.exe",
              "kind": "Exe"
            }
          ]
        },
        {
          "name": "8",
          "layout": "BSP",
          "workspace_rules": [
            {
              "id": "vlc.exe",
              "kind": "Exe"
            },
            {
              "id": "Spotify.exe",
              "kind": "Exe"
            }
          ]
        },
        {
          "name": "9",
          "workspace_rules": [
            {
              "id": "Messenger.exe",
              "kind": "Exe"
            },
            {
              "id": "zalo.exe",
              "kind": "Exe"
            }
          ]
        }
      ]
    }
  ],
  "mouse_follows_focus": false,
  "resize_delta": 20,
  "window_hiding_behaviour": "Cloak",
  "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.22/schema.json"
}
@KevinNitroG KevinNitroG added the bug Something isn't working label Jun 2, 2024
@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 2, 2024

Can you try taking some measurements with a command line tool like https://github.com/ClementTsang/bottom?

We'll need some numbers in order to investigate this further

@KevinNitroG
Copy link
Author

Can you try taking some measurements with a command line tool like ClementTsang/bottom?

We'll need some numbers in order to investigate this further

Thank you for your reply. I will record another video with bottom later when the issue comes up.

@KevinNitroG
Copy link
Author

@LGUG2Z Here is the video using bottom.

Video with bottom

The fastest way to reproduce this is by switching workspaces continuously (about 100 times? - instead of using komorebi for a while).

@KevinNitroG
Copy link
Author

KevinNitroG commented Jun 2, 2024

I will use the older version 0.1.25 and check if the issue appears or not. Then I will let you know later.

Edit:

I uninstall using

scoop uninstall komorebi -p
scoop cleanup -a

Then install using

scoop install komorebi@0.1.25

the output

WARN  Given version (0.1.25) does not match manifest (0.1.26)
WARN  Attempting to generate manifest for 'komorebi' (0.1.25)
Autoupdating komorebi
Downloading komorebi-0.1.25-x86_64-pc-windows-msvc.zip to compute hashes!
Loading komorebi-0.1.25-x86_64-pc-windows-msvc.zip from cache
Computed hash: 8da0d8f4f5316ef2be2c6217296d3b57391ef5349761ec56e540697602435d91
Writing updated komorebi manifest
Installing 'komorebi' (0.1.25) [64bit] from 'C:\Users\kevinnitro\scoop\workspace\komorebi.json'
Loading komorebi-0.1.25-x86_64-pc-windows-msvc.zip from cache
Checking hash of komorebi-0.1.25-x86_64-pc-windows-msvc.zip ... ok.
Extracting komorebi-0.1.25-x86_64-pc-windows-msvc.zip ... done.
Linking ~\scoop\apps\komorebi\current => ~\scoop\apps\komorebi\0.1.25
Creating shim for 'komorebi'.
Creating shim for 'komorebic'.
Creating shim for 'komorebic-no-console'.
Making C:\Users\kevinnitro\scoop\shims\komorebic-no-console.exe a GUI binary.
Creating shim for 'komorebi-gui'.
Get-Command: C:\Users\kevinnitro\scoop\apps\scoop\current\lib\install.ps1:783
Line |
 783 |              $bin = (Get-Command $target).Source
     |                      ~~~~~~~~~~~~~~~~~~~
     | The term 'komorebi-gui.exe' is not recognized as a name of a cmdlet, function, script file, or executable program. Check the spelling of
     | the name, or if a path was included, verify that the path is correct and try again.
Can't shim 'komorebi-gui.exe': File doesn't exist.

But komorebi still works

@KevinNitroG
Copy link
Author

Update: I can confirm that the version 0.1.25 has no problem with high CPU and fan speed 😶‍🌫️

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 2, 2024

Looking at your first video where you isolate the komorebi process: the ~20% CPU usage you point to is the total CPU usage across all running processes; komorebi's CPU usage is still 0%.

Similarly for the video with btm komorebi's CPU usage seems to peak at 0.1%.

Generally we target <1% CPU usage for komorebi running in the background and it seems like your measurements are consistent with that.

However I did notice that you seem to be running in 32-bit mode, while you are running other applications such as OBS in 64-bit mode? When you are running previous versions of komorebi are you also making them run in 32-bit mode?

@KevinNitroG
Copy link
Author

KevinNitroG commented Jun 2, 2024

Looking at your first video where you isolate the komorebi process: the ~20% CPU usage you point to is the total CPU usage across all running processes; komorebi's CPU usage is still 0%.

Similarly for the video with btm komorebi's CPU usage seems to peak at 0.1%.

Generally we target <1% CPU usage for komorebi running in the background and it seems like your measurements are consistent with that.

However I did notice that you seem to be running in 32-bit mode, while you are running other applications such as OBS in 64-bit mode? When you are running previous versions of komorebi are you also making them run in 32-bit mode?

Currently, I'm back to 0.1.25 and all of the versions I use, they are all run at 32-bit mode sir.
image
Also I don't know how to run komorebi in 64-bit mode 😥

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 2, 2024

I wonder if that 32-bit binary is the shim from scoop? 🤔

Since none of the measurements suggest that komorebi is using any more CPU resources than normal, can you check the logs and see and share if there is anything interesting happening there, like threads crashing and restarting?

@KevinNitroG
Copy link
Author

I wonder if that 32-bit binary is the shim from scoop? 🤔

Since none of the measurements suggest that komorebi is using any more CPU resources than normal, can you check the logs and see and share if there is anything interesting happening there, like threads crashing and restarting?

Recently I tried to back to 0.1.26 and try to check the log with komorebic log. I switch between workspaces and there is no warning, or error log (except high CPU every time checking the log lifetime in the terminal - around + [20, 30] % 😐). But I will try again later and let you know if there is any warning or error log.

@KevinNitroG
Copy link
Author

After trying to get some logs in the 0.1.26 version, There were some logs that also occurred in 0.1.25 so I think we cannot find the problem via log 😥.

  1. There was an error whenever I spawned a new window / app. For example Spotify (always at a specific workspace)
    2024-06-02T16:52:13.127031Z ERROR komorebi::process_event: there is no container/window
    
  2. Also when I resized a window, there were warnings that the window could not be resized, but in fact, it was resized normally.
    2024-06-02T17:10:59.299093Z  WARN process_command{ResizeWindowAxis(Horizontal, Decrease)}:resize_window{direction=Left sizing=Decrease delta=20
    

After some try, it couldn't run komorebic log again and showed an error

Error: The system cannot find the file specified. (os error 2)

Location:
    komorebic\src\main.rs:1499:40

I did restart komorebi, but it couldn't show the log and threw the same error. Same with reinstalling komorebi. (note that 0.1.26)


Then I went back to 0.1.25 and it could show log normally.


Then I reinstalled 0.1.26, and it threw the same error when using komorebic log

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 2, 2024

🤦‍♀️ I forgot there was a regression in the log command that was fixed here on master: 1320b74

Can you try running v0.1.27-dev.0 from the latest commit on the master branch?

@KevinNitroG
Copy link
Author

KevinNitroG commented Jun 2, 2024

🤦‍♀️ I forgot there was a regression in the log command that was fixed here on master: 1320b74

Can you try running v0.1.27-dev.0 from the latest commit on the master branch?

So I need to build from source right? I have never built a rust project before 😂 Alright I will give it a try tomorrow. And grab if there is any valuable log.

Edit: Is that possible to run directly the .exe from the artifact of github action's workflow, I wonder?

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 2, 2024

Yeah you can replace the exes on your system with the exes from GitHub actions ^

@KevinNitroG
Copy link
Author

@LGUG2Z

The issue (High CPU) still exists in fix(cli): make quickstart respect whkd config dir #2003. And there wasn't any valuable log. 😥

@thomasroodnl
Copy link

Dear @KevinNitroG , @LGUG2Z

I seem to be having a similar issue since v0.1.26. In Task Manager komorebi.exe CPU usage is reported in the 25%-50% range on idle, and by bottom in the 8-12% range. If I relaunch komorebi it goes back to <1% (on both). I can reproduce it by launching komorebi (which now has all of my windows (~8) in the first workspace) and quickly switching between it and the empty second workspace. Doing this about 20-30 times already gets me in the 4-8% idle CPU usage on bottom.

I tried it with less windows (4) and closed some nefarious applications like PyCharm, and I can still reproduce the increased idle CPU.

I think that during my normal workflow this problem gradually increases the idle CPU usage until all my applications start hanging due to how busy the CPU is. Another thing I note is that my active_window_borders disappear after some time, which may or may not be related to this issue.

My setup is as follows:

komorebi.json:

{
  "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.26/schema.json",
  "app_specific_configuration_path": "C:/Users/trood/Repos/komorebi-config/applications.yaml",
  "window_hiding_behaviour": "Cloak",
  "cross_monitor_move_behaviour": "Insert",
  "float_rules": [], // REDACTED
  "unmanaged_window_operation_behaviour": "Op",
  "default_workspace_padding": 1,
  "default_container_padding": 1,
  "border_padding": 0,
  "border_offset": 0,
  "active_window_border": true,
  "border_width": 3,
  "global_work_area_offset": {"bottom":  -40, "left": 0, "right":  0, "top":  0},
  "active_window_border_colours": {
    "single": "#7582f8",
    "stack": "#7582f8",
    "monocle": "#9a45fa"
  },
  "monitors": [
    {
      "workspaces": [
        { "name": "0_I", "layout": "VerticalStack" },
        { "name": "0_II", "layout": "VerticalStack" },
        { "name": "0_III", "layout": "VerticalStack" },
        { "name": "0_IV", "layout": "VerticalStack" },
        { "name": "0_V", "layout": "VerticalStack" }
      ]
    },
    {
      "workspaces": [
        { "name": "1_I", "layout": "VerticalStack" },
        { "name": "1_II", "layout": "VerticalStack" },
        { "name": "1_III", "layout": "VerticalStack" },
        { "name": "1_IV", "layout": "VerticalStack" },
        { "name": "1_V", "layout": "VerticalStack" }
      ]
    },
    {
      "workspaces": [
        { "name": "2_I", "layout": "Rows" },
        { "name": "2_II", "layout": "Rows" },
        { "name": "2_III", "layout": "Rows" },
        { "name": "2_IV", "layout": "Rows" },
        { "name": "2_V", "layout": "Rows" }
      ]
    }
  ]
}

OS:

Edition	Windows 10 Pro
Version	22H2
Installed on	‎06/‎12/‎2022
OS build	19045.4412
Experience	Windows Feature Experience Pack 1000.19056.1000.0

It is maybe also good to note that I use yasb, and AutoHotkey v1 for my keybinds.

If there is anything that I could test to help track down the problem, please let me know.

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 7, 2024

Another thing I note is that my active_window_borders disappear after some time, which may or may not be related to this issue.

This one at least I believe should be fixed on master:

3232d92
6c90001

I'm still not able to reproduce this on my end, but I will keep trying - It's possible there are some lock contention issues that only trigger under very specific conditions

@thomasroodnl
Copy link

Ah that is good to hear, I will try building the current master! In the meantime, I tried reproducing it without yasb and I get the same issue so at least it is not that.

@starise
Copy link

starise commented Jun 8, 2024

I have the same issue described by @thomasroodnl : I'm working, time passes (hours) and the CPU usage increases until at some point I'm forced to exit komorebi to stop the system being slow. After komorebic stop all back to normal. In my workflow I also change workspaces several times during the day, moving windows around between workspaces.

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 8, 2024

Is anyone able to reproduce this with borders off?

My working theory is that this comes down to the locks on Mutexes when handling WM_PAINT on border windows, and this becomes more and more noticable depending on the number of windows on each workspace that the user switches between.

@starise
Copy link

starise commented Jun 8, 2024

Is anyone able to reproduce this with borders off?

Changed my config to "border": false. I'll let you know.

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 9, 2024

I've been making some small performance refactors in the border manager's hot path here:

493531e
0940fce

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 9, 2024

6b9a084

This should also change the rate at which we trigger the border manager's hot path.

@thomasroodnl
Copy link

Is anyone able to reproduce this with borders off?

My working theory is that this comes down to the locks on Mutexes when handling WM_PAINT on border windows, and this becomes more and more noticable depending on the number of windows on each workspace that the user switches between.

I just tried to replicate it with the borders off and it seems like the issue indeed does not appear. CPU usage stays <1% (in bottom) both wile switching workspaces and afterwards. I will now build the latest from master and see what the performance is like with the borders enabled.

@starise
Copy link

starise commented Jun 11, 2024

Same here. Monitored for an entire day with borders disabled and no issues so far.

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 11, 2024

Any updates to report with the latest changes on the master branch? 🤞

@thomasroodnl
Copy link

Apologies, I have been running without borders enabled since this was working well so I forgot to check. I recompiled from master just now. With borders enabled I can still elicit the high idle CPU usage with the method as described before.

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 11, 2024

Some elevated CPU usage is expected for expensive operations like this, especially when spamming workspace changes quickly over a few seconds to force a repro - but does the CPU usage continue to climb and stay high during normal usage and when idling on a single workspace?

@thomasroodnl
Copy link

Yes that makes sense. In this 'aggressive' reproduction it stays high when idling on a workspace for at least around 5 mins, I have not tested it for a longer period of time as I had to go back to using my pc. To validate further, I will enable the borders during normal usage and keep an eye on the CPU in idle.

@starise
Copy link

starise commented Jun 11, 2024

I'm testing this artifact today with borders on, and after a couple hours the system started to be sluggish with komorebi cpu usage from ~6-8% (in idle) to ~13-14% (peaks).

Tried a couple of komorebic border disable; komorebic border enable from PS but actually CPU usage increased a bit in idle. Only way to free resource is to start fresh with komorebic stop; komorebic start.

komorebi cpu usage

@starise
Copy link

starise commented Jun 11, 2024

Can you share your hardware stats? For ref, I am testing this on a Ryzen 5900x

Sure, same CPU here 😅 - OS : Windows 11 (10.0.26100.712) - CPU : Ryzen 5900X - RAM : 64 GB - VGA: Radeon RX 6800 XT - Display (single) @ 2160p, 120Hz, 200% scaling. I'm using komorebi with 4 workspaces and these are my common apps: explorer, terminal, firefox, vscode, xnview mp, figma, davinci resolve.

@thomasroodnl
Copy link

Today I used komorebi with the borders enabled without any violent workspace shifting. After around 4 hours the CPU usage was noticeably high in idle (4-8%), even after not doing any window switches for several minutes. I performed the profiling like you requested and got the following summary:

image

During this recording I did not interact with the machine. Please let me know if you need a different view of this trace or need me to send you the trace file (I'd need to figure out how first).

Oh and also, the 'potato laptop' hit home :). I am running a 12th Gen Intel(R) Core(TM) i7-1255U, and 16 GB of RAM. No dedicated graphics card. Current test was with single display @ 1440p, 100Hz, 100% scaling. 5 workspaces.

@CtByte
Copy link
Contributor

CtByte commented Jun 12, 2024

I've been using Komorebi for 7 hours now with borders and transparency enabled. I have many windows open (6 terminals, 2 Visual Studio 2022, Teams, Chrome, Firefox, etc)

I did a little test where I grabbed a window an observed the CPU usage:

Recording.2024-06-12.145005.Moving.window.-.Dedicated.mp4

I only observed considerable CPU usage while I was holding the window. It went back to 0%

I am using the 67a3c35 version which I built myself using Visual Studio 2022. I copied the exe files to the c:\Program Files\komorebi\bin\ folder. I don't really think that it has anything to do with the files you are testing with, but I thought I mention it.

I use stackbar a lot and having transparency+borders does not seem to be an issue for me.

Could this have more to do with workspaces? or perhaps the fact that you don't have dedicated GPU to render the borders and other graphical intense workloads so Windows reserves a bit of the CPU for when it needs to use the integrated GPU (it does that with RAM)?

OS Name:                   Microsoft Windows 11 Pro
OS Version:                10.0.22631 N/A Build 22631
CPU:                       12th Gen Intel(R) Core(TM) i9-12900H
GPU:                       NVIDIA GeForce RTX 3070 Ti Laptop GPU
RAM:                       48 GB

Edit: After reading a bit more above, I can see that others with a dedicated GPU have similar issues. This one is difficult to crack.

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 12, 2024

Since this issue is getting quite long, here is a quick summary of what the investigation so far has shown:

  • The core issue is not that drawing borders and changing workspaces consumes CPU cycles, but that komorebi.exe continues to consume CPU cycles at a growing rate over the lifetime of the process
  • There is no clear reproduction for this core issue - this only presents on the machines of some users, but not all users
  • The exact combination of conditions required for the core issue to present for the impacted subset of users remains unknown
    • One of the conditions for the core issue to present for the impacted subset of users is enabling borders
    • The core issue has not presented for people using dedicated Nvidia graphics cards
    • The core issue has presented on both Intel and AMD CPUs
  • Although there have been significant performance improvements after code changes shared earlier in this thread in the extreme case of rapidly switching workspaces (on my machine, v0.1.26 has this going up to 4-5% CPU usage, and master has it always under 1.5% CPU usage), these changes have not addressed the core issue

A few things that come to mind for the next steps:

  • Since the core issue only presents when borders are enabled, we should continue looking in the border_manager module
  • Since we have already aggressively optimized our own logic in border_manager, the underlying issue is probably somewhere in the Win32 system calls we are making
  • The Win32 system calls in the border manager are in the update and callback functions
    • update triggers InvalidateRect which triggers the WM_PAINT message being sent to each border window

pub fn update(&self, rect: &Rect) -> color_eyre::Result<()> {
// Make adjustments to the border
let mut rect = *rect;
rect.add_margin(BORDER_WIDTH.load(Ordering::SeqCst));
rect.add_padding(-BORDER_OFFSET.load(Ordering::SeqCst));
// Update the position of the border if required
if !WindowsApi::window_rect(self.hwnd())?.eq(&rect) {
WindowsApi::set_border_pos(self.hwnd(), &rect, HWND((Z_ORDER.load()).into()))?;
}
// Invalidate the rect to trigger the callback to update colours etc.
self.invalidate();
Ok(())

WM_PAINT => {
// With the rect that we set in Self::update
if let Ok(rect) = WindowsApi::window_rect(window) {
// Grab the focus kind for this border
let focus_kind = {
FOCUS_STATE
.lock()
.get(&window.0)
.copied()
.unwrap_or(WindowKind::Unfocused)
};
// Set up the brush to draw the border
let mut ps = PAINTSTRUCT::default();
let hdc = BeginPaint(window, &mut ps);
let hpen = CreatePen(
PS_SOLID | PS_INSIDEFRAME,
BORDER_WIDTH.load(Ordering::SeqCst),
COLORREF(match focus_kind {
WindowKind::Unfocused => UNFOCUSED.load(Ordering::SeqCst),
WindowKind::Single => FOCUSED.load(Ordering::SeqCst),
WindowKind::Stack => STACK.load(Ordering::SeqCst),
WindowKind::Monocle => MONOCLE.load(Ordering::SeqCst),
}),
);
let hbrush = WindowsApi::create_solid_brush(0);
// Draw the border
SelectObject(hdc, hpen);
SelectObject(hdc, hbrush);
// TODO(raggi): this is approximately the correct curvature for
// the top left of a Windows 11 window (DWMWCP_DEFAULT), but
// often the bottom right has a different shape. Furthermore if
// the window was made with DWMWCP_ROUNDSMALL then this is the
// wrong size. In the future we should read the DWM properties
// of windows and attempt to match appropriately.
match STYLE.load() {
BorderStyle::System => {
if *WINDOWS_11 {
RoundRect(hdc, 0, 0, rect.right, rect.bottom, 20, 20);
} else {
Rectangle(hdc, 0, 0, rect.right, rect.bottom);
}
}
BorderStyle::Rounded => {
RoundRect(hdc, 0, 0, rect.right, rect.bottom, 20, 20);
}
BorderStyle::Square => {
Rectangle(hdc, 0, 0, rect.right, rect.bottom);
}
}
EndPaint(window, &ps);
DeleteObject(hpen);
DeleteObject(hbrush);
ValidateRect(window, None);
}
LRESULT(0)
}

Although this is not documented in the WM_PAINT docs, there is an old StackOverflow comment which states:

This is entirely normal. Windows generates the WM_PAINT message when your window's update region in not empty. What you are supposed to do is mark it empty again. You do so, for example, by calling Begin/EndPaint().

If you don't then Windows immediately generates yet another WM_PAINT message, still trying to get the update region emptied. Your thread will burn 100% core, idly processing WM_PAINT messages and not actually getting the job done. Maybe you are actually painting, Windows just doesn't know what you painted and doesn't try to guess at it.

Using Begin/EndPaint() is very much the sane way to get that job done. It isn't the only way, you could also call ValidateRect() or ValidateRgn(). As long as you are "new to winapi", I'd very strongly recommend you do this the normal way.

Since we are calling if let Ok(rect) = WindowsApi::window_rect(window) {} as the very first step in the WM_PAINT handler, it's possible that this call could fail, triggering the WM_PAINT message loops for a small subset of borders. We don't have any logging here to validate whether or not this is the case, but it should be possible to add both error logging and to push the BeginPaint and EndPaint calls outside of the rect context.

All of the Win32 system calls here are GDI-related, so if you are a game dev using komorebi and you're reading this, please double check all of my assumptions. 😅

Edit: The changes to the WM_PAINT handler have been made on master, and I've also added another change which only triggers the WM_PAINT message if either the focus state or the rect position has changed.

LGUG2Z added a commit that referenced this issue Jun 12, 2024
This commit pushes up the calls to BeginPaint and EndPaint in the border
callback function to ensure that the client area of the border rect is
always validated after calls to InvalidateRect from the update fn.

The callback now also logs errors whenever it is not possible to get the
border rect to operate on for any reason.

There was a call at the end of this logic to ValidateRect which has been
removed as the validation is already handled by the call to BeginPaint.

re #862
LGUG2Z added a commit that referenced this issue Jun 12, 2024
This commit ensures that we only invalidate a border rect to send a
WM_PAINT message either when the position of the focus state of the
border has changed.

re #862
LGUG2Z added a commit that referenced this issue Jun 12, 2024
This commit increases various channel bounds from 5 to 20 since it was
discovered that this reduction had no impact on #862, and some
crashes/freezes have been noted due to the channel bounds of 5 being too
low.
@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 14, 2024

Has anyone been able to run with the latest changes? 🤞

@starise
Copy link

starise commented Jun 14, 2024

I'm testing c022438 right now and the situation looks much better. Changing workspace frequently caused some cpu spikes but nothing dramatic. On idle cpu usage seems under control. I also noticed less memory utilization overall. I'll monitor the situation under a more extensive period of time. I'll keep you updated. 👌

@Q0
Copy link

Q0 commented Jun 15, 2024

I’m sitting on c022438 and in general everything is very stable. I have never had a window border break (previously it often broke when actively working with windows). The review is positive.

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 15, 2024

@thomasroodnl @KevinNitroG if either if you can also confirm the improvements on your end we should be able to close this and begin the next release cycle 🤞

@thomasroodnl
Copy link

Great to hear the changes seem to be having the desired effect :). I'm sorry, I haven't had the opportunity yet to build the latest version and run it, but I will give it a try coming Monday and report my findings.

@KevinNitroG
Copy link
Author

KevinNitroG commented Jun 16, 2024

@LGUG2Z Hi again. I think the commit c022438 is fine now. I haven't had enough long time to test but within an hour, my CPU's fan doesn't complain about komorebi anymore.

Also, this is not related to this issue. If I use komorebic close while on the desktop, it will close the windows explorer which makes the icon disappear. Is it ... a feature? 😶‍🌫️

Thank you for having looked into the bug. Love your project!

EDIT: BUT WAIT... 😅
Please let us test a bit more. I just want to ensure whether the issue is gone completely or not.

Edit: Not yet fine...

@KevinNitroG
Copy link
Author

KevinNitroG commented Jun 17, 2024

@LGUG2Z. I'm testing c022438 for more than an hour and it seems that the issue hasn't gone completely yet I guess. My fan still goes up, but the CPU doesn't show that much, and I can only show you via the CPU temp.

2024-06-17_10-36-19.mp4

After restarting komorebi, my fan goes down.


I will test it again and feedback to you later. But I think I will leave this issue soon because of personal busy. 😅

@KevinNitroG
Copy link
Author

2024-06-17_11-21-31.mp4

Here is another video shows that my CPU temp is high, and decrease after restarting komorebi

@thomasroodnl
Copy link

From a quick look the CPU performance seems largely improved. I can still repro the high idle CPU usage with the fast workspace switching, but I will just run it normally throughout the day and see how the idle looks for me under a more realistic workload. In any case, thanks for the improvements!

@thomasroodnl
Copy link

Just ran it for 4 hours on normal use. Idle komorebi CPU usage hovers around 1-4%. For me this is fine honestly, I haven't noticed any freezing or slowdown due to the extra CPU usage. But it seems there is still something going on in the background. I wanted to note that in general, the stability of the boundaries has improved significantly for me over the past updates.

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 18, 2024

I'm going to close out this issue now; the core issue that we were able to measure through komorebi's CPU usage growing over time has been resolved, and I don't think we can take any investigation into hardware temperatures further right now since our main metrics (CPU usage) have completely normalized.

@LGUG2Z LGUG2Z closed this as completed Jun 18, 2024
@starise
Copy link

starise commented Jun 18, 2024

Sadly I have to report that komorebi cpu usage gone wild again for me right now (Screenshot). 😢 I noticed that every time I switch the workspace, back and forth, it triggers new "Create Thread" events and never exit the threads.

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 18, 2024

Do you have any errors in the logs which show threads crashing and bring restarted when you are changing workspaces? 🤔

@starise
Copy link

starise commented Jun 18, 2024

You mean komorebic log? I uploaded a small video to show what I mean, I was watching "SimpleProgramDebugger" output and it looks like new threads are created every time I change a workspace, but I'm doing nothing except switching between the same 2 workspaces. The threads remain active and are closed on komorebic stop.

Uploaded a video here (Sry: GitHub has 10MB limit): https://streamable.com/p2x31u

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 18, 2024

These calls to CreateThread aren't being made from komorebi directly to the best of my knowledge, but it may be something in a library that we are calling. Another thing to make sure of is whether we see the same debugger output even when there is no elevated CPU usage 🤔

@starise
Copy link

starise commented Jun 18, 2024

make sure of is whether we see the same debugger output even when there is no elevated CPU usage 🤔

If you take a closer look at my video, the cpu usage of komorebi.exe is very low (launched just in that moment). What has high cpu usage is komorebic.exe (after komorebic log command).

LGUG2Z added a commit that referenced this issue Jun 19, 2024
This commit ensures that message handling threads for windows that are
created by komorebi are exited properly when the windows are destroyed.

For some reason, passing the HWND returned by CreateWindowExW to
GetMessageW continues returning TRUE even after the window has been
destroyed.

If HWND::NULL (via the Default trait) is passed to GetMessageW, which
retrieves messages for any window belonging to the current thread (our
threads here only own a single window), GetMessageW returns FALSE as
expected after the window is destroyed.

re #862
@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 19, 2024

@starise fixed the issue with threads not being terminated for border and stackbar windows ^

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 19, 2024

@KevinNitroG I'm guessing this might also have been the cause of your CPU temp issues 🤔

@KevinNitroG
Copy link
Author

@KevinNitroG I'm guessing this might also have been the cause of your CPU temp issues 🤔

Do you think about reopening this issue, for anyone else having the same issue to find? Because I've just installed the latest version 0.1.27 and the CPU usage is not really positive. I'm staying at 0.1.25 for now...

@LGUG2Z
Copy link
Owner

LGUG2Z commented Jun 20, 2024

the CPU usage is not really positive

I can't really make anything out of statements like these about CPU without hard numbers.

If you have CPU usage readings like this to share, or even better, comparative readings across different versions in similar conditions, it gives people something to investigate.

@KevinNitroG
Copy link
Author

the CPU usage is not really positive

I can't really make anything out of statements like these about CPU without hard numbers.

If you have CPU usage readings like this to share, or even better, comparative readings across different versions in similar conditions, it gives people something to investigate.

Sorry that I couldn't help you much. That's only I can give you about my case. I don't know about threads and how to watch the threads or something. Try komorebic log and nothing seems to be related to the issue. I did try my best to show you the issue has not gone yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants