Skip to content

Commit

Permalink
Merge branch 'develop' into steam-beta
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphiiko committed Dec 20, 2023
2 parents 64f0341 + d92005d commit 0e7c0d4
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 4 deletions.
7 changes: 7 additions & 0 deletions src-core/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ tempfile = "3.6.0"
strum = "0.25"
strum_macros = "0.25"
steamworks = { version = "0.10.0" }
human_bytes = { version = "0.4.3" }
system_shutdown = "4.0.1"
async-recursion = "1.0.5"
enumset = "1.1.3"
Expand Down
1 change: 1 addition & 0 deletions src-core/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ fn configure_command_handlers() -> impl Fn(tauri::Invoke) {
os::commands::set_hardware_mic_activity_enabled,
os::commands::set_hardware_mic_activivation_threshold,
os::commands::is_vrchat_active,
os::commands::activate_memory_watcher,
osc::commands::osc_send_bool,
osc::commands::osc_send_float,
osc::commands::osc_send_int,
Expand Down
11 changes: 11 additions & 0 deletions src-core/src/os/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,3 +308,14 @@ pub async fn set_mic_activity_device_id(device_id: Option<String>) {
};
manager.set_mic_activity_device_id(device_id).await;
}

#[tauri::command]
pub async fn activate_memory_watcher() -> bool {
let mut watcher_active_guard = super::MEMORY_WATCHER_ACTIVE.lock().await;
if *watcher_active_guard {
return false;
}
info!("[Core] Activating memory watcher");
*watcher_active_guard = true;
true
}
7 changes: 7 additions & 0 deletions src-core/src/os/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ lazy_static! {
static ref SOLOUD: std::sync::Mutex<Soloud> = std::sync::Mutex::new(Soloud::default().unwrap());
static ref AUDIO_DEVICE_MANAGER: Mutex<Option<AudioDeviceManager>> = Mutex::default();
static ref VRCHAT_ACTIVE: Mutex<bool> = Mutex::new(false);
static ref MEMORY_WATCHER_ACTIVE: Mutex<bool> = Mutex::new(false);
}

pub async fn init_audio_device_manager() {
Expand Down Expand Up @@ -60,6 +61,12 @@ async fn watch_processes() {
}
}
}
if {
let watcher_active = MEMORY_WATCHER_ACTIVE.lock().await;
*watcher_active
} {
crate::utils::monitor_memory_usage(false).await;
}
tokio::time::sleep(Duration::from_secs(1)).await;
}
}
Expand Down
73 changes: 71 additions & 2 deletions src-core/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
use log::error;
use human_bytes::human_bytes;
use log::{error, warn};
use serde::Serialize;
use std::{
os::raw::c_char,
time::{SystemTime, UNIX_EPOCH},
};
use sysinfo::{ProcessExt, Signal, System, SystemExt};
use sysinfo::{Pid, PidExt, Process, ProcessExt, Signal, System, SystemExt};
use tauri::Manager;
use tokio::sync::Mutex;

use crate::globals::{TAURI_APP_HANDLE, TAURI_CLI_MATCHES};

lazy_static! {
static ref SYSINFO: Mutex<System> = Mutex::new(System::new_all());
static ref LAST_MEM_DIALOG: Mutex<u128> = Mutex::new(0);
}

pub mod models;
Expand Down Expand Up @@ -111,3 +113,70 @@ pub fn convert_char_array_to_string(slice: &[c_char]) -> Option<String> {

String::from_utf8(trimmed_array).ok()
}

pub async fn monitor_memory_usage(refresh_processes: bool) {
let mut sysinfo_guard = SYSINFO.lock().await;
let sysinfo = &mut *sysinfo_guard;
// Get processes
if refresh_processes {
sysinfo.refresh_processes();
}
let processes = sysinfo.processes();
let parent_process_id = std::process::id();
// Collect all child process IDs
let mut process_ids: Vec<u32> = vec![];
loop {
let mut found = false;
for process in processes.values() {
let pid = process.pid().as_u32();
if process_ids.contains(&pid) {
continue;
}
if let Some(parent_pid) = process.parent() {
let parent_pid = parent_pid.as_u32();
if process_ids.contains(&parent_pid) || parent_pid == parent_process_id {
process_ids.push(pid);
found = true;
}
}
}
if !found {
break;
}
}
// Notify if any process memory usage is too high
let mut children: Vec<&Process> = Vec::new();
let mut last_mem_dialog = {
let last_mem_dialog_guard = LAST_MEM_DIALOG.lock().await;
*last_mem_dialog_guard
};
for pid in process_ids {
let ppid = &Pid::from_u32(pid);
let process = processes.get(ppid).unwrap();
children.push(&process);
let mem_b = process.memory();
if mem_b >= 1024000000 {
let mem = human_bytes(mem_b as f64);
warn!(
"[Core] SUBPROCESS \"{}\" IS USING {} OF MEMORY.",
process.name(),
mem
);
if last_mem_dialog + 30000 < get_time() {
let _ = tauri::api::dialog::MessageDialogBuilder::new(
"Possible Memory Leak Detected",
&format!(
"OyasumiVR's subprocess \"{}\" is using {} of memory. This is highly unlikely to happen, and likely indicates the presence of a memory leak. If you see this, please contact a developer.",
process.name(),
mem
),
)
.kind(tauri::api::dialog::MessageDialogKind::Error)
.show(|_|{});
let mut last_mem_dialog_guard = LAST_MEM_DIALOG.lock().await;
*last_mem_dialog_guard = get_time();
last_mem_dialog = get_time();
}
}
}
}
4 changes: 4 additions & 0 deletions src-ui/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,10 @@ export class AppModule {
}
// Only initialize update service after language selection
await this.updateService.init();
// Start memory watcher automatically on development builds
if (FLAVOUR === 'DEV') {
await invoke<boolean>('activate_memory_watcher');
}
}

async preloadAssets() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ <h2 translate>settings.advanced.persistentData.title</h2>
<div class="setting-row-label" translate>
<span translate>{{
'settings.advanced.persistentData.dataType.' + item.key + '.title' | translate
}}</span>
}}</span>
<span translate>{{
'settings.advanced.persistentData.dataType.' + item.key + '.description' | translate
}}</span>
}}</span>
</div>
<div class="setting-row-action">
<label class="check-toggle">
Expand Down Expand Up @@ -157,6 +157,21 @@ <h2 translate>settings.advanced.fixes.title</h2>
</button>
</div>
</div>
<div class="setting-row">
<div class="setting-row-label" translate>
<span translate>settings.advanced.fixes.memoryWatcher.title</span>
<span translate>settings.advanced.fixes.memoryWatcher.description</span>
</div>
<div class="setting-row-action">
<button
class="btn btn-primary"
[disabled]="memoryWatcherActive"
(click)="activateMemoryWatcher()"
>
<span translate>settings.advanced.fixes.memoryWatcher.action</span>
</button>
</div>
</div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { SetDebugTranslationsRequest } from '../../../../../../src-grpc-web-clie
import { OpenVRService } from 'src-ui/app/services/openvr.service';
import { AppSettingsService } from '../../../../services/app-settings.service';
import { OscService } from '../../../../services/osc.service';
import { FLAVOUR } from '../../../../../build';

@Component({
selector: 'app-settings-advanced-view',
Expand All @@ -56,6 +57,7 @@ export class SettingsAdvancedViewComponent {
{ key: 'miscData' },
];
checkedPersistentStorageItems: string[] = [];
memoryWatcherActive = FLAVOUR === 'DEV';

constructor(
private router: Router,
Expand Down Expand Up @@ -312,4 +314,25 @@ export class SettingsAdvancedViewComponent {
})
.subscribe();
}

async activateMemoryWatcher() {
this.memoryWatcherActive = true;
if (await invoke<boolean>('activate_memory_watcher')) {
this.modalService
.addModal<ConfirmModalInputModel, ConfirmModalOutputModel>(ConfirmModalComponent, {
title: 'settings.advanced.fixes.memoryWatcher.modal.success.title',
message: 'settings.advanced.fixes.memoryWatcher.modal.success.message',
showCancel: false,
})
.subscribe();
} else {
this.modalService
.addModal<ConfirmModalInputModel, ConfirmModalOutputModel>(ConfirmModalComponent, {
title: 'settings.advanced.fixes.memoryWatcher.modal.error.title',
message: 'settings.advanced.fixes.memoryWatcher.modal.error.message',
showCancel: false,
})
.subscribe();
}
}
}
15 changes: 15 additions & 0 deletions src-ui/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,21 @@
"message": "The internal OSC- and OSCQuery services have been restarted."
}
}
},
"memoryWatcher": {
"title": "Memory Watcher",
"description": "Activate the memory watcher to monitor all child processes. An error dialog will be shown if any processes exceed a gigabyte of memory usage, and extra information will be logged.",
"action": "Activate",
"modal": {
"error": {
"title": "Already Active",
"message": "The memory watcher was already active."
},
"success": {
"title": "Memory Watcher Activated",
"message": "The memory watcher has been activated!"
}
}
}
}
},
Expand Down

0 comments on commit 0e7c0d4

Please sign in to comment.