Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T05:41:50.274Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

hang_detection.rs

124 lines · 4.4 KB · rust
1use std::sync::Arc;
2use std::thread;
3use std::time::Duration;
4
5use client::Client;
6use gpui::{AppContext, TasksIncluded, profiler};
7use parking_lot::Mutex;
8use ui::App;
9
10mod logging;
11mod task_traces;
12mod telemetry;
13
14gpui::actions!(
15    dev,
16    [
17        /// Causes a performance hang to test performance monitoring
18        HangAction,
19        /// Causes a performance hang to test performance monitoring
20        HangBackground,
21        /// Causes a performance hang to test performance monitoring
22        HangForeground,
23    ]
24);
25
26pub(crate) fn start(client: Arc<Client>, cx: &mut App) {
27    let hang_time = if cfg!(debug_assertions) {
28        if cfg!(windows) {
29            // yes windows debug builds are horribly slow
30            Duration::from_secs(30)
31        } else {
32            Duration::from_secs(5)
33        }
34    } else {
35        // will be lowered over time or turned into a setting
36        Duration::from_millis(100)
37    };
38
39    if cfg!(debug_assertions) {
40        log::warn!("debug build, only reporting hangs longer then {hang_time:?}");
41    }
42
43    start_hang_detection(hang_time, client, cx);
44
45    cx.on_action(move |_: &HangAction, _| {
46        log::warn!(
47            "Hanging the foreground for {hang_time:?} by blocking in an action. \
48            Omega will be unresponsive for that time. This should trigger a report in the log",
49        );
50        thread::sleep(hang_time + Duration::from_micros(1));
51        log::warn!("Hang ended");
52    });
53    cx.on_action(move |_: &HangBackground, cx| {
54        cx.background_spawn(async move {
55            log::warn!(
56                "Hanging one background executor for {hang_time:?}. \
57                This should trigger a report in the log",
58            );
59            thread::sleep(hang_time + Duration::from_micros(1));
60            log::warn!("Hang ended");
61        })
62        .detach();
63    });
64    cx.on_action(move |_: &HangForeground, cx| {
65        cx.spawn(async move |_| {
66            log::warn!(
67                "Hanging the foreground executor for {hang_time:?} seconds to test \
68                performance monitoring! Omega will be unresponsive for that time. \
69                This should trigger a report in the log"
70            );
71            thread::sleep(hang_time + Duration::from_micros(1));
72            log::warn!("Hang ended");
73        })
74        .detach();
75    });
76}
77
78fn start_hang_detection(report_longer_then: Duration, client: Arc<Client>, cx: &App) {
79    let foreground_thread = thread::current().id();
80    let monitor_interval = Duration::from_secs(1);
81    let telemetry = Arc::new(Mutex::new(telemetry::Reporter::new(foreground_thread)));
82    let mut log = logging::Reporter::new(monitor_interval, report_longer_then, foreground_thread);
83
84    let telemetry2 = Arc::clone(&telemetry);
85    cx.on_app_quit({
86        move |_| {
87            telemetry2.lock().send();
88            client.telemetry().flush_events()
89        }
90    })
91    .detach();
92
93    // an OS thread to insulate detection and reporting from hangs on the fore
94    // or background.
95    thread::Builder::new()
96        .name("HangDetection".to_string())
97        .spawn(move || {
98            // allow "bad" tasks during startup. Not because we should but since here
99            // they are not observed by the user and to lower on clutter from the reporter
100            thread::sleep(Duration::from_millis(200));
101            loop {
102                thread::sleep(monitor_interval);
103                // TODO(yara) the telemetry should not include still running tasks while the
104                // reports being logged should.
105                let task_stats = profiler::take_all_stats(TasksIncluded::CompletedAndRunning);
106                let action_stats = profiler::take_action_stats();
107
108                {
109                    let mut telemetry = telemetry.lock();
110                    telemetry.update(&task_stats, &action_stats);
111                    telemetry.send_periodically();
112                }
113
114                let should_write_trace = log.check_and_report(&task_stats, &action_stats);
115                if should_write_trace {
116                    if let Some(path) = task_traces::save_any(foreground_thread) {
117                        log::info!("Task trace has been saved to: {}", path.display());
118                    }
119                }
120            }
121        })
122        .expect("App can always spawn threads");
123}
124
Served at tenant.openagents/omega Member data and write actions are omitted.