Skip to content

Commit 959f0a2

Browse files
jensjohaCommit Queue
authored and
Commit Queue
committed
[analyzer] Report memory usage on Windows too
Change-Id: I6a31370c51e40a9593f8875d365a43d9f4111aaf Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/275660 Reviewed-by: Brian Wilkerson <[email protected]> Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Jens Johansen <[email protected]>
1 parent c6d287c commit 959f0a2

File tree

3 files changed

+79
-10
lines changed

3 files changed

+79
-10
lines changed

pkg/analysis_server/lib/src/status/diagnostics.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,8 +1065,10 @@ class MemoryAndCpuPage extends DiagnosticPageWithNav {
10651065
var serviceProtocolInfo = await developer.Service.getInfo();
10661066

10671067
if (usage != null) {
1068-
buf.writeln(
1069-
writeOption('CPU', printPercentage(usage.cpuPercentage / 100.0)));
1068+
var cpuPercentage = usage.cpuPercentage;
1069+
if (cpuPercentage != null) {
1070+
buf.writeln(writeOption('CPU', printPercentage(cpuPercentage / 100.0)));
1071+
}
10701072
buf.writeln(writeOption('Memory', '${usage.memoryMB.round()} MB'));
10711073

10721074
h3('VM');

pkg/analysis_server/lib/src/utilities/profiling.dart

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'dart:convert';
56
import 'dart:io';
67

78
/// A class that can return memory and cpu usage information for a given
@@ -19,6 +20,10 @@ abstract class ProcessProfiler {
1920
return _PosixProcessProfiler();
2021
}
2122

23+
if (Platform.isWindows) {
24+
return _WindowsProcessProfiler();
25+
}
26+
2227
// Not a supported platform.
2328
return null;
2429
}
@@ -27,7 +32,7 @@ abstract class ProcessProfiler {
2732
class UsageInfo {
2833
/// A number between 0.0 and 100.0 * the number of host CPUs (but typically
2934
/// never more than slightly above 100.0).
30-
final double cpuPercentage;
35+
final double? cpuPercentage;
3136

3237
/// The process memory usage in kilobytes.
3338
final int memoryKB;
@@ -37,7 +42,12 @@ class UsageInfo {
3742
double get memoryMB => memoryKB / 1024;
3843

3944
@override
40-
String toString() => '$cpuPercentage% ${memoryMB.toStringAsFixed(1)}MB';
45+
String toString() {
46+
if (cpuPercentage != null) {
47+
return '$cpuPercentage% ${memoryMB.toStringAsFixed(1)}MB';
48+
}
49+
return '${memoryMB.toStringAsFixed(1)}MB';
50+
}
4151
}
4252

4353
class _PosixProcessProfiler extends ProcessProfiler {
@@ -74,3 +84,44 @@ class _PosixProcessProfiler extends ProcessProfiler {
7484
}
7585
}
7686
}
87+
88+
class _WindowsProcessProfiler extends ProcessProfiler {
89+
_WindowsProcessProfiler() : super._();
90+
91+
@override
92+
Future<UsageInfo?> getProcessUsage(int processId) async {
93+
try {
94+
var result = await Process.run(
95+
'tasklist', ['/FI', 'PID eq $processId', '/NH', '/FO', 'csv']);
96+
97+
if (result.exitCode != 0) {
98+
return Future.value(null);
99+
}
100+
101+
return Future.value(_parse(result.stdout as String));
102+
} catch (e) {
103+
return Future.error(e);
104+
}
105+
}
106+
107+
UsageInfo? _parse(String tasklistResults) {
108+
try {
109+
var lines = tasklistResults.split(RegExp("\r?\n"));
110+
for (var line in lines) {
111+
if (line.trim().isEmpty) continue;
112+
// Hacky parsing of csv line.
113+
var entries = jsonDecode("[$line]") as List;
114+
if (entries.length != 5) continue;
115+
// E.g. 123,456 K
116+
var memory = entries[4] as String;
117+
memory = memory.substring(0, memory.indexOf(" "));
118+
memory = memory.replaceAll(",", "");
119+
memory = memory.replaceAll(".", "");
120+
return UsageInfo(null, int.parse(memory));
121+
}
122+
return null;
123+
} catch (e) {
124+
return null;
125+
}
126+
}
127+
}

pkg/analysis_server/test/src/utilities/profiling_test.dart

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,13 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'dart:io';
6+
import 'dart:typed_data';
67

78
import 'package:analysis_server/src/utilities/profiling.dart';
89
import 'package:test/test.dart';
910

1011
void main() {
1112
group('ProcessProfiler', () {
12-
// Skip on windows.
13-
if (Platform.isWindows) {
14-
return;
15-
}
16-
1713
test('getProfilerForPlatform', () async {
1814
expect(ProcessProfiler.getProfilerForPlatform(), isNotNull);
1915
});
@@ -22,8 +18,28 @@ void main() {
2218
var profiler = ProcessProfiler.getProfilerForPlatform()!;
2319
var info = (await profiler.getProcessUsage(pid))!;
2420

25-
expect(info.cpuPercentage, greaterThanOrEqualTo(0.0));
21+
print("Uses ${info.memoryKB} KB");
22+
23+
if (Platform.isWindows) {
24+
expect(info.cpuPercentage, isNull);
25+
} else {
26+
expect(info.cpuPercentage, greaterThanOrEqualTo(0.0));
27+
}
2628
expect(info.memoryKB, greaterThanOrEqualTo(0));
29+
30+
// Use ~50 MB more memory and ensure that we actually use more memory
31+
// as reported by the return value.
32+
Uint8List use50mb = Uint8List(50 * 1024 * 1024);
33+
for (int i = 0; i < use50mb.length; i++) {
34+
use50mb[i] = i % 200;
35+
}
36+
var info2 = (await profiler.getProcessUsage(pid))!;
37+
print("Now uses ${info2.memoryKB} KB");
38+
39+
for (var b in use50mb) {
40+
if (b < 0) throw "This shouldn't happen, but we're using the data!";
41+
}
42+
expect(info2.memoryKB, greaterThan(info.memoryKB));
2743
});
2844
});
2945
}

0 commit comments

Comments
 (0)