Unix/Arch Linux

sway CPU 사용량이 30% 넘게 나올 때 (hybrid graphic + waybar)

ForceCore 2026. 7. 21. 00:55

노트북에서 sway 를 실행하면 아무것도 안 해도 CPU가 30% 정도 먹었다. 그것 때문에 한동안 i3를 쓰고 있었지만 sway만의 편의기능들도 있었기에 점점 불편해졌다. 원래 그런가하면 아니었다. 다른 데스크탑에 sway를 설치하면 보통 1% 이하정도 CPU 사용량이 된다.

Sway가 NVIDIA 그래픽카드를 지원 안 하니까 원래 그런가했지만 이번에 고치는데 성공했다.

증상 확인

먼저 내가 같은 상황인지부터 본다.

htop

몇 분 그냥 켜놓고 지켜봐도 sway의 CPU 점유율이 안 내려가면 아래로 간다.

1. 모니터가 어느 GPU에 물려있는지 확인한다

하이브리드 그래픽 노트북은 iGPU/dGPU 중 하나에 출력 포트가 물리적으로 연결돼 있다. sway가 렌더링하는 GPU와 실제로 화면에 물려있는 GPU가 다르면, 매 프레임마다 한쪽 GPU에서 그린 걸 다른 쪽 GPU로 복사해서 넘겨야 한다.

lspci -k | grep -A3 -i vga
00:02.0 VGA compatible controller: Intel Corporation ... UHD Graphics
    Kernel driver in use: i915
01:00.0 VGA compatible controller: NVIDIA Corporation ... GeForce GTX 1660 Ti
    Kernel driver in use: nvidia

이제 /dev/dri/cardN이 각각 어느 PCI 디바이스인지, 그리고 어느 출력 커넥터를 담당하는지 알아내자:

ls -la /sys/class/drm/ | grep -E 'card[0-9]-(HDMI|DP|eDP)|card[0-9]$'
for c in /sys/class/drm/card0 /sys/class/drm/card1; do
  echo "$c -> $(readlink -f $c/device)"
  cat $c/device/uevent | grep DRIVER
done

내 경우 card0-HDMI-A-1 심볼릭 링크가 nvidia 쪽 PCI 주소를 가리키고 있었다. 즉 지금 켜져 있는 외장 모니터(HDMI)가 엔비디아에 GPU에 연결된 것이었다. sway가 기본으로 렌더링에 쓰는 GPU와 다른 GPU였던 거다.

swaymsg -t get_outputs로 지금 켜진(active) 출력이 뭔지 먼저 확인하고 그 커넥터 이름으로 매칭하면 된다.

2. WLR_DRM_DEVICES로 GPU를 고정한다

wlroots가 실제 출력이 물린 GPU 하나만 쓰게 강제한다. /dev/dri/card0가 위에서 확인한 nvidia 쪽이다.

WLR_DRM_DEVICES=/dev/dri/card0

3. 어디에 설정하느냐가 진짜 문제였다

여기서 한참 헤맸다. 아래 두 개는 시도했다가 안 먹혔던 것들이다. 검색해서 온 사람은 이 시행착오 건너뛰어도 된다.

안 먹힌 것 1: ~/.config/environment.d/*.conf

systemd 문서 보면 로그인 환경변수는 이걸 쓰라고 나온다. 그래서 여기다 넣고 재로그인했는데 CPU가 그대로였다.

systemctl --user show-environment | grep WLR_DRM

이걸로 확인해보면 변수는 systemd --user 매니저 안에는 들어가 있다. 근데 sway 프로세스 자체 환경변수엔 없다. sway 안에서 kitty든 konsole든 터미널을 하나 띄우면 그 프로세스는 sway의 자식이라서 sway의 환경변수를 그대로 물려받는다. 거기서 확인하면 된다.

echo $WLR_DRM_DEVICES

아무것도 안 찍히면 sway까지 전달이 안 된 거다.

environment.d는 systemd --user가 직접 띄우는 유닛(예: waybar.service)한테나 적용된다. sddm은 로그인 세션(sway)을 systemd --user를 거치지 않고 PAM 스택에서 바로 exec한다. ps -o pid,ppid,cmd -p $(pgrep sway) 찍어보면 sway의 부모가 sddm-helper다. 그래서 environment.d가 아예 적용될 자리가 없었다.

안 먹힌 것 2: PCI by-path 이름을 그대로 넣기

/dev/dri/card0보다 /dev/dri/by-path/pci-0000:01:00.0-card처럼 고정된 이름을 쓰는 게 더 안전할 것 같아서 이걸로 넣었다. 결과는 로그인 자체가 안 됐다. sddm에서 로그인 눌러도 sway가 아예 안 뜨고 그대로 로그인 화면으로 튕겼다.

셸에서 직접 실행해보면 원인이 나온다.
(로그인 화면에서, Alt+Ctrl+F2, F3 등을 치면 Console 로그인으로 화면이 전환되는데 거기서 로그인 뒤에, WLR_DRM_DEVICES 환경변수를 세팅하고 sway를 실행했음)

[ERROR] [wlr] [backend/session/session.c:340] Failed to open device: '/dev/dri/by-path/pci-0000': No such file or directory
[ERROR] [wlr] [backend/session/session.c:340] Failed to open device: '01': No such file or directory
[ERROR] [wlr] [backend/session/session.c:340] Failed to open device: '00.0-card': No such file or directory
[ERROR] [wlr] [backend/backend.c:245] Found 0 GPUs, cannot create backend

WLR_DRM_DEVICES는 콜론(:)으로 여러 GPU를 구분하는 리스트다. by-path 이름 자체에 pci-0000:01:00.0-card처럼 콜론이 들어있어서 wlroots가 그 콜론 기준으로 잘라버렸다. 여러개의 GPU가 있는 경우 순서대로 처리하려는 것임. 마치 PATH에 여러 경로를 넣을 때 :으로 구분하는 것 처럼. 그래서 /dev/dri/by-path, 01, 00.0-card 세 개의 존재하지도 않는 경로를 열려고 시도하고 GPU를 못 찾아서 죽은 거다. 콜론 없는 이름을 써야 한다. card0 번호가 리부트마다 바뀔 수 있다는 단점은 있는데, GPU 구성이 안 바뀌는 한 실제로는 안정적이다.

실제로 먹힌 곳: /etc/environment

환경변수를 넣을만한 후보는 많이 있지만, 제일 간단한 방법은 /etc/environment 다. 어차피 PC인 것 어렵게 갈 이유가 없다.

/etc/pam.d/sddmsystem-login을 include하고 있고, 거기 pam_env.so가 들어있다. pam_env/etc/environment를 기본으로 읽고, 이건 sddm이 세션을 exec하기 전에 적용된다.

/etc/environment 마지막에 한 줄 추가한다. (수정 전에 sudo cp /etc/environment /etc/environment.bak로 백업해두는 게 좋다.)

WLR_DRM_DEVICES=/dev/dri/card0

깔끔하게 그냥 재부팅. sway 안에서 터미널 켜서 echo $WLR_DRM_DEVICES 찍히는지 먼저 본다. 그 다음 진짜로 GPU를 하나만 물고 있는지는 이걸로 확인한다.

sudo lsof -p $(pgrep -x sway) | grep dri | awk '{print $NF}' | sort -u

card0/renderD128 (nvidia)만 나오고 card1(intel) 쪽은 안 나오면 성공이다. 여기까지 하니까 35% 근처였던 CPU가 10%로 떨어졌다.

4. 그래도 남는 CPU는 waybar 쪽이었다

10%에서 더 안 내려가서 waybar를 꺼봤다. killall waybar. 그러자 5% 밑으로 떨어졌다.

원인은 상단바에 달아놓은 오디오 비주얼라이저(custom/cava_mviz) 모듈이었다. 안에서 cava를 30fps로 계속 돌리고 있었고, 아무 소리가 안 나오고 있어도 무조건 돌아간다. waybar가 그 텍스트를 초당 30번 갱신하니까 sway가 그 영역을 초당 30번 다시 그려야 했다.

ps aux | grep cava
user  9930  7.3  0.0 ... cava -p /tmp/bar_cava_config

이 모듈만 waybar 설정에서 뺐다. ~/.config/waybar/configs/[TOP] Default Laptop 파일의 modules-left에서 아래 줄만 지운다.

전:

"modules-left": [
    "custom/separator#blank",
    "custom/cava_mviz",
    "custom/separator#blank",
    "custom/playerctl",
    ...

후:

"modules-left": [
    "custom/separator#blank",
    "custom/playerctl",
    ...

waybar 재시작(killall waybar && waybar &)하면 적용된다. 여기까지 하면 5% 밑으로 정상화된다. ~1% 정도임.