diff --git a/pkg/dev_compiler/tool/input_sdk/patch/io_patch.dart b/pkg/dev_compiler/tool/input_sdk/patch/io_patch.dart index e3342f108f3..59aa7fff52f 100644 --- a/pkg/dev_compiler/tool/input_sdk/patch/io_patch.dart +++ b/pkg/dev_compiler/tool/input_sdk/patch/io_patch.dart @@ -290,6 +290,19 @@ class _ProcessUtils { } } +@patch +class ProcessInfo { + @patch + static int get currentRss { + throw new UnsupportedError("ProcessInfo.currentRss"); + } + + @patch + static int get maxRss { + throw new UnsupportedError("ProcessInfo.maxRss"); + } +} + @patch class Process { @patch diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc index b3a14e134f7..67b74763500 100644 --- a/runtime/bin/io_natives.cc +++ b/runtime/bin/io_natives.cc @@ -102,6 +102,8 @@ namespace bin { V(Process_Pid, 1) \ V(Process_SetSignalHandler, 1) \ V(Process_ClearSignalHandler, 1) \ + V(ProcessInfo_CurrentRSS, 0) \ + V(ProcessInfo_MaxRSS, 0) \ V(SecureSocket_Connect, 7) \ V(SecureSocket_Destroy, 1) \ V(SecureSocket_FilterPointer, 1) \ diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc index 80133289d31..ab2b9ace9d4 100644 --- a/runtime/bin/process.cc +++ b/runtime/bin/process.cc @@ -366,6 +366,26 @@ void FUNCTION_NAME(StringToSystemEncoding)(Dart_NativeArguments args) { Dart_SetReturnValue(args, external_array); } + +void FUNCTION_NAME(ProcessInfo_CurrentRSS)(Dart_NativeArguments args) { + int64_t current_rss = Process::CurrentRSS(); + if (current_rss < 0) { + Dart_SetReturnValue(args, DartUtils::NewDartOSError()); + return; + } + Dart_SetIntegerReturnValue(args, current_rss); +} + + +void FUNCTION_NAME(ProcessInfo_MaxRSS)(Dart_NativeArguments args) { + int64_t max_rss = Process::MaxRSS(); + if (max_rss < 0) { + Dart_SetReturnValue(args, DartUtils::NewDartOSError()); + return; + } + Dart_SetIntegerReturnValue(args, max_rss); +} + } // namespace bin } // namespace dart diff --git a/runtime/bin/process.h b/runtime/bin/process.h index 734db37c841..683e747837c 100644 --- a/runtime/bin/process.h +++ b/runtime/bin/process.h @@ -146,6 +146,9 @@ class Process { intptr_t* pid); static Dart_Handle SetProcessIdNativeField(Dart_Handle process, intptr_t pid); + static int64_t CurrentRSS(); + static int64_t MaxRSS(); + private: static int global_exit_code_; static Mutex* global_exit_code_mutex_; diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc index 64ee4dc7497..8107ee3dda9 100644 --- a/runtime/bin/process_android.cc +++ b/runtime/bin/process_android.cc @@ -20,8 +20,10 @@ #include "bin/dartutils.h" #include "bin/fdutils.h" +#include "bin/file.h" #include "bin/lockers.h" #include "bin/log.h" +#include "bin/reference_counting.h" #include "bin/thread.h" #include "platform/signal_blocker.h" @@ -887,6 +889,40 @@ intptr_t Process::CurrentProcessId() { } +int64_t Process::CurrentRSS() { + // The second value in /proc/self/statm is the current RSS in pages. + File* statm = File::Open("/proc/self/statm", File::kRead); + if (statm == NULL) { + return -1; + } + RefCntReleaseScope releaser(statm); + const intptr_t statm_length = 1 * KB; + void* buffer = reinterpret_cast(Dart_ScopeAllocate(statm_length)); + const intptr_t statm_read = statm->Read(buffer, statm_length); + if (statm_read <= 0) { + return -1; + } + int64_t current_rss_pages = 0; + int matches = sscanf(reinterpret_cast(buffer), "%*s%" Pd64 "", + ¤t_rss_pages); + if (matches != 1) { + return -1; + } + return current_rss_pages * getpagesize(); +} + + +int64_t Process::MaxRSS() { + struct rusage usage; + usage.ru_maxrss = 0; + int r = getrusage(RUSAGE_SELF, &usage); + if (r < 0) { + return -1; + } + return usage.ru_maxrss * KB; +} + + static Mutex* signal_mutex = new Mutex(); static SignalInfo* signal_handlers = NULL; static const int kSignalsCount = 7; diff --git a/runtime/bin/process_fuchsia.cc b/runtime/bin/process_fuchsia.cc index 26ca132afe6..14f3faa85e1 100644 --- a/runtime/bin/process_fuchsia.cc +++ b/runtime/bin/process_fuchsia.cc @@ -431,6 +431,27 @@ intptr_t Process::CurrentProcessId() { } +int64_t Process::CurrentRSS() { + mx_info_task_stats_t task_stats; + mx_handle_t process = mx_process_self(); + mx_status_t status = mx_object_get_info( + process, MX_INFO_TASK_STATS, &task_stats, sizeof(task_stats), NULL, NULL); + if (status != NO_ERROR) { + // TODO(zra): Translate this to a Unix errno. + errno = status; + return -1; + } + return task_stats.mem_committed_bytes; +} + + +int64_t Process::MaxRSS() { + // There is currently no way to get the high watermark value on Fuchsia, so + // just return the current RSS value. + return CurrentRSS(); +} + + static bool ProcessWaitCleanup(intptr_t out, intptr_t err, intptr_t exit_event, diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc index 29e6044db84..4e1ae8c73d7 100644 --- a/runtime/bin/process_linux.cc +++ b/runtime/bin/process_linux.cc @@ -15,13 +15,16 @@ #include // NOLINT #include // NOLINT #include // NOLINT +#include // NOLINT #include // NOLINT #include // NOLINT #include "bin/dartutils.h" #include "bin/fdutils.h" +#include "bin/file.h" #include "bin/lockers.h" #include "bin/log.h" +#include "bin/reference_counting.h" #include "bin/thread.h" #include "platform/signal_blocker.h" @@ -887,6 +890,40 @@ intptr_t Process::CurrentProcessId() { } +int64_t Process::CurrentRSS() { + // The second value in /proc/self/statm is the current RSS in pages. + File* statm = File::Open("/proc/self/statm", File::kRead); + if (statm == NULL) { + return -1; + } + RefCntReleaseScope releaser(statm); + const intptr_t statm_length = 1 * KB; + void* buffer = reinterpret_cast(Dart_ScopeAllocate(statm_length)); + const intptr_t statm_read = statm->Read(buffer, statm_length); + if (statm_read <= 0) { + return -1; + } + int64_t current_rss_pages = 0; + int matches = sscanf(reinterpret_cast(buffer), "%*s%" Pd64 "", + ¤t_rss_pages); + if (matches != 1) { + return -1; + } + return current_rss_pages * getpagesize(); +} + + +int64_t Process::MaxRSS() { + struct rusage usage; + usage.ru_maxrss = 0; + int r = getrusage(RUSAGE_SELF, &usage); + if (r < 0) { + return -1; + } + return usage.ru_maxrss * KB; +} + + static Mutex* signal_mutex = new Mutex(); static SignalInfo* signal_handlers = NULL; static const int kSignalsCount = 7; diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc index a4420d21251..6c0d451712f 100644 --- a/runtime/bin/process_macos.cc +++ b/runtime/bin/process_macos.cc @@ -14,6 +14,7 @@ #endif #include // NOLINT #include // NOLINT +#include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT @@ -968,6 +969,30 @@ intptr_t Process::CurrentProcessId() { } +int64_t Process::CurrentRSS() { + struct mach_task_basic_info info; + mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; + kern_return_t result = + task_info(mach_task_self(), MACH_TASK_BASIC_INFO, + reinterpret_cast(&info), &infoCount); + if (result != KERN_SUCCESS) { + return -1; + } + return info.resident_size; +} + + +int64_t Process::MaxRSS() { + struct rusage usage; + usage.ru_maxrss = 0; + int r = getrusage(RUSAGE_SELF, &usage); + if (r < 0) { + return -1; + } + return usage.ru_maxrss; +} + + static Mutex* signal_mutex = new Mutex(); static SignalInfo* signal_handlers = NULL; static const int kSignalsCount = 7; diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart index 03c0462f2b9..a4bd4513599 100644 --- a/runtime/bin/process_patch.dart +++ b/runtime/bin/process_patch.dart @@ -165,6 +165,30 @@ class _ProcessUtils { } } +@patch +class ProcessInfo { + @patch + static int get maxRss { + var result = _maxRss(); + if (result is OSError) { + throw result; + } + return result; + } + + @patch + static int get currentRss { + var result = _currentRss(); + if (result is OSError) { + throw result; + } + return result; + } + + static _maxRss() native "ProcessInfo_MaxRSS"; + static _currentRss() native "ProcessInfo_CurrentRSS"; +} + class _ProcessStartStatus { int _errorCode; // Set to OS error code if process start failed. String _errorMessage; // Set to OS error message if process start failed. diff --git a/runtime/bin/process_unsupported.cc b/runtime/bin/process_unsupported.cc index 1bb4ce879c8..f73f82d210e 100644 --- a/runtime/bin/process_unsupported.cc +++ b/runtime/bin/process_unsupported.cc @@ -92,6 +92,18 @@ void FUNCTION_NAME(StringToSystemEncoding)(Dart_NativeArguments args) { DartUtils::NewInternalError("Process is not supported on this platform")); } + +void FUNCTION_NAME(ProcessInfo_CurrentRSS)(Dart_NativeArguments args) { + Dart_ThrowException( + DartUtils::NewInternalError("Process is not supported on this platform")); +} + + +void FUNCTION_NAME(ProcessInfo_MaxRSS)(Dart_NativeArguments args) { + Dart_ThrowException( + DartUtils::NewInternalError("Process is not supported on this platform")); +} + } // namespace bin } // namespace dart diff --git a/runtime/bin/process_win.cc b/runtime/bin/process_win.cc index 56cd57d6b16..95f9cd34ad1 100644 --- a/runtime/bin/process_win.cc +++ b/runtime/bin/process_win.cc @@ -9,6 +9,7 @@ #include "bin/process.h" +#include // NOLINT #include // NOLINT #include "bin/builtin.h" @@ -941,6 +942,24 @@ intptr_t Process::CurrentProcessId() { } +int64_t Process::CurrentRSS() { + PROCESS_MEMORY_COUNTERS pmc; + if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { + return -1; + } + return pmc.WorkingSetSize; +} + + +int64_t Process::MaxRSS() { + PROCESS_MEMORY_COUNTERS pmc; + if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { + return -1; + } + return pmc.PeakWorkingSetSize; +} + + static SignalInfo* signal_handlers = NULL; static Mutex* signal_mutex = new Mutex(); diff --git a/runtime/vm/kernel.cc b/runtime/vm/kernel.cc index 293f946592b..8c0e7884c5e 100644 --- a/runtime/vm/kernel.cc +++ b/runtime/vm/kernel.cc @@ -80,7 +80,8 @@ bool CanonicalName::IsMember() { // Note the two occurrences of the parameter 'literal'. #define COMPARE_NAME(canonical_name, literal) \ - ((canonical_name)->name()->size() == strlen(literal) && \ + ((canonical_name)->name()->size() == \ + static_cast(strlen(literal)) && \ memcmp((canonical_name)->name()->buffer(), (literal), strlen(literal)) == \ 0) diff --git a/runtime/vm/os_fuchsia.cc b/runtime/vm/os_fuchsia.cc index 10e2640e922..72f854846d7 100644 --- a/runtime/vm/os_fuchsia.cc +++ b/runtime/vm/os_fuchsia.cc @@ -8,7 +8,9 @@ #include "vm/os.h" #include +#include #include +#include #include #include "platform/assert.h" @@ -156,8 +158,11 @@ int OS::NumberOfAvailableProcessors() { uintptr_t OS::MaxRSS() { - // TODO(US-95): Implement. - return 0; + mx_info_task_stats_t task_stats; + mx_handle_t process = mx_process_self(); + mx_status_t status = mx_object_get_info( + process, MX_INFO_TASK_STATS, &task_stats, sizeof(task_stats), NULL, NULL); + return (status == NO_ERROR) ? task_stats.mem_committed_bytes : 0; } diff --git a/sdk/lib/_internal/js_runtime/lib/io_patch.dart b/sdk/lib/_internal/js_runtime/lib/io_patch.dart index e3342f108f3..59aa7fff52f 100644 --- a/sdk/lib/_internal/js_runtime/lib/io_patch.dart +++ b/sdk/lib/_internal/js_runtime/lib/io_patch.dart @@ -290,6 +290,19 @@ class _ProcessUtils { } } +@patch +class ProcessInfo { + @patch + static int get currentRss { + throw new UnsupportedError("ProcessInfo.currentRss"); + } + + @patch + static int get maxRss { + throw new UnsupportedError("ProcessInfo.maxRss"); + } +} + @patch class Process { @patch diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart index 5bc531e45b2..bfe1c505139 100644 --- a/sdk/lib/io/process.dart +++ b/sdk/lib/io/process.dart @@ -99,6 +99,33 @@ void sleep(Duration duration) { */ int get pid => _ProcessUtils._pid(null); +/** + * [ProcessInfo] provides methods for retrieving information about the + * current process. + */ +class ProcessInfo { + /** + * The current resident set size of memory for the process. + * + * Note that the meaning of this field is platform dependent. For example, + * some memory acounted for here may be shared with other processes, or if + * the same page is mapped into a process's address space, it may be counted + * twice. + */ + external static int get currentRss; + + /** + * The high-watermark in bytes for the resident set size of memory for the + * process. + * + * Note that the meaning of this field is platform dependent. For example, + * some memory acounted for here may be shared with other processes, or if + * the same page is mapped into a process's address space, it may be counted + * twice. + */ + external static int get maxRss; +} + /** * Modes for running a new process. */ diff --git a/tests/standalone/io/process_info_test.dart b/tests/standalone/io/process_info_test.dart new file mode 100644 index 00000000000..72f2260a223 --- /dev/null +++ b/tests/standalone/io/process_info_test.dart @@ -0,0 +1,19 @@ +// 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:io"; + +import "package:expect/expect.dart"; + +main() { + int currentRss = ProcessInfo.currentRss; + print('currentRss = $currentRss'); + Expect.isTrue(currentRss > 0); + + int maxRss = ProcessInfo.maxRss; + print('maxRss = $maxRss'); + Expect.isTrue(maxRss > 0); + + Expect.isTrue(currentRss <= maxRss); +}