mirror of
https://github.com/GpuZelenograd/memtest_vulkan
synced 2025-02-24 18:35:23 +01:00
conciser output by default
This commit is contained in:
parent
ea086da818
commit
2880062484
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -211,7 +211,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memtest_vulkan"
|
||||
version = "0.0.1"
|
||||
version = "0.0.3"
|
||||
dependencies = [
|
||||
"byte-strings",
|
||||
"ctrlc",
|
||||
|
@ -1,8 +1,10 @@
|
||||
#!/usr/bin/env -Scargo run --release --manifest-path
|
||||
#cargo fmt
|
||||
#cargo build --release --target x86_64-pc-windows-gnu
|
||||
[package]
|
||||
edition = '2021'
|
||||
name = 'memtest_vulkan'
|
||||
version = '0.0.1'
|
||||
version = '0.0.3'
|
||||
|
||||
[dependencies]
|
||||
byte-strings = '0.2.2'
|
||||
|
1
memtest_vulkan_debug
Symbolic link
1
memtest_vulkan_debug
Symbolic link
@ -0,0 +1 @@
|
||||
./target/release/memtest_vulkan
|
82
src/input.rs
82
src/input.rs
@ -21,28 +21,11 @@ impl Reader {
|
||||
prompt: &str,
|
||||
timeout: &std::time::Duration,
|
||||
) -> Result<ReaderEvent, Box<dyn std::error::Error>> {
|
||||
let terminal;
|
||||
if self.prepare_state.is_none() {
|
||||
self.terminal = Some(mortal::Terminal::new()?);
|
||||
terminal = self.terminal.as_ref().unwrap();
|
||||
let mut signals = mortal::signal::SignalSet::new();
|
||||
signals.insert(mortal::signal::Signal::Break);
|
||||
signals.insert(mortal::signal::Signal::Interrupt);
|
||||
signals.insert(mortal::signal::Signal::Quit);
|
||||
let tried_prepare = terminal.prepare(mortal::terminal::PrepareConfig {
|
||||
block_signals: false,
|
||||
enable_keypad: false,
|
||||
report_signals: signals,
|
||||
..mortal::terminal::PrepareConfig::default()
|
||||
});
|
||||
match tried_prepare {
|
||||
//terminal input not available, treate it as empty input
|
||||
Err(_) => return Ok(ReaderEvent::Completed),
|
||||
Ok(state) => self.prepare_state = Some(state),
|
||||
}
|
||||
} else {
|
||||
terminal = self.terminal.as_ref().unwrap();
|
||||
if !self.try_prepare_terminal() {
|
||||
//terminal input not available, treate it as empty input
|
||||
return Ok(ReaderEvent::Completed);
|
||||
}
|
||||
let terminal = self.terminal.as_ref().unwrap();
|
||||
terminal.move_to_first_column()?;
|
||||
terminal.clear_to_line_end()?;
|
||||
terminal.write_str(prompt)?;
|
||||
@ -80,6 +63,60 @@ impl Reader {
|
||||
_ => Ok(ReaderEvent::Timeout),
|
||||
}
|
||||
}
|
||||
pub fn set_pass_fail_accent_color(&mut self, passed: bool) {
|
||||
use mortal::terminal::Color;
|
||||
if !self.try_prepare_terminal() {
|
||||
//terminal input not available, don't perform wait.
|
||||
return;
|
||||
}
|
||||
let terminal = self.terminal.as_ref().unwrap();
|
||||
let _ = terminal.set_fg(Some(match passed {
|
||||
true => Color::Green,
|
||||
false => Color::Red,
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn wait_any_key(&mut self)
|
||||
{
|
||||
if !self.try_prepare_terminal() {
|
||||
//terminal input not available, don't perform wait.
|
||||
return;
|
||||
}
|
||||
let terminal = self.terminal.as_ref().unwrap();
|
||||
if terminal.write_str(" press any key to continue...\n").is_err()
|
||||
{
|
||||
return;
|
||||
}
|
||||
let _ignored = terminal.read_event(None);
|
||||
}
|
||||
fn try_prepare_terminal(&mut self) -> bool {
|
||||
if self.prepare_state.is_some() {
|
||||
return true;
|
||||
}
|
||||
let tried_terminal = mortal::Terminal::new();
|
||||
self.terminal = match tried_terminal
|
||||
{
|
||||
Ok(terminal) => Some(terminal),
|
||||
_ => return false
|
||||
};
|
||||
let terminal = self.terminal.as_ref().unwrap();
|
||||
let mut signals = mortal::signal::SignalSet::new();
|
||||
signals.insert(mortal::signal::Signal::Break);
|
||||
signals.insert(mortal::signal::Signal::Interrupt);
|
||||
signals.insert(mortal::signal::Signal::Quit);
|
||||
let tried_prepare = terminal.prepare(mortal::terminal::PrepareConfig {
|
||||
block_signals: false,
|
||||
enable_keypad: false,
|
||||
report_signals: signals,
|
||||
..mortal::terminal::PrepareConfig::default()
|
||||
});
|
||||
match tried_prepare {
|
||||
//terminal input not available, treate it as empty input
|
||||
Err(_) => return false,
|
||||
Ok(state) => self.prepare_state = Some(state),
|
||||
}
|
||||
true
|
||||
}
|
||||
fn handle_backspace(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if !self.current_input.is_empty() {
|
||||
if let Some(terminal) = &mut self.terminal {
|
||||
@ -96,7 +133,8 @@ impl Drop for Reader {
|
||||
fn drop(&mut self) {
|
||||
if let Some(terminal) = &mut self.terminal {
|
||||
if let Some(state) = self.prepare_state.take() {
|
||||
terminal.restore(state).unwrap();
|
||||
let _ = terminal.set_fg(None);
|
||||
let _ = terminal.restore(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
144
src/main.rs
144
src/main.rs
@ -13,6 +13,7 @@ use std::{
|
||||
atomic::{AtomicBool, Ordering::SeqCst},
|
||||
Arc,
|
||||
},
|
||||
io::Write,
|
||||
time,
|
||||
};
|
||||
|
||||
@ -206,7 +207,8 @@ fn test_device(
|
||||
physical_device: vk::PhysicalDevice,
|
||||
queue_family_index: u32,
|
||||
device_create_info: vk::DeviceCreateInfo,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
debug_mode: bool,
|
||||
) -> Result<bool, Box<dyn std::error::Error>> {
|
||||
let device = unsafe { DeviceLoader::new(&instance, physical_device, &device_create_info) }?;
|
||||
let queue = unsafe { device.get_device_queue(queue_family_index, 0) };
|
||||
|
||||
@ -262,13 +264,15 @@ fn test_device(
|
||||
)
|
||||
})
|
||||
.ok_or("DEVICE_LOCAL | HOST_COHERENT memory type not available")?;
|
||||
println!(
|
||||
"IO memory type {}: {:?} heap {:?}",
|
||||
io_mem_index,
|
||||
memory_props.memory_types[io_mem_index as usize],
|
||||
memory_props.memory_heaps
|
||||
[memory_props.memory_types[io_mem_index as usize].heap_index as usize]
|
||||
);
|
||||
if debug_mode {
|
||||
println!(
|
||||
"IO memory type {}: {:?} heap {:?}",
|
||||
io_mem_index,
|
||||
memory_props.memory_types[io_mem_index as usize],
|
||||
memory_props.memory_heaps
|
||||
[memory_props.memory_types[io_mem_index as usize].heap_index as usize]
|
||||
);
|
||||
}
|
||||
|
||||
let io_memory_allocate_info = vk::MemoryAllocateInfoBuilder::new()
|
||||
.allocation_size(io_mem_reqs.size)
|
||||
@ -323,14 +327,16 @@ fn test_device(
|
||||
allocation_size -= min_wanted_allocation;
|
||||
}
|
||||
|
||||
println!(
|
||||
"Test memory size {:5.1}GB type {:2}: {:?} {:?}",
|
||||
allocation_size as f32 / GB,
|
||||
test_mem_index,
|
||||
memory_props.memory_types[test_mem_index as usize],
|
||||
memory_props.memory_heaps
|
||||
[memory_props.memory_types[test_mem_index as usize].heap_index as usize]
|
||||
);
|
||||
if debug_mode {
|
||||
println!(
|
||||
"Test memory size {:5.1}GB type {:2}: {:?} {:?}",
|
||||
allocation_size as f32 / GB,
|
||||
test_mem_index,
|
||||
memory_props.memory_types[test_mem_index as usize],
|
||||
memory_props.memory_heaps
|
||||
[memory_props.memory_types[test_mem_index as usize].heap_index as usize]
|
||||
);
|
||||
}
|
||||
|
||||
let test_window_count = allocation_size / TEST_WINDOW_MAX_SIZE
|
||||
+ i64::from(allocation_size % TEST_WINDOW_MAX_SIZE != 0);
|
||||
@ -480,6 +486,7 @@ fn test_device(
|
||||
let mut start = time::Instant::now();
|
||||
let stop_requested = Arc::new(AtomicBool::new(false));
|
||||
let mut buffer_in = IOBuf::default();
|
||||
let mut no_errors = true;
|
||||
for iteration in 1..=iter_count {
|
||||
buffer_in.prepare_next_iter_write();
|
||||
unsafe { std::ptr::write(mapped, buffer_in) }
|
||||
@ -517,6 +524,7 @@ fn test_device(
|
||||
buffer_out = std::ptr::read(mapped);
|
||||
}
|
||||
if let Some(error) = buffer_out.get_error_addresses(test_offset) {
|
||||
no_errors = false;
|
||||
println!("{:?}", buffer_out);
|
||||
println!(
|
||||
"Error found. Mode {}, addresses: {:?}",
|
||||
@ -585,18 +593,19 @@ fn test_device(
|
||||
device.destroy_device(None);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(no_errors)
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
fn init_vk_and_check_no_errors(debug_mode: bool) -> Result<bool, Box<dyn std::error::Error>> {
|
||||
let entry = EntryLoader::new()?;
|
||||
println!("https://github.com/galkinvv/memtest_vulkan by GpuZelenograd");
|
||||
println!(
|
||||
"Runing on Vulkan {}.{}.{} Press Ctrl+C to stop",
|
||||
vk::api_version_major(entry.instance_version()),
|
||||
vk::api_version_minor(entry.instance_version()),
|
||||
vk::api_version_patch(entry.instance_version())
|
||||
);
|
||||
if debug_mode {
|
||||
println!("Debug mode enabled ('debug' found in executable), running on Vulkan {}.{}.{}",
|
||||
vk::api_version_major(entry.instance_version()),
|
||||
vk::api_version_minor(entry.instance_version()),
|
||||
vk::api_version_patch(entry.instance_version())
|
||||
);
|
||||
}
|
||||
println!("To finish testing use Ctrl+C");
|
||||
println!();
|
||||
|
||||
let mut instance_extensions = Vec::new();
|
||||
@ -697,21 +706,29 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
_ => (2, negative_bus_for_reverse_ordering),
|
||||
}
|
||||
});
|
||||
let mut numbered_devices = Vec::new();
|
||||
for (i, d) in compute_capable_devices.iter().enumerate() {
|
||||
let props = d.2;
|
||||
let pci_props = d.4;
|
||||
println!(
|
||||
"{}: Bus=0x{:02X}:{:02X} DevId=0x{:04X} API v.{}.{}.{} {}GB {}",
|
||||
let api_info = if debug_mode {
|
||||
std::format!("API v.{}.{}.{}",
|
||||
vk::api_version_major(props.api_version),
|
||||
vk::api_version_minor(props.api_version),
|
||||
vk::api_version_patch(props.api_version),
|
||||
)
|
||||
} else { String::new() };
|
||||
numbered_devices.push(std::format!(
|
||||
"{}: Bus=0x{:02X}:{:02X} DevId=0x{:04X} {api_info} {}GB {}",
|
||||
i + 1,
|
||||
pci_props.pci_bus,
|
||||
pci_props.pci_device,
|
||||
props.device_id,
|
||||
vk::api_version_major(props.api_version),
|
||||
vk::api_version_minor(props.api_version),
|
||||
vk::api_version_patch(props.api_version),
|
||||
(d.3 as f32 / GB).ceil(),
|
||||
unsafe { CStr::from_ptr(props.device_name.as_ptr()).to_str().unwrap() },
|
||||
);
|
||||
));
|
||||
}
|
||||
for desc in &numbered_devices {
|
||||
println!("{desc}");
|
||||
}
|
||||
|
||||
let mut device_test_index = Some(0usize);
|
||||
@ -746,14 +763,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
break;
|
||||
}
|
||||
input::ReaderEvent::Completed => {
|
||||
println!("");
|
||||
if !input_reader.current_input.is_empty() {
|
||||
let mut parsed = input_reader.current_input.parse::<usize>().unwrap();
|
||||
if parsed > 0 {
|
||||
parsed -= 1;
|
||||
match input_reader.current_input.parse::<usize>() {
|
||||
Ok(parsed_idx) => {
|
||||
let mut parsed = parsed_idx;
|
||||
if parsed > 0 {
|
||||
parsed -= 1;
|
||||
}
|
||||
device_test_index = Some(parsed);
|
||||
},
|
||||
Err(_) => {
|
||||
input_reader.current_input.clear();
|
||||
continue
|
||||
}
|
||||
}
|
||||
device_test_index = Some(parsed);
|
||||
}
|
||||
println!("");
|
||||
break;
|
||||
}
|
||||
input::ReaderEvent::Timeout => {} //just redraw prompt
|
||||
@ -761,15 +786,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
drop(input_reader);
|
||||
|
||||
let no_errors;
|
||||
if let Some(selected_index) = device_test_index {
|
||||
let (physical_device, queue_family, props, _max_local_heap_size, _pci_props_structure) =
|
||||
let (physical_device, queue_family, _, _, _) =
|
||||
*(compute_capable_devices
|
||||
.get(selected_index)
|
||||
.expect("No suitable physical device found"));
|
||||
.ok_or("No device at given index")?);
|
||||
|
||||
println!("Using physical device: {}", unsafe {
|
||||
CStr::from_ptr(props.device_name.as_ptr()).to_str().unwrap()
|
||||
});
|
||||
println!("Testing {}", numbered_devices[selected_index]);
|
||||
|
||||
let queue_create_info = vec![vk::DeviceQueueCreateInfoBuilder::new()
|
||||
.queue_family_index(queue_family)
|
||||
@ -779,14 +803,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.queue_create_infos(&queue_create_info)
|
||||
.enabled_layer_names(&device_layers);
|
||||
|
||||
test_device(
|
||||
no_errors = test_device(
|
||||
&instance,
|
||||
physical_device,
|
||||
queue_family,
|
||||
*device_create_info,
|
||||
debug_mode,
|
||||
)?;
|
||||
} else {
|
||||
println!("Test cancelled, no device selected");
|
||||
return Err("Test cancelled, no device selected".into());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
@ -795,7 +820,38 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
}
|
||||
instance.destroy_instance(None);
|
||||
}
|
||||
Ok(no_errors)
|
||||
}
|
||||
|
||||
println!("Exited cleanly");
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let debug_mode = match std::env::args_os().next() {
|
||||
Some(argv0) => match std::path::PathBuf::from(argv0)
|
||||
.file_stem()
|
||||
.map(std::ffi::OsStr::to_str)
|
||||
.flatten()
|
||||
{
|
||||
Some(file_stem) => file_stem.to_ascii_lowercase().contains("debug"),
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
print!("https://github.com/GpuZelenograd/");
|
||||
let _ = std::io::stdout().flush();
|
||||
let mut color_setter = input::Reader::default();
|
||||
color_setter.set_pass_fail_accent_color(true);
|
||||
println!("memtest_vulkan v{} by GpuZelenograd", env!("CARGO_PKG_VERSION"));
|
||||
drop(color_setter);
|
||||
let result = init_vk_and_check_no_errors(debug_mode);
|
||||
let mut key_reader = input::Reader::default();
|
||||
if result.is_ok() {
|
||||
key_reader.set_pass_fail_accent_color(*result.as_ref().unwrap());
|
||||
}
|
||||
match result
|
||||
{
|
||||
Ok(false) => println!("memtest_vulkan: memory/GPU errors found, testing finished."),
|
||||
Ok(true) => println!("memtest_vulkan: no any errors found, testing finished."),
|
||||
Err(e) => println!("memtest_vulkan: testing not done: {}", e)
|
||||
}
|
||||
key_reader.wait_any_key();
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user