[vm, gc] Report RSS as timeline counter events, sampled before and after GC.

Catapult will display a nice graph for this.

TEST=view timeline
Change-Id: I6b6fdede463b37dbb10841cfa7c1e08c95e7cb62
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/427060
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
Ryan Macnak
2025-05-12 10:46:39 -07:00
committed by Commit Queue
parent 10fddf820e
commit eb563faf6d
11 changed files with 106 additions and 0 deletions
@@ -111,6 +111,10 @@ void allEventsHaveIsolateNumber(List<TimelineEvent> events) {
// Skip API category events which sometimes don't have an isolate.
continue;
}
if (event['name'] == 'RSS' && event['ph'] == 'C') {
// Skip RSS events, which don't have an isolate or isolate group.
continue;
}
if (event['cat'] == 'Embedder' &&
(event['name'] == 'DFE::ReadScript' ||
event['name'] == 'CreateIsolateGroupAndSetupHelper' ||
@@ -103,6 +103,10 @@ void allEventsHaveIsolateNumber(List events) {
// Skip API category events which sometimes don't have an isolate.
continue;
}
if (event['name'] == 'RSS' && event['ph'] == 'C') {
// Skip RSS events, which don't have an isolate or isolate group.
continue;
}
if (event['cat'] == 'Embedder' &&
(event['name'] == 'DFE::ReadScript' ||
event['name'] == 'CreateIsolateGroupAndSetupHelper')) {
+15
View File
@@ -1002,6 +1002,19 @@ void Heap::PrintMemoryUsageJSON(JSONObject* jsobj) const {
}
#endif // PRODUCT
static void RecordRSS() {
#if defined(SUPPORT_TIMELINE)
TimelineEvent* event = Timeline::GetGCStream()->StartEvent();
if (event != nullptr) {
event->Counter("RSS");
event->SetNumArguments(1);
event->FormatArgument(0, "value", "%" Pd, OS::CurrentRSS());
event->ClearIsolateGroupId(); // This value is per-process.
event->Complete();
}
#endif
}
void Heap::RecordBeforeGC(GCType type, GCReason reason) {
stats_.num_++;
stats_.type_ = type;
@@ -1010,6 +1023,7 @@ void Heap::RecordBeforeGC(GCType type, GCReason reason) {
stats_.before_.new_ = new_space_.GetCurrentUsage();
stats_.before_.old_ = old_space_.GetCurrentUsage();
stats_.before_.store_buffer_ = isolate_group_->store_buffer()->Size();
RecordRSS();
}
void Heap::RecordAfterGC(GCType type) {
@@ -1025,6 +1039,7 @@ void Heap::RecordAfterGC(GCType type) {
stats_.after_.new_ = new_space_.GetCurrentUsage();
stats_.after_.old_ = old_space_.GetCurrentUsage();
stats_.after_.store_buffer_ = isolate_group_->store_buffer()->Size();
RecordRSS();
#ifndef PRODUCT
// For now we'll emit the same GC events on all isolates.
if (Service::gc_stream.enabled()) {
+4
View File
@@ -68,6 +68,10 @@ class OS {
// Returns number of available processor cores.
static int NumberOfAvailableProcessors();
// Returns the current resident set size in bytes, or 0 if it could not be
// determined.
static uintptr_t CurrentRSS();
// Sleep the currently executing thread for millis ms.
static void Sleep(int64_t millis);
+17
View File
@@ -204,6 +204,23 @@ int OS::NumberOfAvailableProcessors() {
return sysconf(_SC_NPROCESSORS_ONLN);
}
uintptr_t OS::CurrentRSS() {
// The second value in /proc/self/statm is the current RSS in pages.
// It is not possible to use getrusage() because the interested fields are not
// implemented by the linux kernel.
FILE* statm = fopen("/proc/self/statm", "r");
if (statm == nullptr) {
return 0;
}
int64_t current_rss_pages = 0;
int matches = fscanf(statm, "%*s%" Pd64 "", &current_rss_pages);
fclose(statm);
if (matches != 1) {
return 0;
}
return current_rss_pages * getpagesize();
}
void OS::Sleep(int64_t millis) {
int64_t micros = millis * kMicrosecondsPerMillisecond;
SleepMicros(micros);
+12
View File
@@ -488,6 +488,18 @@ int OS::NumberOfAvailableProcessors() {
return sysconf(_SC_NPROCESSORS_CONF);
}
uintptr_t OS::CurrentRSS() {
zx_info_task_stats_t task_stats;
zx_handle_t process = zx_process_self();
zx_status_t status =
zx_object_get_info(process, ZX_INFO_TASK_STATS, &task_stats,
sizeof(task_stats), nullptr, nullptr);
if (status != ZX_OK) {
return 0;
}
return task_stats.mem_private_bytes + task_stats.mem_shared_bytes;
}
void OS::Sleep(int64_t millis) {
SleepMicros(millis * kMicrosecondsPerMillisecond);
}
+17
View File
@@ -521,6 +521,23 @@ int OS::NumberOfAvailableProcessors() {
return sysconf(_SC_NPROCESSORS_ONLN);
}
uintptr_t OS::CurrentRSS() {
// The second value in /proc/self/statm is the current RSS in pages.
// It is not possible to use getrusage() because the interested fields are not
// implemented by the linux kernel.
FILE* statm = fopen("/proc/self/statm", "r");
if (statm == nullptr) {
return 0;
}
int64_t current_rss_pages = 0;
int matches = fscanf(statm, "%*s%" Pd64 "", &current_rss_pages);
fclose(statm);
if (matches != 1) {
return 0;
}
return current_rss_pages * getpagesize();
}
void OS::Sleep(int64_t millis) {
int64_t micros = millis * kMicrosecondsPerMillisecond;
SleepMicros(micros);
+12
View File
@@ -123,6 +123,18 @@ int OS::NumberOfAvailableProcessors() {
return sysconf(_SC_NPROCESSORS_ONLN);
}
uintptr_t OS::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<task_info_t>(&info), &infoCount);
if (result != KERN_SUCCESS) {
return 0;
}
return info.resident_size;
}
void OS::Sleep(int64_t millis) {
int64_t micros = millis * kMicrosecondsPerMillisecond;
SleepMicros(micros);
+16
View File
@@ -238,6 +238,22 @@ int OS::NumberOfAvailableProcessors() {
return info.dwNumberOfProcessors;
}
uintptr_t OS::CurrentRSS() {
// Although the documentation at
// https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-getprocessmemoryinfo
// claims that GetProcessMemoryInfo is UWP compatible, it is actually not
// hence this function cannot work when compiled in UWP mode.
#ifdef DART_TARGET_OS_WINDOWS_UWP
return 0;
#else
PROCESS_MEMORY_COUNTERS pmc;
if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
return 0;
}
return pmc.WorkingSetSize;
#endif
}
void OS::Sleep(int64_t millis) {
::Sleep(millis);
}
+4
View File
@@ -1220,6 +1220,10 @@ bool TimelineEvent::HasIsolateGroupId() const {
return isolate_group_id_ != ILLEGAL_ISOLATE_GROUP_ID;
}
void TimelineEvent::ClearIsolateGroupId() {
isolate_group_id_ = ILLEGAL_ISOLATE_GROUP_ID;
}
TimelineTrackMetadata::TimelineTrackMetadata(intptr_t pid,
intptr_t tid,
CStringUniquePtr&& track_name)
+1
View File
@@ -457,6 +457,7 @@ class TimelineEvent {
bool HasIsolateId() const;
bool HasIsolateGroupId() const;
void ClearIsolateGroupId();
// The lowest time value stored in this event.
int64_t LowTime() const;