Skip to repository content299 lines · 9.5 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T03:36:59.285Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
system_specs.rs
1pub use gpui::GpuSpecs;
2use gpui::{App, AppContext as _, Task, Window, actions};
3use human_bytes::human_bytes;
4use release_channel::{AppCommitSha, AppVersion, ReleaseChannel};
5use semver::Version;
6use serde::Serialize;
7use std::{env, fmt::Display};
8use sysinfo::{MemoryRefreshKind, RefreshKind, System};
9
10actions!(
11 omega,
12 [
13 /// Copies system specifications to the clipboard for bug reports.
14 #[action(deprecated_aliases = ["zed::CopySystemSpecsIntoClipboard"])]
15 CopySystemSpecsIntoClipboard,
16 ]
17);
18
19#[derive(Clone, Debug, Serialize)]
20pub struct SystemSpecs {
21 app_version: String,
22 release_channel: &'static str,
23 os_name: String,
24 os_version: String,
25 memory: u64,
26 architecture: &'static str,
27 commit_sha: Option<String>,
28 bundle_type: Option<String>,
29 gpu_specs: Option<String>,
30}
31
32impl SystemSpecs {
33 pub fn new(
34 window: &mut Window,
35 cx: &mut App,
36 os_name: String,
37 os_version: String,
38 ) -> Task<Self> {
39 let app_version = AppVersion::global(cx).to_string();
40 let release_channel = ReleaseChannel::global(cx);
41 let system = System::new_with_specifics(
42 RefreshKind::nothing().with_memory(MemoryRefreshKind::everything()),
43 );
44 let memory = system.total_memory();
45 let architecture = env::consts::ARCH;
46 let commit_sha = match release_channel {
47 ReleaseChannel::Dev | ReleaseChannel::Nightly => {
48 AppCommitSha::try_global(cx).map(|sha| sha.full())
49 }
50 _ => None,
51 };
52 let bundle_type = bundle_type();
53
54 let gpu_specs = window.gpu_specs().map(|specs| {
55 format!(
56 "{} || {} || {}",
57 specs.device_name, specs.driver_name, specs.driver_info
58 )
59 });
60
61 cx.background_spawn(async move {
62 SystemSpecs {
63 app_version,
64 release_channel: release_channel.display_name(),
65 bundle_type,
66 os_name,
67 os_version,
68 memory,
69 architecture,
70 commit_sha,
71 gpu_specs,
72 }
73 })
74 }
75
76 pub fn new_stateless(
77 app_version: Version,
78 app_commit_sha: Option<AppCommitSha>,
79 release_channel: ReleaseChannel,
80 os_name: String,
81 os_version: String,
82 ) -> Self {
83 let system = System::new_with_specifics(
84 RefreshKind::nothing().with_memory(MemoryRefreshKind::everything()),
85 );
86 let memory = system.total_memory();
87 let architecture = env::consts::ARCH;
88 let commit_sha = match release_channel {
89 ReleaseChannel::Dev | ReleaseChannel::Nightly => app_commit_sha.map(|sha| sha.full()),
90 _ => None,
91 };
92 let bundle_type = bundle_type();
93
94 Self {
95 app_version: app_version.to_string(),
96 release_channel: release_channel.display_name(),
97 os_name,
98 os_version,
99 memory,
100 architecture,
101 commit_sha,
102 bundle_type,
103 gpu_specs: try_determine_available_gpus(),
104 }
105 }
106}
107
108impl Display for SystemSpecs {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 let os_information = format!("OS: {} {}", self.os_name, self.os_version);
111 let app_version_information = format!(
112 "Omega: v{} ({}) {}{}",
113 self.app_version,
114 match &self.commit_sha {
115 Some(commit_sha) => format!("{} {}", self.release_channel, commit_sha),
116 None => self.release_channel.to_string(),
117 },
118 if let Some(bundle_type) = &self.bundle_type {
119 format!("({bundle_type})")
120 } else {
121 "".to_string()
122 },
123 if cfg!(debug_assertions) {
124 "(Taylor's Version)"
125 } else {
126 ""
127 },
128 );
129 let system_specs = [
130 app_version_information,
131 os_information,
132 format!("Memory: {}", human_bytes(self.memory as f64)),
133 format!("Architecture: {}", self.architecture),
134 ]
135 .into_iter()
136 .chain(
137 self.gpu_specs
138 .as_ref()
139 .map(|specs| format!("GPU: {}", specs)),
140 )
141 .collect::<Vec<String>>()
142 .join("\n");
143
144 write!(f, "{system_specs}")
145 }
146}
147
148fn try_determine_available_gpus() -> Option<String> {
149 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
150 {
151 #[allow(
152 clippy::disallowed_methods,
153 reason = "we are not running in an executor"
154 )]
155 std::process::Command::new("vulkaninfo")
156 .args(&["--summary"])
157 .output()
158 .ok()
159 .map(|output| {
160 [
161 "<details><summary>`vulkaninfo --summary` output</summary>",
162 "",
163 "```",
164 String::from_utf8_lossy(&output.stdout).as_ref(),
165 "```",
166 "</details>",
167 ]
168 .join("\n")
169 })
170 .or(Some("Failed to run `vulkaninfo --summary`".to_string()))
171 }
172 #[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
173 {
174 None
175 }
176}
177
178#[derive(Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize, Clone)]
179pub struct GpuInfo {
180 pub device_name: Option<String>,
181 pub device_pci_id: u16,
182 pub vendor_name: Option<String>,
183 pub vendor_pci_id: u16,
184 pub driver_version: Option<String>,
185 pub driver_name: Option<String>,
186}
187
188#[cfg(any(target_os = "linux", target_os = "freebsd"))]
189pub fn read_gpu_info_from_sys_class_drm() -> anyhow::Result<Vec<GpuInfo>> {
190 use anyhow::Context as _;
191 use pciid_parser;
192 let dir_iter = std::fs::read_dir("/sys/class/drm").context("Failed to read /sys/class/drm")?;
193 let mut pci_addresses = vec![];
194 let mut gpus = Vec::<GpuInfo>::new();
195 let pci_db = pciid_parser::Database::read().ok();
196 for entry in dir_iter {
197 let Ok(entry) = entry else {
198 continue;
199 };
200
201 let device_path = entry.path().join("device");
202 let Some(pci_address) = device_path.read_link().ok().and_then(|pci_address| {
203 pci_address
204 .file_name()
205 .and_then(std::ffi::OsStr::to_str)
206 .map(str::trim)
207 .map(str::to_string)
208 }) else {
209 continue;
210 };
211 let Ok(device_pci_id) = read_pci_id_from_path(device_path.join("device")) else {
212 continue;
213 };
214 let Ok(vendor_pci_id) = read_pci_id_from_path(device_path.join("vendor")) else {
215 continue;
216 };
217 let driver_name = std::fs::read_link(device_path.join("driver"))
218 .ok()
219 .and_then(|driver_link| {
220 driver_link
221 .file_name()
222 .and_then(std::ffi::OsStr::to_str)
223 .map(str::trim)
224 .map(str::to_string)
225 });
226 let driver_version = driver_name
227 .as_ref()
228 .and_then(|driver_name| {
229 std::fs::read_to_string(format!("/sys/module/{driver_name}/version")).ok()
230 })
231 .as_deref()
232 .map(str::trim)
233 .map(str::to_string);
234
235 let already_found = gpus
236 .iter()
237 .zip(&pci_addresses)
238 .any(|(gpu, gpu_pci_address)| {
239 gpu_pci_address == &pci_address
240 && gpu.driver_version == driver_version
241 && gpu.driver_name == driver_name
242 });
243
244 if already_found {
245 continue;
246 }
247
248 let vendor = pci_db
249 .as_ref()
250 .and_then(|db| db.vendors.get(&vendor_pci_id));
251 let vendor_name = vendor.map(|vendor| vendor.name.clone());
252 let device_name = vendor
253 .and_then(|vendor| vendor.devices.get(&device_pci_id))
254 .map(|device| device.name.clone());
255
256 gpus.push(GpuInfo {
257 device_name,
258 device_pci_id,
259 vendor_name,
260 vendor_pci_id,
261 driver_version,
262 driver_name,
263 });
264 pci_addresses.push(pci_address);
265 }
266
267 Ok(gpus)
268}
269
270#[cfg(any(target_os = "linux", target_os = "freebsd"))]
271fn read_pci_id_from_path(path: impl AsRef<std::path::Path>) -> anyhow::Result<u16> {
272 use anyhow::Context as _;
273 let id = std::fs::read_to_string(path)?;
274 let id = id
275 .trim()
276 .strip_prefix("0x")
277 .context("Not a device ID")
278 .context(id.clone())?;
279 anyhow::ensure!(
280 id.len() == 4,
281 "Not a device id, expected 4 digits, found {}",
282 id.len()
283 );
284 u16::from_str_radix(id, 16).context("Failed to parse device ID")
285}
286
287/// Returns value of `ZED_BUNDLE_TYPE` set at compiletime or else at runtime.
288///
289/// The compiletime value is used by flatpak since it doesn't seem to have a way to provide a
290/// runtime environment variable.
291///
292/// The runtime value is used by snap since the Zed snaps use release binaries directly, and so
293/// cannot have this baked in.
294fn bundle_type() -> Option<String> {
295 option_env!("ZED_BUNDLE_TYPE")
296 .map(|bundle_type| bundle_type.to_string())
297 .or_else(|| env::var("ZED_BUNDLE_TYPE").ok())
298}
299