[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:
committed by
Commit Queue
parent
10fddf820e
commit
eb563faf6d
@@ -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')) {
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 "", ¤t_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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 "", ¤t_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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user