File size: 5,109 Bytes
94004a2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/**
 * Settings → Performance panel (Wave 2 INST-12 UI half).
 *
 * Toggles the `Disable torch.compile (Windows)` setting that backend
 * engine launchers read via `services.engine_env.build_engine_env()`.
 *
 * The toggle is disabled (with an explainer tooltip) on non-Windows
 * platforms — torch.compile OOMs the same Triton kernel cache
 * differently on macOS / Linux, so toggling it there would just slow
 * the engine for no gain (issue #65).
 *
 * Endpoints:
 *   GET /api/settings/perf/torch-compile-disabled
 *     → {"enabled": bool, "platform": "darwin"|"linux"|"win32"}
 *   PUT /api/settings/perf/torch-compile-disabled
 *     body {"enabled": bool}  (loopback-only)
 */
import React, { useCallback, useEffect, useState } from 'react';
import { Cpu } from 'lucide-react';
import { apiJson, apiFetch } from '../../api/client';
import { useAppStore } from '../../store';
import './PerformancePanel.css';

export default function PerformancePanel() {
  const [enabled, setEnabled] = useState(false);
  const [platform, setPlatform] = useState(null);
  const [loading, setLoading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState(null);

  // Header live-metrics toggle (default OFF). Persisted via the Zustand
  // app store so it survives reload without a separate API round-trip.
  const showHeaderLiveStats = useAppStore(s => s.showHeaderLiveStats);
  const setShowHeaderLiveStats = useAppStore(s => s.setShowHeaderLiveStats);

  const refresh = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const data = await apiJson('/api/settings/perf/torch-compile-disabled');
      setEnabled(Boolean(data?.enabled));
      setPlatform(data?.platform ?? null);
    } catch (e) {
      setError(e?.message || 'Failed to load performance settings');
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    refresh();
  }, [refresh]);

  const isWindows = platform === 'win32';
  const tooltip = isWindows
    ? 'Sets TORCH_COMPILE_DISABLE=1 on engine subprocesses to dodge the Windows torch.compile OOM (#65).'
    : 'This setting only affects Windows; on macOS/Linux torch.compile is not the OOM source.';

  const onToggle = async (e) => {
    const next = e.target.checked;
    setSaving(true);
    setError(null);
    try {
      const res = await apiFetch('/api/settings/perf/torch-compile-disabled', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ enabled: next }),
      });
      const body = await res.json().catch(() => ({}));
      setEnabled(Boolean(body?.enabled ?? next));
    } catch (err) {
      setError(err?.message || 'Failed to save setting');
      // Re-sync on failure so the UI doesn't show a stale state
      refresh();
    } finally {
      setSaving(false);
    }
  };

  return (
    <section className="perfpanel" aria-labelledby="perfpanel-heading">
      <h3 id="perfpanel-heading" className="perfpanel__title">
        <Cpu size={14} /> Performance
      </h3>

      {error && (
        <div className="perfpanel__error" role="alert">
          {error}
        </div>
      )}

      <label className="perfpanel__row" title={tooltip}>
        <input
          type="checkbox"
          className="perfpanel__checkbox"
          checked={enabled}
          onChange={onToggle}
          disabled={!isWindows || saving || loading}
          data-testid="torch-compile-toggle"
        />
        <span className="perfpanel__label">Disable torch.compile (Windows)</span>
        {!isWindows && (
          <span className="perfpanel__badge">{platform === null ? '…' : 'not applicable'}</span>
        )}
      </label>

      <p className="perfpanel__help">
        Workaround for{' '}
        <a
          href="https://github.com/debpalash/OmniVoice-Studio/issues/65"
          target="_blank"
          rel="noopener noreferrer"
        >
          #65
        </a>{' '}
        — Windows users may hit Triton / <code>torch.compile</code> OOM during
        model load on GPUs with &lt;16 GB VRAM. Enabling this sets{' '}
        <code>TORCH_COMPILE_DISABLE=1</code> on engine subprocesses, which
        falls back to eager mode. macOS and Linux are unaffected.
      </p>

      <label className="perfpanel__row" title="Show RAM / CPU / VRAM live counters in the top bar.">
        <input
          type="checkbox"
          className="perfpanel__checkbox"
          checked={showHeaderLiveStats}
          onChange={(e) => setShowHeaderLiveStats(e.target.checked)}
          data-testid="header-live-stats-toggle"
        />
        <span className="perfpanel__label">Show live system metrics in header</span>
      </label>

      <p className="perfpanel__help">
        Default off — the header keeps the model-status badge and Flush
        button always visible because they're action-relevant, but RAM /
        CPU / VRAM counters are noise on the welcome screen. Turn this on
        if you want a live resource monitor in the top bar.
      </p>
    </section>
  );
}