linux: Better GPU debugging (#14706)

Release Notes:

- linux: Added GPU information to `editor: Copy System Specs to
Clipboard`
- linux: Show a prominant warning before running under llvmpipe and
similar.
This commit is contained in:
Conrad Irwin 2024-07-23 09:56:45 -06:00 committed by GitHub
parent c262c81e52
commit bdf1d4edea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 136 additions and 48 deletions

27
Cargo.lock generated
View File

@ -1651,7 +1651,7 @@ dependencies = [
[[package]]
name = "blade-graphics"
version = "0.4.0"
source = "git+https://github.com/zed-industries/blade?rev=a477c2008db27db0b9f745715e119b3ee7ab7818#a477c2008db27db0b9f745715e119b3ee7ab7818"
source = "git+https://github.com/zed-industries/blade?rev=7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e#7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e"
dependencies = [
"ash",
"ash-window",
@ -1681,7 +1681,7 @@ dependencies = [
[[package]]
name = "blade-macros"
version = "0.2.1"
source = "git+https://github.com/zed-industries/blade?rev=a477c2008db27db0b9f745715e119b3ee7ab7818#a477c2008db27db0b9f745715e119b3ee7ab7818"
source = "git+https://github.com/zed-industries/blade?rev=7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e#7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e"
dependencies = [
"proc-macro2",
"quote",
@ -1691,7 +1691,7 @@ dependencies = [
[[package]]
name = "blade-util"
version = "0.1.0"
source = "git+https://github.com/zed-industries/blade?rev=a477c2008db27db0b9f745715e119b3ee7ab7818#a477c2008db27db0b9f745715e119b3ee7ab7818"
source = "git+https://github.com/zed-industries/blade?rev=7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e#7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e"
dependencies = [
"blade-graphics",
"bytemuck",
@ -6644,11 +6644,11 @@ dependencies = [
[[package]]
name = "metal"
version = "0.25.0"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "550b24b0cd4cf923f36bae78eca457b3a10d8a6a14a9c84cb2687b527e6a84af"
checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21"
dependencies = [
"bitflags 1.3.2",
"bitflags 2.6.0",
"block",
"core-graphics-types",
"foreign-types 0.5.0",
@ -6749,8 +6749,9 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]]
name = "naga"
version = "0.20.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=425526828f738c95ec50b016c6a761bc00d2fb25#425526828f738c95ec50b016c6a761bc00d2fb25"
version = "22.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09eeccb9b50f4f7839b214aa3e08be467159506a986c18e0702170ccf720a453"
dependencies = [
"arrayvec",
"bit-set 0.6.0",
@ -7180,16 +7181,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
"malloc_buf",
"objc_exception",
]
[[package]]
name = "objc_exception"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
dependencies = [
"cc",
]
[[package]]

View File

@ -295,9 +295,9 @@ async-watch = "0.3.1"
async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] }
base64 = "0.13"
bitflags = "2.6.0"
blade-graphics = { git = "https://github.com/zed-industries/blade", rev = "a477c2008db27db0b9f745715e119b3ee7ab7818" }
blade-macros = { git = "https://github.com/zed-industries/blade", rev = "a477c2008db27db0b9f745715e119b3ee7ab7818" }
blade-util = { git = "https://github.com/zed-industries/blade", rev = "a477c2008db27db0b9f745715e119b3ee7ab7818" }
blade-graphics = { git = "https://github.com/zed-industries/blade", rev = "7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e" }
blade-macros = { git = "https://github.com/zed-industries/blade", rev = "7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e" }
blade-util = { git = "https://github.com/zed-industries/blade", rev = "7e497c534d5d4a30c18d9eb182cf39eaf0aaa25e" }
cap-std = "3.0"
cargo_toml = "0.20"
chrono = { version = "0.4", features = ["serde"] }

View File

@ -1,10 +1,11 @@
use client::telemetry;
use gpui::{AppContext, Task};
use gpui::Task;
use human_bytes::human_bytes;
use release_channel::{AppCommitSha, AppVersion, ReleaseChannel};
use serde::Serialize;
use std::{env, fmt::Display};
use sysinfo::{MemoryRefreshKind, RefreshKind, System};
use ui::WindowContext;
#[derive(Clone, Debug, Serialize)]
pub struct SystemSpecs {
@ -15,10 +16,11 @@ pub struct SystemSpecs {
memory: u64,
architecture: &'static str,
commit_sha: Option<String>,
gpu_specs: Option<String>,
}
impl SystemSpecs {
pub fn new(cx: &AppContext) -> Task<Self> {
pub fn new(cx: &WindowContext) -> Task<Self> {
let app_version = AppVersion::global(cx).to_string();
let release_channel = ReleaseChannel::global(cx);
let os_name = telemetry::os_name();
@ -34,6 +36,15 @@ impl SystemSpecs {
_ => None,
};
let gpu_specs = if let Some(specs) = cx.gpu_specs() {
Some(format!(
"{} || {} || {}",
specs.device_name, specs.driver_name, specs.driver_info
))
} else {
None
};
cx.background_executor().spawn(async move {
let os_version = telemetry::os_version();
SystemSpecs {
@ -44,6 +55,7 @@ impl SystemSpecs {
memory,
architecture,
commit_sha,
gpu_specs,
}
})
}
@ -67,6 +79,11 @@ impl Display for SystemSpecs {
format!("Architecture: {}", self.architecture),
]
.into_iter()
.chain(
self.gpu_specs
.as_ref()
.map(|specs| format!("GPU: {}", specs)),
)
.collect::<Vec<String>>()
.join("\n");

View File

@ -98,7 +98,7 @@ core-text = "20.1"
foreign-types = "0.5"
log.workspace = true
media.workspace = true
metal = "0.25"
metal = "0.29"
objc = "0.2"
[target.'cfg(any(target_os = "linux", target_os = "windows"))'.dependencies]

View File

@ -341,3 +341,16 @@ impl<T> Flatten<T> for Result<T> {
self
}
}
#[derive(Default, Debug)]
/// Information about the GPU GPUI is running on
pub struct GPUSpecs {
/// true if the GPU is really a fake (like llvmpipe) running on the CPU
pub is_software_emulated: bool,
/// Name of the device as reported by vulkan
pub device_name: String,
/// Name of the driver as reported by vulkan
pub driver_name: String,
/// Further driver info as reported by vulkan
pub driver_info: String,
}

View File

@ -24,8 +24,8 @@ mod windows;
use crate::{
point, Action, AnyWindowHandle, AsyncWindowContext, BackgroundExecutor, Bounds, DevicePixels,
DispatchEventResult, Font, FontId, FontMetrics, FontRun, ForegroundExecutor, GlyphId, Keymap,
LineLayout, Pixels, PlatformInput, Point, RenderGlyphParams, RenderImageParams,
DispatchEventResult, Font, FontId, FontMetrics, FontRun, ForegroundExecutor, GPUSpecs, GlyphId,
Keymap, LineLayout, Pixels, PlatformInput, Point, RenderGlyphParams, RenderImageParams,
RenderSvgParams, Scene, SharedString, Size, Task, TaskLabel, WindowContext,
DEFAULT_WINDOW_SIZE,
};
@ -366,6 +366,7 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
}
}
fn set_client_inset(&self, _inset: Pixels) {}
fn gpu_specs(&self) -> Option<GPUSpecs>;
#[cfg(any(test, feature = "test-support"))]
fn as_test(&mut self) -> Option<&mut TestWindow> {

View File

@ -3,9 +3,9 @@
use super::{BladeAtlas, PATH_TEXTURE_FORMAT};
use crate::{
AtlasTextureKind, AtlasTile, Bounds, ContentMask, DevicePixels, Hsla, MonochromeSprite, Path,
PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size,
Underline,
AtlasTextureKind, AtlasTile, Bounds, ContentMask, DevicePixels, GPUSpecs, Hsla,
MonochromeSprite, Path, PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad,
ScaledPixels, Scene, Shadow, Size, Underline,
};
use bytemuck::{Pod, Zeroable};
use collections::HashMap;
@ -451,6 +451,18 @@ impl BladeRenderer {
&self.atlas
}
#[cfg_attr(target_os = "macos", allow(dead_code))]
pub fn gpu_specs(&self) -> GPUSpecs {
let info = self.gpu.device_information();
GPUSpecs {
is_software_emulated: info.is_software_emulated,
device_name: info.device_name.clone(),
driver_name: info.driver_name.clone(),
driver_info: info.driver_info.clone(),
}
}
#[cfg(target_os = "macos")]
pub fn layer(&self) -> metal::MetalLayer {
self.gpu.metal_layer().unwrap()

View File

@ -25,7 +25,7 @@ use crate::platform::linux::wayland::serial::SerialKind;
use crate::platform::{PlatformAtlas, PlatformInputHandler, PlatformWindow};
use crate::scene::Scene;
use crate::{
px, size, AnyWindowHandle, Bounds, Decorations, Globals, Modifiers, Output, Pixels,
px, size, AnyWindowHandle, Bounds, Decorations, GPUSpecs, Globals, Modifiers, Output, Pixels,
PlatformDisplay, PlatformInput, Point, PromptLevel, ResizeEdge, Size, Tiling,
WaylandClientStatePtr, WindowAppearance, WindowBackgroundAppearance, WindowBounds,
WindowControls, WindowDecorations, WindowParams,
@ -1007,6 +1007,10 @@ impl PlatformWindow for WaylandWindow {
update_window(state);
}
}
fn gpu_specs(&self) -> Option<GPUSpecs> {
self.borrow().renderer.gpu_specs().into()
}
}
fn update_window(mut state: RefMut<WaylandWindowState>) {

View File

@ -2,9 +2,9 @@ use anyhow::Context;
use crate::{
platform::blade::{BladeRenderer, BladeSurfaceConfig},
px, size, AnyWindowHandle, Bounds, Decorations, DevicePixels, ForegroundExecutor, Modifiers,
Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow,
Point, PromptLevel, ResizeEdge, Scene, Size, Tiling, WindowAppearance,
px, size, AnyWindowHandle, Bounds, Decorations, DevicePixels, ForegroundExecutor, GPUSpecs,
Modifiers, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler,
PlatformWindow, Point, PromptLevel, ResizeEdge, Scene, Size, Tiling, WindowAppearance,
WindowBackgroundAppearance, WindowBounds, WindowDecorations, WindowKind, WindowParams,
X11ClientStatePtr,
};
@ -1385,4 +1385,8 @@ impl PlatformWindow for X11Window {
appearance_changed();
}
}
fn gpu_specs(&self) -> Option<GPUSpecs> {
self.0.state.borrow().renderer.gpu_specs().into()
}
}

View File

@ -1096,6 +1096,10 @@ impl PlatformWindow for MacWindow {
fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
self.0.lock().renderer.sprite_atlas().clone()
}
fn gpu_specs(&self) -> Option<crate::GPUSpecs> {
None
}
}
impl rwh::HasWindowHandle for MacWindow {

View File

@ -1,7 +1,7 @@
use crate::{
AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, DispatchEventResult, Pixels,
PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point,
Size, TestPlatform, TileId, WindowAppearance, WindowBackgroundAppearance, WindowBounds,
AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, DispatchEventResult, GPUSpecs,
Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow,
Point, Size, TestPlatform, TileId, WindowAppearance, WindowBackgroundAppearance, WindowBounds,
WindowParams,
};
use collections::HashMap;
@ -273,6 +273,10 @@ impl PlatformWindow for TestWindow {
fn start_window_move(&self) {
unimplemented!()
}
fn gpu_specs(&self) -> Option<GPUSpecs> {
None
}
}
pub(crate) struct TestAtlasState {

View File

@ -654,6 +654,10 @@ impl PlatformWindow for WindowsWindow {
fn get_raw_handle(&self) -> HWND {
self.0.hwnd
}
fn gpu_specs(&self) -> Option<GPUSpecs> {
Some(self.0.state.borrow().renderer.gpu_specs())
}
}
#[implement(IDropTarget)]

View File

@ -3,7 +3,7 @@ use crate::{
AnyView, AppContext, Arena, Asset, AsyncWindowContext, AvailableSpace, Bounds, BoxShadow,
Context, Corners, CursorStyle, Decorations, DevicePixels, DispatchActionListener,
DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter,
FileDropEvent, Flatten, FontId, Global, GlobalElementId, GlyphId, Hsla, ImageData,
FileDropEvent, Flatten, FontId, GPUSpecs, Global, GlobalElementId, GlyphId, Hsla, ImageData,
InputHandler, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent, Keystroke,
KeystrokeEvent, LayoutId, LineLayoutIndex, Model, ModelContext, Modifiers,
ModifiersChangedEvent, MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent,
@ -3733,6 +3733,12 @@ impl<'a> WindowContext<'a> {
.dispatch_tree
.on_action(action_type, Rc::new(listener));
}
/// Read information about the GPU backing this window.
/// Currently returns None on Mac and Windows.
pub fn gpu_specs(&self) -> Option<GPUSpecs> {
self.window.platform_window.gpu_specs()
}
}
#[cfg(target_os = "windows")]

View File

@ -18,7 +18,7 @@ anyhow.workspace = true
[target.'cfg(target_os = "macos")'.dependencies]
core-foundation.workspace = true
foreign-types = "0.5"
metal = "0.25"
metal = "0.29"
objc = "0.2"
[build-dependencies]

View File

@ -139,6 +139,30 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
})
.detach();
if let Some(specs) = cx.gpu_specs() {
log::info!("Using GPU: {:?}", specs);
if specs.is_software_emulated && std::env::var("ZED_ALLOW_EMULATED_GPU").is_err() {
let message = format!(db::indoc!{r#"
Zed uses Vulkan for rendering and requires a compatible GPU.
Currently you are using a software emulated GPU ({}) which
will result in awful performance.
For troubleshooting see: https://zed.dev/docs/linux
"#}, specs.device_name);
let prompt = cx.prompt(PromptLevel::Critical, "Unsupported GPU", Some(&message),
&["Troubleshoot and Quit"]);
cx.spawn(|_, mut cx| async move {
if prompt.await == Ok(0) {
cx.update(|cx| {
cx.open_url("https://zed.dev/docs/linux#zed-fails-to-open-windows");
cx.quit();
}).ok();
}
}).detach()
}
}
let inline_completion_button = cx.new_view(|cx| {
inline_completion_button::InlineCompletionButton::new(app_state.fs.clone(), cx)
});

View File

@ -12,11 +12,14 @@ We also offer a preview build of Zed which receives updates about a week ahead o
curl -f https://zed.dev/install.sh | ZED_CHANNEL=preview sh
```
The install script does not work on systems that:
* have no system-wide glibc (for example on NixOS or Alpine)
The Zed installed by the script does not work on systems that:
* have no Vulkan compatible GPU available (for example Linux on an M-series macBook)
* have no system-wide glibc (for example on NixOS or Alpine by default)
* have a glibc older than version 2.29 (for example Amazon Linux 2 or Ubuntu 18 and earlier)
* use an architecture other than 64-bit Intel or 64-bit ARM (for example a 32-bit or RISC-V machine)
Both Nix and Alpine have third-party Zed packages available (though they are currently a few weeks out of date). If you'd like to use our builds they do work if you install a glibc compatibility layer. On NixOS you can try [nix-ld](https://github.com/Mic92/nix-ld), and on Alpine [gcompat](https://wiki.alpinelinux.org/wiki/Running_glibc_programs).
## Other ways to install Zed on Linux
Zed is open source, and [you can install from source](./development/linux.md).
@ -80,30 +83,31 @@ Linux works on a large variety of systems configured in many different ways. We
If you see an error like "/lib64/libc.so.6: version 'GLIBC_2.29' not found" it means that your distribution's version of glibc is too old. You can either upgrade your system, or [install Zed from source](./development/linux.md).
### Zed fails to open windows
### Zed is very slow
Zed requires a GPU to run effectively. Under the hood, we use [Vulkan](https://www.vulkan.org/) to communicate with your GPU. If you are seeing problems with performance, or Zed fails to load, it is possible that Vulkan is the culprit.
If you're using an AMD GPU, you might get a 'Broken Pipe' error. Try using the RADV or Mesa drivers. (See the following GitHub issue for more details: [#13880](https://github.com/zed-industries/zed/issues/13880)).
Otherwise, if you see error messages like: "Zed failed to open a window: NoSupportedDeviceFound" or "called `Result::unwrap()` on an `Err` value: ERROR_INITIALIZATION_FAILED", you can begin troubleshooting Vulkan, by installing the `vulkan-tools` package, and running:
If you see a notification saying `Zed failed to open a window: NoSupportedDeviceFound` this means that Vulkan cannot find a compatible GPU. You can begin troubleshooting Vulkan by installing the `vulkan-tools` package and running:
```sh
vkcube
```
This should output a line describing your current graphics setup. If it contains `llvmpipe` then Vulkan is not using a GPU, which will make Zed run very slowly.
This should output a line describing your current graphics setup and show a rotating cube. If this does not work, you should be able to fix it by installing Vulkan compatible GPU drivers, however in some cases (for example running Linux on an Arm-based MacBook) there is no Vulkan support yet.
In most cases this can be fixed by configuring Vulkan and installing compatible GPU drivers, however in some cases (for example running Linux on an Arm-based MacBook) there is no Vulkan support yet.
If you see errors like `ERROR_INITIALIZATION_FAILED` or `GPU Crashed` or `ERROR_SURFACE_LOST_KHR` then you may be able to work around this by installing different drivers for your GPU, or by selecting a different GPU to run on. (See the following GitHub issue for more details: [#14225](https://github.com/zed-industries/zed/issues/14225))
For more information, the [Arch guide to Vulkan](https://wiki.archlinux.org/title/Vulkan) has some good steps.
As of Zed v0.146.x we log the selected GPU driver and you should see `Using GPU: ...` in the Zed log (`~/.local/share/zed/logs/Zed.log`).
### Zed is very slow
If Zed is selecting your integrated GPU instead of your discrete GPU, you can fix this by exporting the environment variable `DRI_PRIME=1` before running Zed.
If you're on relatively modern hardware Zed should feel fast to use. That said, we do rely on the GPU to make rendering quick.
If you are using Mesa, and want more control over which GPU is selected you can run `MESA_VK_DEVICE_SELECT=list zed --foreground` to get a list of available GPUs and then export `MESA_VK_DEVICE_SELECT=xxxx:yyyy` to choose a specific device.
If you install the `vulkan-tools` package and run `vkcube` and you see `llvmpipe` in the output, you need to make sure your GPU is configured correctly.
If you are using `amdvlk` you may find that zed only opens when run with `sudo $(which zed)`. To fix this, remove the `amdvlk` and `lib32-amdvlk` packages and install mesa/vulkan instead. ([#14141](https://github.com/zed-industries/zed/issues/14141).
For more information, the [Arch guide to Vulkan](https://wiki.archlinux.org/title/Vulkan) has some good troubleshooting steps.
For more information, the [Arch guide to Vulkan](https://wiki.archlinux.org/title/Vulkan) has some good steps that translate well to most distributions.
If Vulkan is configured correctly, and Zed is still slow for you, please [file an issue](https://github.com/zed-industries/zed) with as much information as possible.