[analyzer] Report memory usage on Windows too

Change-Id: I6a31370c51e40a9593f8875d365a43d9f4111aaf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/275660
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
This commit is contained in:
Jens Johansen 2022-12-14 18:11:25 +00:00 committed by Commit Queue
parent c6d287cc05
commit 959f0a299c
3 changed files with 79 additions and 10 deletions

View file

@ -1065,8 +1065,10 @@ class MemoryAndCpuPage extends DiagnosticPageWithNav {
var serviceProtocolInfo = await developer.Service.getInfo();
if (usage != null) {
buf.writeln(
writeOption('CPU', printPercentage(usage.cpuPercentage / 100.0)));
var cpuPercentage = usage.cpuPercentage;
if (cpuPercentage != null) {
buf.writeln(writeOption('CPU', printPercentage(cpuPercentage / 100.0)));
}
buf.writeln(writeOption('Memory', '${usage.memoryMB.round()} MB'));
h3('VM');

View file

@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:convert';
import 'dart:io';
/// A class that can return memory and cpu usage information for a given
@ -19,6 +20,10 @@ abstract class ProcessProfiler {
return _PosixProcessProfiler();
}
if (Platform.isWindows) {
return _WindowsProcessProfiler();
}
// Not a supported platform.
return null;
}
@ -27,7 +32,7 @@ abstract class ProcessProfiler {
class UsageInfo {
/// A number between 0.0 and 100.0 * the number of host CPUs (but typically
/// never more than slightly above 100.0).
final double cpuPercentage;
final double? cpuPercentage;
/// The process memory usage in kilobytes.
final int memoryKB;
@ -37,7 +42,12 @@ class UsageInfo {
double get memoryMB => memoryKB / 1024;
@override
String toString() => '$cpuPercentage% ${memoryMB.toStringAsFixed(1)}MB';
String toString() {
if (cpuPercentage != null) {
return '$cpuPercentage% ${memoryMB.toStringAsFixed(1)}MB';
}
return '${memoryMB.toStringAsFixed(1)}MB';
}
}
class _PosixProcessProfiler extends ProcessProfiler {
@ -74,3 +84,44 @@ class _PosixProcessProfiler extends ProcessProfiler {
}
}
}
class _WindowsProcessProfiler extends ProcessProfiler {
_WindowsProcessProfiler() : super._();
@override
Future<UsageInfo?> getProcessUsage(int processId) async {
try {
var result = await Process.run(
'tasklist', ['/FI', 'PID eq $processId', '/NH', '/FO', 'csv']);
if (result.exitCode != 0) {
return Future.value(null);
}
return Future.value(_parse(result.stdout as String));
} catch (e) {
return Future.error(e);
}
}
UsageInfo? _parse(String tasklistResults) {
try {
var lines = tasklistResults.split(RegExp("\r?\n"));
for (var line in lines) {
if (line.trim().isEmpty) continue;
// Hacky parsing of csv line.
var entries = jsonDecode("[$line]") as List;
if (entries.length != 5) continue;
// E.g. 123,456 K
var memory = entries[4] as String;
memory = memory.substring(0, memory.indexOf(" "));
memory = memory.replaceAll(",", "");
memory = memory.replaceAll(".", "");
return UsageInfo(null, int.parse(memory));
}
return null;
} catch (e) {
return null;
}
}
}

View file

@ -3,17 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
import 'dart:io';
import 'dart:typed_data';
import 'package:analysis_server/src/utilities/profiling.dart';
import 'package:test/test.dart';
void main() {
group('ProcessProfiler', () {
// Skip on windows.
if (Platform.isWindows) {
return;
}
test('getProfilerForPlatform', () async {
expect(ProcessProfiler.getProfilerForPlatform(), isNotNull);
});
@ -22,8 +18,28 @@ void main() {
var profiler = ProcessProfiler.getProfilerForPlatform()!;
var info = (await profiler.getProcessUsage(pid))!;
expect(info.cpuPercentage, greaterThanOrEqualTo(0.0));
print("Uses ${info.memoryKB} KB");
if (Platform.isWindows) {
expect(info.cpuPercentage, isNull);
} else {
expect(info.cpuPercentage, greaterThanOrEqualTo(0.0));
}
expect(info.memoryKB, greaterThanOrEqualTo(0));
// Use ~50 MB more memory and ensure that we actually use more memory
// as reported by the return value.
Uint8List use50mb = Uint8List(50 * 1024 * 1024);
for (int i = 0; i < use50mb.length; i++) {
use50mb[i] = i % 200;
}
var info2 = (await profiler.getProcessUsage(pid))!;
print("Now uses ${info2.memoryKB} KB");
for (var b in use50mb) {
if (b < 0) throw "This shouldn't happen, but we're using the data!";
}
expect(info2.memoryKB, greaterThan(info.memoryKB));
});
});
}