mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
Added clockspeed information and unpriveleged service execution
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
use daemon::daemon_connection::DaemonConnection;
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(StructOpt)]
|
||||
@@ -10,13 +11,17 @@ enum Opt {
|
||||
|
||||
fn main() {
|
||||
let opt = Opt::from_args();
|
||||
|
||||
let mut d = DaemonConnection::new().unwrap();
|
||||
|
||||
match opt {
|
||||
Opt::Stats => {
|
||||
let gpu_stats = daemon::get_gpu_stats();
|
||||
let gpu_stats = d.get_gpu_stats();
|
||||
println!("VRAM: {}/{}", gpu_stats.mem_used, gpu_stats.mem_total);
|
||||
println!("{:?}", gpu_stats);
|
||||
}
|
||||
Opt::Info => {
|
||||
let gpu_info = daemon::get_gpu_info().unwrap();
|
||||
let gpu_info = d.get_gpu_info();
|
||||
println!("GPU Vendor: {}", gpu_info.gpu_vendor);
|
||||
println!("GPU Model: {}", gpu_info.card_model);
|
||||
println!("Driver in use: {}", gpu_info.driver);
|
||||
|
||||
@@ -9,4 +9,5 @@ edition = "2018"
|
||||
[dependencies]
|
||||
bincode = "1.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
vulkano = "0.19"
|
||||
vulkano = "0.19"
|
||||
glob = "0.3"
|
||||
@@ -1,68 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::net::{UnixListener, UnixStream};
|
||||
use std::process::Command;
|
||||
use std::thread;
|
||||
|
||||
use crate::gpu_controller::GpuController;
|
||||
use crate::SOCK_PATH;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Daemon {
|
||||
gpu_controller: GpuController,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum Action {
|
||||
GetInfo,
|
||||
GetStats,
|
||||
}
|
||||
|
||||
impl Daemon {
|
||||
pub fn new(gpu_controller: GpuController) -> Daemon {
|
||||
Daemon { gpu_controller }
|
||||
}
|
||||
|
||||
pub fn run(self) {
|
||||
if fs::metadata(SOCK_PATH).is_ok() {
|
||||
fs::remove_file(SOCK_PATH).expect("Failed to take control over socket");
|
||||
}
|
||||
|
||||
let listener = UnixListener::bind(SOCK_PATH).unwrap();
|
||||
|
||||
Command::new("chmod")
|
||||
.arg("666")
|
||||
.arg(SOCK_PATH)
|
||||
.output()
|
||||
.expect("Failed to chmod");
|
||||
|
||||
for stream in listener.incoming() {
|
||||
let d = self.clone();
|
||||
match stream {
|
||||
Ok(stream) => {
|
||||
thread::spawn(move || d.handle_connection(stream));
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_connection(self, mut stream: UnixStream) {
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
stream.read_to_end(&mut buffer).unwrap();
|
||||
println!("finished reading, buffer size {}", buffer.len());
|
||||
let action: Action = bincode::deserialize(&buffer).unwrap();
|
||||
|
||||
let response: Vec<u8> = match action {
|
||||
Action::GetStats => bincode::serialize(&self.gpu_controller.get_stats()).unwrap(),
|
||||
Action::GetInfo => bincode::serialize(&self.gpu_controller.gpu_info).unwrap(),
|
||||
};
|
||||
stream
|
||||
.write_all(&response)
|
||||
.expect("Failed writing response");
|
||||
}
|
||||
}
|
||||
60
daemon/src/daemon_connection.rs
Normal file
60
daemon/src/daemon_connection.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
use crate::{Action, gpu_controller::GpuStats, SOCK_PATH, gpu_controller::GpuInfo};
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::net::UnixStream;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DaemonConnectionError {
|
||||
ConnectionFailed,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct DaemonConnection {
|
||||
}
|
||||
|
||||
impl DaemonConnection {
|
||||
pub fn new() -> Result<Self, DaemonConnectionError> {
|
||||
match UnixStream::connect(SOCK_PATH) {
|
||||
Ok(mut stream) => {
|
||||
stream.write(&bincode::serialize(&Action::CheckAlive).unwrap()).unwrap();
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
stream.read_to_end(&mut buffer).unwrap();
|
||||
|
||||
if buffer[0] == 1 {
|
||||
Ok(DaemonConnection { })
|
||||
}
|
||||
else {
|
||||
Err(DaemonConnectionError::ConnectionFailed)
|
||||
}
|
||||
}
|
||||
Err(_) => Err(DaemonConnectionError::ConnectionFailed),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gpu_stats(&self) -> GpuStats {
|
||||
let mut stream = UnixStream::connect(SOCK_PATH).expect("Failed to connect to daemon");
|
||||
stream
|
||||
.write(&bincode::serialize(&Action::GetStats).unwrap())
|
||||
.unwrap();
|
||||
/*stream
|
||||
.shutdown(std::net::Shutdown::Write)
|
||||
.expect("Could not shut down");*/
|
||||
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
stream.read_to_end(&mut buffer).unwrap();
|
||||
|
||||
bincode::deserialize(&buffer).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_gpu_info(&self) -> GpuInfo {
|
||||
let mut s = UnixStream::connect(SOCK_PATH).unwrap();
|
||||
s.write_all(&bincode::serialize(&Action::GetInfo).unwrap())
|
||||
.unwrap();
|
||||
/*s.shutdown(std::net::Shutdown::Write)
|
||||
.expect("Could not shut down");*/
|
||||
|
||||
let mut buffer = Vec::<u8>::new();
|
||||
s.read_to_end(&mut buffer).unwrap();
|
||||
|
||||
bincode::deserialize(&buffer).unwrap()
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct FanController {
|
||||
hwmon_path: String,
|
||||
}
|
||||
|
||||
impl FanController {
|
||||
pub fn new(hwmon_path: &str) -> FanController {
|
||||
FanController {
|
||||
hwmon_path: hwmon_path.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,21 @@
|
||||
use crate::fan_controller::FanController;
|
||||
use crate::hw_mon::HWMon;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice};
|
||||
use std::fs;
|
||||
use std::{collections::HashMap, fs};
|
||||
use std::path::PathBuf;
|
||||
use vulkano::instance::{Instance, InstanceExtensions, PhysicalDevice};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct GpuStats {
|
||||
pub mem_used: u64,
|
||||
pub mem_total: u64,
|
||||
pub mem_freq: i32,
|
||||
pub gpu_freq: i32,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct GpuController {
|
||||
pub struct GpuController {
|
||||
hw_path: PathBuf,
|
||||
fan_controller: FanController,
|
||||
hw_mon: HWMon,
|
||||
pub gpu_info: GpuInfo,
|
||||
}
|
||||
|
||||
@@ -41,10 +43,10 @@ pub struct GpuInfo {
|
||||
}
|
||||
|
||||
impl GpuController {
|
||||
pub fn new(hw_path: &str) -> Self {
|
||||
pub fn new(hw_path: PathBuf) -> Self {
|
||||
let mut controller = GpuController {
|
||||
hw_path: PathBuf::from(hw_path),
|
||||
fan_controller: FanController::new(hw_path),
|
||||
hw_path: hw_path.clone(),
|
||||
hw_mon: HWMon::new(&hw_path.join("hwmon/hwmon0")),
|
||||
gpu_info: Default::default(),
|
||||
};
|
||||
controller.gpu_info = controller.get_info();
|
||||
@@ -53,7 +55,8 @@ impl GpuController {
|
||||
}
|
||||
|
||||
fn get_info(&self) -> GpuInfo {
|
||||
let uevent = fs::read_to_string(self.hw_path.join("uevent")).expect("Failed to read uevent");
|
||||
let uevent =
|
||||
fs::read_to_string(self.hw_path.join("uevent")).expect("Failed to read uevent");
|
||||
|
||||
let mut driver = String::new();
|
||||
let mut vendor_id = String::new();
|
||||
@@ -128,7 +131,7 @@ impl GpuController {
|
||||
.expect("Failed to read link speed")
|
||||
.trim()
|
||||
.to_string();
|
||||
|
||||
|
||||
let link_width = fs::read_to_string(self.hw_path.join("current_link_width"))
|
||||
.expect("Failed to read link width")
|
||||
.trim()
|
||||
@@ -169,9 +172,14 @@ impl GpuController {
|
||||
/ 1024
|
||||
/ 1024;
|
||||
|
||||
let (mem_freq, gpu_freq) = (self.hw_mon.get_mem_freq(), self.hw_mon.get_gpu_freq());
|
||||
|
||||
|
||||
GpuStats {
|
||||
mem_total,
|
||||
mem_used,
|
||||
mem_freq,
|
||||
gpu_freq,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +192,7 @@ impl GpuController {
|
||||
let api_version = physical.api_version().to_string();
|
||||
let device_name = physical.name().to_string();
|
||||
let features = format!("{:?}", physical.supported_features());
|
||||
|
||||
|
||||
return VulkanInfo {
|
||||
device_name,
|
||||
api_version,
|
||||
@@ -193,7 +201,10 @@ impl GpuController {
|
||||
}
|
||||
}
|
||||
|
||||
VulkanInfo { device_name: "Not supported".to_string(), api_version: "".to_string(), features: "".to_string()}
|
||||
|
||||
VulkanInfo {
|
||||
device_name: "Not supported".to_string(),
|
||||
api_version: "".to_string(),
|
||||
features: "".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
52
daemon/src/hw_mon.rs
Normal file
52
daemon/src/hw_mon.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use glob::glob;
|
||||
use std::{collections::HashMap, fs, path::PathBuf};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
pub struct HWMon {
|
||||
hwmon_path: PathBuf,
|
||||
freqs: HashMap<String, u8>,
|
||||
}
|
||||
|
||||
impl HWMon {
|
||||
pub fn new(hwmon_path: &PathBuf) -> HWMon {
|
||||
let mut freqs: HashMap<String, u8> = HashMap::new();
|
||||
for entry in glob(&format!("{}/freq*_label", hwmon_path.to_str().unwrap())).expect("Couldnt read glob pattern")
|
||||
{
|
||||
let entry = entry.unwrap();
|
||||
let filename = entry.file_name().unwrap().to_str().unwrap();
|
||||
let index = filename.chars().nth(4).unwrap().to_digit(10).unwrap() as u8;
|
||||
let label = fs::read_to_string(hwmon_path.join(&format!("freq{}_label", index)))
|
||||
.unwrap()
|
||||
.trim()
|
||||
.to_string();
|
||||
freqs.insert(label, index);
|
||||
}
|
||||
println!("{:?}", freqs);
|
||||
|
||||
HWMon {
|
||||
hwmon_path: hwmon_path.clone(),
|
||||
freqs,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_fan_speed(&self) -> i32 {
|
||||
fs::read_to_string(self.hwmon_path.join("fan1_input"))
|
||||
.expect("Couldn't read fan speed")
|
||||
.parse::<i32>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn get_mem_freq(&self) -> i32 {
|
||||
let filename = self.hwmon_path.join(format!("freq{}_input", self.freqs.get("mclk").unwrap()));
|
||||
|
||||
fs::read_to_string(filename).unwrap().trim().parse::<i32>().unwrap() / 1000 / 1000
|
||||
}
|
||||
|
||||
pub fn get_gpu_freq(&self) -> i32 {
|
||||
let filename = self.hwmon_path.join(format!("freq{}_input", self.freqs.get("sclk").unwrap()));
|
||||
|
||||
fs::read_to_string(filename).unwrap().trim().parse::<i32>().unwrap() / 1000 / 1000
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,89 @@
|
||||
use std::io::{Read, Write};
|
||||
use std::os::unix::net::UnixStream;
|
||||
|
||||
use gpu_controller::{GpuInfo, GpuStats};
|
||||
|
||||
pub mod daemon;
|
||||
pub mod fan_controller;
|
||||
pub mod gpu_controller;
|
||||
pub mod hw_mon;
|
||||
pub mod daemon_connection;
|
||||
|
||||
use std::{path::PathBuf, io::{Read, Write}};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fs;
|
||||
use std::os::unix::net::{UnixListener, UnixStream};
|
||||
use std::process::Command;
|
||||
use std::thread;
|
||||
|
||||
use crate::gpu_controller::GpuController;
|
||||
|
||||
pub const SOCK_PATH: &str = "/tmp/amdgpu-configurator.sock";
|
||||
|
||||
pub struct Daemon {
|
||||
gpu_controller: GpuController,
|
||||
listener: UnixListener,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum Action {
|
||||
CheckAlive,
|
||||
GetInfo,
|
||||
GetStats,
|
||||
}
|
||||
|
||||
impl Daemon {
|
||||
pub fn new() -> Daemon {
|
||||
if fs::metadata(SOCK_PATH).is_ok() {
|
||||
fs::remove_file(SOCK_PATH).expect("Failed to take control over socket");
|
||||
}
|
||||
|
||||
let listener = UnixListener::bind(SOCK_PATH).unwrap();
|
||||
|
||||
Command::new("chmod")
|
||||
.arg("666")
|
||||
.arg(SOCK_PATH)
|
||||
.output()
|
||||
.expect("Failed to chmod");
|
||||
|
||||
Daemon { listener, gpu_controller: GpuController::new(PathBuf::from("/sys/class/drm/card0/device"))}
|
||||
}
|
||||
|
||||
pub fn listen(self) {
|
||||
for stream in self.listener.incoming() {
|
||||
match stream {
|
||||
Ok(stream) => {
|
||||
let controller = self.gpu_controller.clone();
|
||||
thread::spawn(move || Daemon::handle_connection(controller, stream));
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {}", err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_connection(gpu_controller: GpuController, mut stream: UnixStream) {
|
||||
let mut buffer: [u8; 4] = [0; 4];
|
||||
stream.read(&mut buffer).unwrap();
|
||||
println!("finished reading, buffer size {}", buffer.len());
|
||||
let action: Action = bincode::deserialize(&buffer).expect("Failed to deserialize buffer");
|
||||
|
||||
let response: Vec<u8> = match action {
|
||||
Action::GetStats => bincode::serialize(&gpu_controller.get_stats()).unwrap(),
|
||||
Action::GetInfo => bincode::serialize(&gpu_controller.gpu_info).unwrap(),
|
||||
Action::CheckAlive => vec![1],
|
||||
};
|
||||
println!("responding with {:?}", response);
|
||||
|
||||
stream
|
||||
.write_all(&response)
|
||||
.expect("Failed writing response");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DaemonError {
|
||||
ConnectionFailed,
|
||||
}
|
||||
|
||||
pub fn get_gpu_stats() -> GpuStats {
|
||||
/*pub fn get_gpu_stats() -> GpuStats {
|
||||
let mut stream = UnixStream::connect(SOCK_PATH).expect("Failed to connect to daemon");
|
||||
stream
|
||||
.write_all(&bincode::serialize(&daemon::Action::GetStats).unwrap())
|
||||
@@ -44,6 +113,4 @@ pub fn get_gpu_info() -> Result<GpuInfo, DaemonError> {
|
||||
}
|
||||
Err(_) => Err(DaemonError::ConnectionFailed),
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}*/
|
||||
@@ -1,8 +1,6 @@
|
||||
use daemon::daemon::Daemon;
|
||||
use daemon::gpu_controller::GpuController;
|
||||
use daemon::Daemon;
|
||||
|
||||
fn main() {
|
||||
let gpu_controller = GpuController::new("/sys/class/drm/card0/device");
|
||||
let d = Daemon::new(gpu_controller);
|
||||
d.run();
|
||||
let d = Daemon::new();
|
||||
d.listen();
|
||||
}
|
||||
|
||||
@@ -2,16 +2,18 @@ extern crate gdk;
|
||||
extern crate gio;
|
||||
extern crate gtk;
|
||||
|
||||
use daemon::{Daemon, daemon_connection::DaemonConnection};
|
||||
use gio::prelude::*;
|
||||
use gtk::{prelude::*, ButtonsType, DialogFlags, MessageType};
|
||||
use gtk::{ButtonsType, DialogFlags, Label, LevelBar, MessageType, prelude::*};
|
||||
|
||||
use gtk::{Builder, MessageDialog, TextBuffer, Window};
|
||||
|
||||
use std::env::args;
|
||||
use std::{process::Command, env::args, thread, time::Duration};
|
||||
|
||||
fn build_ui(application: >k::Application) {
|
||||
let glade_src = include_str!("main_window.glade");
|
||||
let builder = Builder::from_string(glade_src);
|
||||
println!("Getting elements");
|
||||
|
||||
let main_window: Window = builder
|
||||
.get_object("main_window")
|
||||
@@ -41,7 +43,7 @@ fn build_ui(application: >k::Application) {
|
||||
.get_object("link_speed_text_buffer")
|
||||
.expect("Couldn't get textbuffer");
|
||||
|
||||
let vulkan_device_name_text_buffer: TextBuffer = builder
|
||||
let vulkan_device_name_text_buffer: TextBuffer = builder
|
||||
.get_object("vulkan_device_name_text_buffer")
|
||||
.expect("Couldn't get textbuffer");
|
||||
|
||||
@@ -53,32 +55,82 @@ fn build_ui(application: >k::Application) {
|
||||
.get_object("vulkan_features_text_buffer")
|
||||
.expect("Couldn't get textbuffer");
|
||||
|
||||
let vram_usage_level_bar: LevelBar = builder
|
||||
.get_object("vram_usage_level_bar")
|
||||
.expect("Couldnt get levelbar");
|
||||
|
||||
match daemon::get_gpu_info() {
|
||||
Ok(gpu_info) => {
|
||||
gpu_model_text_buffer.set_text(&gpu_info.card_model);
|
||||
manufacturer_text_buffer.set_text(&gpu_info.card_vendor);
|
||||
vbios_version_text_buffer.set_text(&gpu_info.vbios_version);
|
||||
driver_text_buffer.set_text(&gpu_info.driver);
|
||||
vram_size_text_buffer.set_text(&format!("{} MiB", &gpu_info.vram_size));
|
||||
link_speed_text_buffer.set_text(&format!("{} x{}", &gpu_info.link_speed, &gpu_info.link_width));
|
||||
let vram_usage_label: Label = builder
|
||||
.get_object("vram_usage_label")
|
||||
.expect("Couldn't get label");
|
||||
|
||||
let gpu_clock_text_buffer: TextBuffer = builder
|
||||
.get_object("gpu_clock_text_buffer").unwrap();
|
||||
|
||||
vulkan_device_name_text_buffer.set_text(&gpu_info.vulkan_info.device_name);
|
||||
vulkan_version_text_buffer.set_text(&gpu_info.vulkan_info.api_version);
|
||||
vulkan_features_text_buffer.set_text(&gpu_info.vulkan_info.features);
|
||||
}
|
||||
let vram_clock_text_buffer: TextBuffer = builder
|
||||
.get_object("vram_clock_text_buffer").unwrap();
|
||||
|
||||
let d = match DaemonConnection::new() {
|
||||
Ok(a) => a,
|
||||
Err(_) => {
|
||||
MessageDialog::new(
|
||||
let daemon = Daemon::new();
|
||||
thread::spawn(move || {
|
||||
daemon.listen();
|
||||
});
|
||||
|
||||
let diag = MessageDialog::new(
|
||||
None::<&Window>,
|
||||
DialogFlags::empty(),
|
||||
MessageType::Error,
|
||||
ButtonsType::Ok,
|
||||
"Unable to connect to service",
|
||||
)
|
||||
.run();
|
||||
application.quit();
|
||||
"Running in unpriveleged mode",
|
||||
);
|
||||
diag.run();
|
||||
diag.hide();
|
||||
|
||||
DaemonConnection::new().unwrap()
|
||||
}
|
||||
}
|
||||
};
|
||||
println!("Connected");
|
||||
|
||||
let gpu_info = d.get_gpu_info();
|
||||
|
||||
gpu_model_text_buffer.set_text(&gpu_info.card_model);
|
||||
manufacturer_text_buffer.set_text(&gpu_info.card_vendor);
|
||||
vbios_version_text_buffer.set_text(&gpu_info.vbios_version);
|
||||
driver_text_buffer.set_text(&gpu_info.driver);
|
||||
vram_size_text_buffer.set_text(&format!("{} MiB", &gpu_info.vram_size));
|
||||
link_speed_text_buffer.set_text(&format!(
|
||||
"{} x{}",
|
||||
&gpu_info.link_speed, &gpu_info.link_width
|
||||
));
|
||||
|
||||
vulkan_device_name_text_buffer.set_text(&gpu_info.vulkan_info.device_name);
|
||||
vulkan_version_text_buffer.set_text(&gpu_info.vulkan_info.api_version);
|
||||
vulkan_features_text_buffer.set_text(&gpu_info.vulkan_info.features);
|
||||
|
||||
let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
||||
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
let gpu_stats = d.get_gpu_stats();
|
||||
|
||||
tx.send(gpu_stats).expect("Couldn't send text");
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
}
|
||||
});
|
||||
|
||||
rx.attach(None, move |gpu_stats| {
|
||||
vram_usage_level_bar.set_max_value(gpu_stats.mem_total as f64);
|
||||
vram_usage_level_bar.set_value(gpu_stats.mem_used as f64);
|
||||
|
||||
let text = format!("{}/{} MiB", gpu_stats.mem_used, gpu_stats.mem_total);
|
||||
vram_usage_label.set_text(&text);
|
||||
gpu_clock_text_buffer.set_text(&format!("{}MHz", gpu_stats.gpu_freq));
|
||||
vram_clock_text_buffer.set_text(&format!("{}MHz", gpu_stats.mem_freq));
|
||||
|
||||
glib::Continue(true)
|
||||
});
|
||||
|
||||
|
||||
main_window.set_application(Some(application));
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
<object class="GtkTextBuffer" id="driver_text_buffer">
|
||||
<property name="text" translatable="yes">driver</property>
|
||||
</object>
|
||||
<object class="GtkTextBuffer" id="gpu_clock_text_buffer">
|
||||
<property name="text" translatable="yes">1000MHz</property>
|
||||
</object>
|
||||
<object class="GtkTextBuffer" id="gpu_model_text_buffer">
|
||||
<property name="text">gpu_model</property>
|
||||
</object>
|
||||
@@ -17,6 +20,9 @@
|
||||
<object class="GtkTextBuffer" id="vbios_version_text_buffer">
|
||||
<property name="text" translatable="yes">vbios_version</property>
|
||||
</object>
|
||||
<object class="GtkTextBuffer" id="vram_clock_text_buffer">
|
||||
<property name="text" translatable="yes">1500MHz</property>
|
||||
</object>
|
||||
<object class="GtkTextBuffer" id="vram_size_text_buffer">
|
||||
<property name="text" translatable="yes">1024 MiB</property>
|
||||
</object>
|
||||
@@ -401,30 +407,160 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<!-- n-columns=3 n-rows=3 -->
|
||||
<!-- n-columns=2 n-rows=3 -->
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label" translatable="yes">VRAM Usage</property>
|
||||
<property name="justify">center</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
<object class="GtkOverlay">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<child>
|
||||
<object class="GtkLevelBar" id="vram_usage_level_bar">
|
||||
<property name="height-request">30</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="value">0.5</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="index">-1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="overlay">
|
||||
<object class="GtkLabel" id="vram_usage_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes">512/1024 MiB</property>
|
||||
<attributes>
|
||||
<attribute name="style" value="normal"/>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label" translatable="yes">GPU Clock</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTextView">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="cursor-visible">False</property>
|
||||
<property name="buffer">gpu_clock_text_buffer</property>
|
||||
<property name="accepts-tab">False</property>
|
||||
<property name="monospace">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">0</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label" translatable="yes">VRAM Clock</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTextView">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="cursor-visible">False</property>
|
||||
<property name="buffer">vram_clock_text_buffer</property>
|
||||
<property name="accepts-tab">False</property>
|
||||
<property name="monospace">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">1</property>
|
||||
<property name="top-attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
@@ -441,7 +577,7 @@
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">page 2</property>
|
||||
<property name="label" translatable="yes">OC</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
|
||||
Reference in New Issue
Block a user