- Add VariableSpec class with magnitude field validation - Add Formula class supporting multiple input/output variables - Support d4rt_code as string or object with code field - Add comprehensive tests for parsing and serialization - Fix broken test import in pruebas_d4rt_test.dart Follows README.md format requirements exactly
135 lines
3.5 KiB
Dart
135 lines
3.5 KiB
Dart
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
|
|
// 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
|
|
/// process.
|
|
abstract class ProcessProfiler {
|
|
ProcessProfiler._();
|
|
|
|
Future<UsageInfo?> getProcessUsage(int processId);
|
|
|
|
/// Return a [ProcessProfiler] instance suitable for the current host
|
|
/// platform. This can return `null` if we're not able to gather memory and
|
|
/// cpu information for the current platform.
|
|
static ProcessProfiler? getProfilerForPlatform() {
|
|
if (Platform.isLinux || Platform.isMacOS) {
|
|
return _PosixProcessProfiler();
|
|
}
|
|
|
|
if (Platform.isWindows) {
|
|
return _WindowsProcessProfiler();
|
|
}
|
|
|
|
// Not a supported platform.
|
|
return null;
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
/// The process memory usage in kilobytes.
|
|
final int memoryKB;
|
|
|
|
UsageInfo(this.cpuPercentage, this.memoryKB);
|
|
|
|
double get memoryMB => memoryKB / 1024;
|
|
|
|
@override
|
|
String toString() {
|
|
if (cpuPercentage != null) {
|
|
return '$cpuPercentage% ${memoryMB.toStringAsFixed(1)}MB';
|
|
}
|
|
return '${memoryMB.toStringAsFixed(1)}MB';
|
|
}
|
|
}
|
|
|
|
class _PosixProcessProfiler extends ProcessProfiler {
|
|
static final RegExp stringSplitRegExp = RegExp(r'\s+');
|
|
|
|
_PosixProcessProfiler() : super._();
|
|
|
|
@override
|
|
Future<UsageInfo?> getProcessUsage(int processId) {
|
|
try {
|
|
// Execution time is typically 2-4ms.
|
|
var future = Process.run('ps', [
|
|
'-o',
|
|
'%cpu=,rss=',
|
|
processId.toString(),
|
|
]);
|
|
return future.then((ProcessResult result) {
|
|
if (result.exitCode != 0) {
|
|
return Future.value();
|
|
}
|
|
|
|
return Future.value(_parse(result.stdout as String));
|
|
});
|
|
} catch (e) {
|
|
return Future.error(e);
|
|
}
|
|
}
|
|
|
|
UsageInfo? _parse(String psResults) {
|
|
try {
|
|
// " 0.0 378940"
|
|
var line = psResults.split('\n').first.trim();
|
|
var values = line.split(stringSplitRegExp);
|
|
return UsageInfo(double.parse(values[0]), int.parse(values[1]));
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|