Skip to content

Commit d1f3ade

Browse files
authored
Merge pull request #2 from bubablue/feat/optimizations-improvements
feat(optimizations improvements): Optimize single instance running
2 parents 7cc56d6 + 3898221 commit d1f3ade

File tree

9 files changed

+228
-67
lines changed

9 files changed

+228
-67
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@
127127
},
128128
"systemGraph.updateInterval": {
129129
"type": "number",
130-
"default": 2000,
130+
"default": 4000,
131131
"minimum": 500,
132132
"maximum": 10000,
133133
"description": "Update interval in milliseconds"

src/extension.ts

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,34 @@ import { StatusBarManager } from "./statusBarManager";
44
import { SystemMonitor } from "./systemMonitor";
55
import { SystemResourcesProvider } from "./systemResourcesProvider";
66

7+
interface GlobalExtensionState {
8+
systemMonitor: SystemMonitor | undefined;
9+
provider: SystemResourcesProvider | undefined;
10+
windowInstances: Map<string, {
11+
statusBarItems: StatusBarItems;
12+
statusBarManager: StatusBarManager;
13+
}>;
14+
instanceCount: number;
15+
}
16+
17+
const GLOBAL_STATE_KEY = Symbol.for('system-performance-extension.globalState');
18+
const globalThis_ = globalThis as any;
19+
20+
function getGlobalState(): GlobalExtensionState {
21+
if (!globalThis_[GLOBAL_STATE_KEY]) {
22+
globalThis_[GLOBAL_STATE_KEY] = {
23+
systemMonitor: undefined,
24+
provider: undefined,
25+
windowInstances: new Map(),
26+
instanceCount: 0,
27+
};
28+
}
29+
return globalThis_[GLOBAL_STATE_KEY];
30+
}
31+
732
let statusBarItems: StatusBarItems | undefined;
833
let statusBarManager: StatusBarManager;
9-
let systemMonitor: SystemMonitor;
10-
let provider: SystemResourcesProvider;
34+
let windowId: string;
1135

1236
async function requestSystemPermissions(context: vscode.ExtensionContext): Promise<boolean> {
1337
const permissionsGranted = context.globalState.get<boolean>('systemPermissionsGranted');
@@ -43,19 +67,34 @@ export function activate(context: vscode.ExtensionContext) {
4367
return;
4468
}
4569

46-
provider = new SystemResourcesProvider(context.extensionUri);
70+
const globalState = getGlobalState();
71+
globalState.instanceCount++;
72+
73+
windowId = `window-${Date.now()}-${Math.random()}`;
74+
4775
statusBarManager = new StatusBarManager();
48-
systemMonitor = new SystemMonitor(statusBarManager, provider);
76+
statusBarItems = statusBarManager.createStatusBarItems();
77+
78+
if (!globalState.systemMonitor) {
79+
globalState.provider = new SystemResourcesProvider(context.extensionUri);
80+
globalState.systemMonitor = new SystemMonitor(statusBarManager, globalState.provider);
81+
} else {
82+
globalState.systemMonitor.addStatusBarInstance(statusBarItems);
83+
}
84+
85+
globalState.windowInstances.set(windowId, {
86+
statusBarItems,
87+
statusBarManager
88+
});
4989

5090
context.subscriptions.push(
5191
vscode.window.registerWebviewViewProvider(
5292
SystemResourcesProvider.viewType,
53-
provider
93+
globalState.provider!
5494
)
5595
);
5696

57-
statusBarItems = statusBarManager.createStatusBarItems();
58-
systemMonitor.startSystemMonitoring(statusBarItems);
97+
globalState.systemMonitor.startSystemMonitoring(statusBarItems);
5998

6099
const showGraphDisposable = vscode.commands.registerCommand(
61100
"system-performance.showGraph",
@@ -75,7 +114,8 @@ export function activate(context: vscode.ExtensionContext) {
75114
"system-performance.refresh",
76115
() => {
77116
if (statusBarItems) {
78-
systemMonitor.startSystemMonitoring(statusBarItems);
117+
const globalState = getGlobalState();
118+
globalState.systemMonitor?.startSystemMonitoring(statusBarItems);
79119
}
80120
}
81121
);
@@ -84,7 +124,8 @@ export function activate(context: vscode.ExtensionContext) {
84124
"system-performance.toggleMonitoring",
85125
() => {
86126
if (statusBarItems) {
87-
systemMonitor.toggleMonitoring(statusBarItems);
127+
const globalState = getGlobalState();
128+
globalState.systemMonitor?.toggleMonitoring(statusBarItems);
88129
}
89130
}
90131
);
@@ -127,10 +168,29 @@ export function activate(context: vscode.ExtensionContext) {
127168
}
128169

129170
export function deactivate() {
130-
if (systemMonitor) {
131-
systemMonitor.dispose();
171+
const globalState = getGlobalState();
172+
173+
if (globalState.systemMonitor && statusBarItems) {
174+
globalState.systemMonitor.removeStatusBarInstance(statusBarItems);
175+
}
176+
177+
if (windowId) {
178+
globalState.windowInstances.delete(windowId);
132179
}
180+
181+
globalState.instanceCount--;
182+
133183
if (statusBarItems) {
134184
statusBarManager.disposeStatusBarItems(statusBarItems);
185+
statusBarItems = undefined;
186+
}
187+
188+
if (globalState.instanceCount <= 0) {
189+
if (globalState.systemMonitor) {
190+
globalState.systemMonitor.dispose();
191+
globalState.systemMonitor = undefined;
192+
}
193+
globalState.provider = undefined;
194+
globalState.windowInstances.clear();
135195
}
136196
}

src/systemMonitor.ts

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export class SystemMonitor {
2525
private static lastUpdateTime = 0;
2626
private static isUpdating = false;
2727
private static lastSystemData: any = null;
28+
private readonly statusBarInstances: StatusBarItems[] = [];
2829

2930
constructor(
3031
private readonly statusBarManager: StatusBarManager,
@@ -33,39 +34,53 @@ export class SystemMonitor {
3334
SystemMonitor.activeMonitors.add(this);
3435
}
3536

37+
public addStatusBarInstance(statusBarItems: StatusBarItems): void {
38+
if (!this.statusBarInstances.includes(statusBarItems)) {
39+
this.statusBarInstances.push(statusBarItems);
40+
}
41+
}
42+
43+
public removeStatusBarInstance(statusBarItems: StatusBarItems): void {
44+
const index = this.statusBarInstances.indexOf(statusBarItems);
45+
if (index > -1) {
46+
this.statusBarInstances.splice(index, 1);
47+
}
48+
}
49+
3650
public startSystemMonitoring(statusBarItems: StatusBarItems): void {
51+
this.addStatusBarInstance(statusBarItems);
52+
3753
if (this.updateInterval) {
3854
clearInterval(this.updateInterval);
3955
this.updateInterval = undefined;
4056
}
4157

4258
const config = vscode.workspace.getConfiguration("systemGraph");
43-
const updateIntervalMs = config.get("updateInterval", 2000);
59+
const updateIntervalMs = config.get("updateInterval", 4000);
4460

4561
if (!this.isPaused && this.monitoringEnabled) {
46-
SystemMonitor.globalInterval ??= setInterval(async () => {
47-
if (SystemMonitor.isUpdating) {
48-
return;
49-
}
62+
if (SystemMonitor.globalInterval) {
63+
clearInterval(SystemMonitor.globalInterval);
64+
SystemMonitor.globalInterval = undefined;
65+
}
5066

51-
const now = Date.now();
52-
if (now - SystemMonitor.lastUpdateTime < updateIntervalMs - 200) {
67+
SystemMonitor.globalInterval = setInterval(async () => {
68+
if (SystemMonitor.isUpdating) {
5369
return;
5470
}
5571

5672
SystemMonitor.isUpdating = true;
57-
SystemMonitor.lastUpdateTime = now;
73+
SystemMonitor.lastUpdateTime = Date.now();
5874

5975
try {
6076
const systemData = await SystemMonitor.collectSystemData();
6177
SystemMonitor.lastSystemData = systemData;
6278

6379
SystemMonitor.activeMonitors.forEach((monitor) => {
6480
if (monitor.monitoringEnabled && !monitor.isPaused) {
65-
const items = monitor.statusBarManager.getStatusBarItems();
66-
if (items) {
81+
monitor.statusBarInstances.forEach((items) => {
6782
monitor.updateWithSystemData(items, systemData);
68-
}
83+
});
6984
}
7085
});
7186
} catch (error) {
@@ -117,7 +132,7 @@ export class SystemMonitor {
117132
}
118133
}
119134

120-
public toggleMonitoring(statusBarItems: StatusBarItems): void {
135+
public toggleMonitoring(_statusBarItems: StatusBarItems): void {
121136
this.isPaused = !this.isPaused;
122137
const config = vscode.workspace.getConfiguration("systemGraph");
123138
config.update(
@@ -138,7 +153,10 @@ export class SystemMonitor {
138153
vscode.window.showInformationMessage("System monitoring paused");
139154

140155
this.monitoringEnabled = false;
141-
this.statusBarManager.hideAllStatusBarItems(statusBarItems);
156+
157+
this.statusBarInstances.forEach((items) => {
158+
this.statusBarManager.hideAllStatusBarItems(items);
159+
});
142160

143161
const anyActiveMonitor = Array.from(SystemMonitor.activeMonitors).some(
144162
(monitor) => monitor.monitoringEnabled && !monitor.isPaused
@@ -154,8 +172,14 @@ export class SystemMonitor {
154172
vscode.window.showInformationMessage("System monitoring resumed");
155173

156174
this.monitoringEnabled = true;
157-
this.startSystemMonitoring(statusBarItems);
158-
this.statusBarManager.updateStatusBarVisibility(statusBarItems);
175+
176+
if (this.statusBarInstances.length > 0) {
177+
this.startSystemMonitoring(this.statusBarInstances[0]);
178+
}
179+
180+
this.statusBarInstances.forEach((items) => {
181+
this.statusBarManager.updateStatusBarVisibility(items);
182+
});
159183
}
160184
}
161185

@@ -202,13 +226,11 @@ export class SystemMonitor {
202226

203227
const cpuPercent = Math.round(cpu.currentLoad);
204228

205-
// Calculate total CPU usage of all processes
206229
const totalProcessCpu = processes.list.reduce(
207230
(sum, p) => sum + (p.cpu || 0),
208231
0
209232
);
210233

211-
// Calculate VS Code CPU as percentage of all process CPU usage
212234
const vscodeCpuRelative =
213235
totalProcessCpu > 0
214236
? Math.round((vscodeCpu / totalProcessCpu) * 100)
@@ -347,7 +369,7 @@ export class SystemMonitor {
347369
data.vscodeMemoryMBRounded
348370
}MB\n${generateMiniGraph(
349371
this.historyData.vscodeMemory,
350-
2000
372+
4000
351373
)}\nClick to focus System Resources view`;
352374
statusBarItems.vscodeMemory.color = undefined;
353375

src/test/e2e/extension.test.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
import * as assert from "assert";
22
import * as vscode from "vscode";
3+
import { TestHelper } from "./testHelper";
34

45
suite("System Performance Extension E2E Tests", () => {
56
let extension: vscode.Extension<any>;
67

78
setup(async () => {
8-
extension = vscode.extensions.getExtension(
9-
"bubablue00.system-performance"
10-
)!;
11-
12-
if (!extension.isActive) {
13-
await extension.activate();
14-
}
9+
extension = await TestHelper.setupExtensionForTesting();
10+
});
1511

16-
await new Promise((resolve) => setTimeout(resolve, 2000));
12+
teardown(async () => {
13+
await TestHelper.cleanupExtension();
1714
});
1815

1916
test("Extension should be present and activated", async () => {
@@ -87,8 +84,8 @@ suite("System Performance Extension E2E Tests", () => {
8784
);
8885
assert.strictEqual(
8986
config.get("updateInterval"),
90-
2000,
91-
"updateInterval should default to 2000"
87+
4000,
88+
"updateInterval should default to 4000"
9289
);
9390
});
9491

@@ -150,17 +147,28 @@ suite("System Performance Extension E2E Tests", () => {
150147
test("Status bar configuration should work", async () => {
151148
const config = vscode.workspace.getConfiguration("systemGraph");
152149

150+
await config.update(
151+
"statusBarEnabled",
152+
true,
153+
vscode.ConfigurationTarget.Global
154+
);
155+
await new Promise((resolve) => setTimeout(resolve, 500));
156+
157+
// Now test disabling
153158
await config.update(
154159
"statusBarEnabled",
155160
false,
156161
vscode.ConfigurationTarget.Global
157162
);
158163

159-
await new Promise((resolve) => setTimeout(resolve, 1000));
164+
await new Promise((resolve) => setTimeout(resolve, 2000));
160165

161-
const updatedValue = config.get("statusBarEnabled");
166+
const freshConfig = vscode.workspace.getConfiguration("systemGraph");
167+
const updatedValue = freshConfig.get("statusBarEnabled");
168+
162169
assert.strictEqual(updatedValue, false, "Status bar should be disabled");
163170

171+
// Restore to true for cleanup
164172
await config.update(
165173
"statusBarEnabled",
166174
true,
@@ -173,7 +181,7 @@ suite("System Performance Extension E2E Tests", () => {
173181
test("System information should be collected", async () => {
174182
await vscode.commands.executeCommand("system-performance.refresh");
175183

176-
await new Promise((resolve) => setTimeout(resolve, 2000));
184+
await new Promise((resolve) => setTimeout(resolve, 4000));
177185

178186
assert.ok(true, "System information collection works");
179187
});

src/test/e2e/performance.test.ts

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
import * as assert from "assert";
22
import * as vscode from "vscode";
3+
import { TestHelper } from "./testHelper";
34

45
suite("System Performance Extension Performance Tests", () => {
5-
let extension: vscode.Extension<any>;
6-
76
setup(async () => {
8-
extension = vscode.extensions.getExtension(
9-
"bubablue00.system-performance"
10-
)!;
11-
12-
if (!extension.isActive) {
13-
await extension.activate();
14-
}
7+
await TestHelper.setupExtensionForTesting();
8+
});
159

16-
await new Promise((resolve) => setTimeout(resolve, 2000));
10+
teardown(async () => {
11+
await TestHelper.cleanupExtension();
1712
});
1813

1914
test("Extension activation should be fast", async () => {
@@ -99,7 +94,7 @@ suite("System Performance Extension Performance Tests", () => {
9994

10095
await config.update(
10196
"updateInterval",
102-
2000,
97+
4000,
10398
vscode.ConfigurationTarget.Global
10499
);
105100
});
@@ -137,7 +132,7 @@ suite("System Performance Extension Performance Tests", () => {
137132
config.update("updateInterval", 1000, vscode.ConfigurationTarget.Global),
138133
config.update("showCpu", true, vscode.ConfigurationTarget.Global),
139134
config.update("showMemory", true, vscode.ConfigurationTarget.Global),
140-
config.update("updateInterval", 2000, vscode.ConfigurationTarget.Global),
135+
config.update("updateInterval", 4000, vscode.ConfigurationTarget.Global),
141136
];
142137

143138
await Promise.all(configChanges);

0 commit comments

Comments
 (0)