/** * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "runtime/mem/mem_stats.h" #include "libpandabase/utils/utf.h" #include "runtime/include/class.h" #include "runtime/include/runtime.h" #include "runtime/mem/mem_stats_additional_info.h" #include "runtime/mem/mem_stats_default.h" #include "runtime/mem/object_helpers.h" namespace panda::mem { template void MemStats::RecordAllocateObject(size_t size, SpaceType type_mem) { RecordAllocateObjects(1, size, type_mem); } template void MemStats::RecordAllocateObjects(size_t total_object_num, size_t total_object_size, SpaceType type_mem) { ASSERT(IsHeapSpace(type_mem)); RecordAllocate(total_object_size, type_mem); if (type_mem == SpaceType::SPACE_TYPE_HUMONGOUS_OBJECT) { // Atomic with acq_rel order reason: data race with humongous_objects_allocated_ with dependecies on reads after // the load and on writes before the store humongous_objects_allocated_.fetch_add(total_object_num, std::memory_order_acq_rel); } else { // Atomic with acq_rel order reason: data race with objects_allocated_ with dependecies on reads after the load // and on writes before the store objects_allocated_.fetch_add(total_object_num, std::memory_order_acq_rel); } } template void MemStats::RecordYoungMovedObjects(size_t young_object_num, size_t size, SpaceType type_mem) { ASSERT(IsHeapSpace(type_mem)); RecordMoved(size, type_mem); // We can't move SPACE_TYPE_HUMONGOUS_OBJECT ASSERT(type_mem != SpaceType::SPACE_TYPE_HUMONGOUS_OBJECT); // Atomic with acq_rel order reason: data race with last_young_objects_moved_bytes_ with dependecies on reads after // the load and on writes before the store last_young_objects_moved_bytes_.fetch_add(size, std::memory_order_acq_rel); // Atomic with acq_rel order reason: data race with objects_allocated_ with dependecies on reads after the load and // on writes before the store [[maybe_unused]] uint64_t old_val = objects_allocated_.fetch_sub(young_object_num, std::memory_order_acq_rel); ASSERT(old_val >= young_object_num); } template void MemStats::RecordTenuredMovedObjects(size_t tenured_object_num, size_t size, SpaceType type_mem) { ASSERT(IsHeapSpace(type_mem)); RecordMoved(size, type_mem); // We can't move SPACE_TYPE_HUMONGOUS_OBJECT ASSERT(type_mem != SpaceType::SPACE_TYPE_HUMONGOUS_OBJECT); // Atomic with acq_rel order reason: data race with objects_allocated_ with dependecies on reads after the load and // on writes before the store [[maybe_unused]] uint64_t old_val = objects_allocated_.fetch_sub(tenured_object_num, std::memory_order_acq_rel); ASSERT(old_val >= tenured_object_num); } template void MemStats::RecordFreeObject(size_t object_size, SpaceType type_mem) { RecordFreeObjects(1, object_size, type_mem); } template void MemStats::RecordFreeObjects(size_t total_object_num, size_t total_object_size, SpaceType type_mem) { ASSERT(IsHeapSpace(type_mem)); RecordFree(total_object_size, type_mem); if (type_mem == SpaceType::SPACE_TYPE_HUMONGOUS_OBJECT) { // Atomic with acq_rel order reason: data race with humongous_objects_freed_ with dependecies on reads after the // load and on writes before the store humongous_objects_freed_.fetch_add(total_object_num, std::memory_order_acq_rel); } else { // Atomic with acq_rel order reason: data race with objects_freed_ with dependecies on reads after the load and // on writes before the store objects_freed_.fetch_add(total_object_num, std::memory_order_acq_rel); } } template PandaString MemStats::GetStatistics(HeapManager *heap_manager) { PandaStringStream statistic; statistic << "memory statistics:" << std::endl; statistic << "heap: allocated - " << GetAllocatedHeap() << ", freed - " << GetFreedHeap() << std::endl; statistic << "raw memory: allocated - " << GetAllocated(SpaceType::SPACE_TYPE_INTERNAL) << ", freed - " << GetFreed(SpaceType::SPACE_TYPE_INTERNAL) << std::endl; statistic << "compiler: allocated - " << GetAllocated(SpaceType::SPACE_TYPE_CODE) << std::endl; statistic << "ArenaAllocator: allocated - " << GetAllocated(SpaceType::SPACE_TYPE_COMPILER) << std::endl; statistic << "total footprint now - " << GetTotalFootprint() << std::endl; statistic << "total allocated object - " << GetTotalObjectsAllocated() << std::endl; statistic << "min GC pause time - " << GetMinGCPause() << std::endl; statistic << "max GC pause time - " << GetMaxGCPause() << std::endl; statistic << "average GC pause time - " << GetAverageGCPause() << std::endl; statistic << "total GC pause time - " << GetTotalGCPause() << std::endl; auto additional_statistics = static_cast(this)->GetAdditionalStatistics(heap_manager); return statistic.str() + additional_statistics; } template [[nodiscard]] uint64_t MemStats::GetTotalObjectsAllocated() const { // Atomic with acquire order reason: data race with objects_allocated_ with dependecies on reads after the load // which should become visible return objects_allocated_.load(std::memory_order_acquire); } template [[nodiscard]] uint64_t MemStats::GetTotalObjectsFreed() const { // Atomic with acquire order reason: data race with objects_freed_ with dependecies on reads after the load which // should become visible return objects_freed_.load(std::memory_order_acquire); } template [[nodiscard]] uint64_t MemStats::GetTotalRegularObjectsAllocated() const { return GetTotalObjectsAllocated() - GetTotalHumongousObjectsAllocated(); } template [[nodiscard]] uint64_t MemStats::GetTotalRegularObjectsFreed() const { return GetTotalObjectsFreed() - GetTotalHumongousObjectsFreed(); } template [[nodiscard]] uint64_t MemStats::GetTotalHumongousObjectsAllocated() const { // Atomic with acquire order reason: data race with humongous_objects_allocated_ with dependecies on reads after the // load which should become visible return humongous_objects_allocated_.load(std::memory_order_acquire); } template [[nodiscard]] uint64_t MemStats::GetTotalHumongousObjectsFreed() const { // Atomic with acquire order reason: data race with humongous_objects_freed_ with dependecies on reads after the // load which should become visible return humongous_objects_freed_.load(std::memory_order_acquire); } template [[nodiscard]] uint64_t MemStats::GetObjectsCountAlive() const { return GetTotalObjectsAllocated() - GetTotalObjectsFreed(); } template [[nodiscard]] uint64_t MemStats::GetRegularObjectsCountAlive() const { return GetTotalRegularObjectsAllocated() - GetTotalRegularObjectsFreed(); } template [[nodiscard]] uint64_t MemStats::GetHumonguousObjectsCountAlive() const { return GetTotalHumongousObjectsAllocated() - GetTotalHumongousObjectsFreed(); } template [[nodiscard]] uint64_t MemStats::GetLastYoungObjectsMovedBytes() const { // Atomic with acquire order reason: data race with last_young_objects_moved_bytes_ with dependecies on reads after // the load which should become visible return last_young_objects_moved_bytes_.load(std::memory_order_acquire); } template void MemStats::RecordGCPauseStart() { pause_start_time_ = clock::now(); } template void MemStats::RecordGCPauseEnd() { duration pause_time = clock::now() - pause_start_time_; if (pause_count_) { min_pause_ = std::min(min_pause_, pause_time); max_pause_ = std::max(max_pause_, pause_time); } else { min_pause_ = pause_time; max_pause_ = pause_time; } pause_count_++; sum_pause_ += pause_time; } template uint64_t MemStats::GetMinGCPause() const { return std::chrono::duration_cast(min_pause_).count(); } template uint64_t MemStats::GetMaxGCPause() const { return std::chrono::duration_cast(max_pause_).count(); } template uint64_t MemStats::GetAverageGCPause() const { return pause_count_ ? std::chrono::duration_cast(sum_pause_).count() / pause_count_ : 0; } template uint64_t MemStats::GetTotalGCPause() const { return std::chrono::duration_cast(sum_pause_).count(); } template class MemStats; template class MemStats; } // namespace panda::mem