X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fsgen%2Fsgen-memory-governor.c;h=12c775a2384a1c106251a5ab5e5c2e1830bf81ce;hb=HEAD;hp=611ae5c118f4d66b7e1eb982fd4d32048e78a20b;hpb=df9c98dda18083ec63171490267e08342621ef45;p=mono.git diff --git a/mono/sgen/sgen-memory-governor.c b/mono/sgen/sgen-memory-governor.c index 611ae5c118f..12c775a2384 100644 --- a/mono/sgen/sgen-memory-governor.c +++ b/mono/sgen/sgen-memory-governor.c @@ -1,6 +1,6 @@ -/* - * sgen-memory-governor.c: When to schedule collections based on - * memory usage. +/** + * \file + * When to schedule collections based on memory usage. * * Author: * Rodrigo Kumpera (rkumpera@novell.com) @@ -10,18 +10,7 @@ * Copyright 2011 Xamarin Inc (http://www.xamarin.com) * Copyright (C) 2012 Xamarin Inc * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License 2.0 as published by the Free Software Foundation; - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License 2.0 along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Licensed under the MIT license. See LICENSE file in the project root for full license information. */ #include "config.h" @@ -31,10 +20,18 @@ #include "mono/sgen/sgen-gc.h" #include "mono/sgen/sgen-memory-governor.h" -#include "mono/sgen/sgen-thread-pool.h" +#include "mono/sgen/sgen-workers.h" #include "mono/sgen/sgen-client.h" -#define MIN_MINOR_COLLECTION_ALLOWANCE ((mword)(DEFAULT_NURSERY_SIZE * default_allowance_nursery_size_ratio)) +#define MIN_MINOR_COLLECTION_ALLOWANCE ((mword)(SGEN_DEFAULT_NURSERY_SIZE * default_allowance_nursery_size_ratio)) + +static SgenPointerQueue log_entries = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_TEMPORARY); +static mono_mutex_t log_entries_mutex; + +mword total_promoted_size = 0; +mword total_allocated_major = 0; +static mword total_promoted_size_start; +static mword total_allocated_major_end; /*Heap limits and allocation knobs*/ static mword max_heap_size = ((mword)0)- ((mword)1); @@ -48,6 +45,9 @@ static mword allocated_heap; static mword total_alloc = 0; static mword total_alloc_max = 0; +static SGEN_TV_DECLARE(last_minor_start); +static SGEN_TV_DECLARE(last_major_start); + /* GC triggers. */ static gboolean debug_print_allowance = FALSE; @@ -59,13 +59,11 @@ static mword major_collection_trigger_size; static mword major_pre_sweep_heap_size; static mword major_start_heap_size; -static mword last_major_num_sections = 0; -static mword last_los_memory_usage = 0; - static gboolean need_calculate_minor_collection_allowance; /* The size of the LOS after the last major collection, after sweeping. */ static mword last_collection_los_memory_usage = 0; +static mword last_used_slots_size = 0; static mword sgen_memgov_available_free_space (void); @@ -113,7 +111,7 @@ sgen_memgov_calculate_minor_collection_allowance (void) /* FIXME: Why is this here? */ if (major_collector.free_swept_blocks) - major_collector.free_swept_blocks (allowance); + major_collector.free_swept_blocks (major_collector.get_num_major_sections () * SGEN_DEFAULT_ALLOWANCE_HEAP_SIZE_RATIO); major_collection_trigger_size = new_heap_size + allowance; @@ -171,11 +169,38 @@ sgen_need_major_collection (mword space_needed) void sgen_memgov_minor_collection_start (void) { + total_promoted_size_start = total_promoted_size; + SGEN_TV_GETTIME (last_minor_start); +} + +static void +sgen_add_log_entry (SgenLogEntry *log_entry) +{ + mono_os_mutex_lock (&log_entries_mutex); + sgen_pointer_queue_add (&log_entries, log_entry); + mono_os_mutex_unlock (&log_entries_mutex); } void -sgen_memgov_minor_collection_end (void) +sgen_memgov_minor_collection_end (const char *reason, gboolean is_overflow) { + if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_GC)) { + SgenLogEntry *log_entry = (SgenLogEntry*)sgen_alloc_internal (INTERNAL_MEM_LOG_ENTRY); + SGEN_TV_DECLARE (current_time); + SGEN_TV_GETTIME (current_time); + + log_entry->type = SGEN_LOG_NURSERY; + log_entry->reason = reason; + log_entry->is_overflow = is_overflow; + log_entry->time = SGEN_TV_ELAPSED (last_minor_start, current_time); + log_entry->promoted_size = total_promoted_size - total_promoted_size_start; + log_entry->major_size = major_collector.get_num_major_sections () * major_collector.section_size; + log_entry->major_size_in_use = last_used_slots_size + total_allocated_major - total_allocated_major_end; + log_entry->los_size = los_memory_usage_total; + log_entry->los_size_in_use = los_memory_usage; + + sgen_add_log_entry (log_entry); + } } void @@ -190,7 +215,22 @@ sgen_memgov_major_pre_sweep (void) } void -sgen_memgov_major_collection_start (void) +sgen_memgov_major_post_sweep (mword used_slots_size) +{ + if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_GC)) { + SgenLogEntry *log_entry = (SgenLogEntry*)sgen_alloc_internal (INTERNAL_MEM_LOG_ENTRY); + + log_entry->type = SGEN_LOG_MAJOR_SWEEP_FINISH; + log_entry->major_size = major_collector.get_num_major_sections () * major_collector.section_size; + log_entry->major_size_in_use = used_slots_size + total_allocated_major - total_allocated_major_end; + + sgen_add_log_entry (log_entry); + } + last_used_slots_size = used_slots_size; +} + +void +sgen_memgov_major_collection_start (gboolean concurrent, const char *reason) { need_calculate_minor_collection_allowance = TRUE; major_start_heap_size = get_heap_size (); @@ -198,13 +238,41 @@ sgen_memgov_major_collection_start (void) if (debug_print_allowance) { SGEN_LOG (0, "Starting collection with heap size %ld bytes", (long)major_start_heap_size); } + if (concurrent && mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_GC)) { + SgenLogEntry *log_entry = (SgenLogEntry*)sgen_alloc_internal (INTERNAL_MEM_LOG_ENTRY); + + log_entry->type = SGEN_LOG_MAJOR_CONC_START; + log_entry->reason = reason; + + sgen_add_log_entry (log_entry); + } + SGEN_TV_GETTIME (last_major_start); } void -sgen_memgov_major_collection_end (gboolean forced) +sgen_memgov_major_collection_end (gboolean forced, gboolean concurrent, const char *reason, gboolean is_overflow) { - last_collection_los_memory_usage = los_memory_usage; + if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_GC)) { + SgenLogEntry *log_entry = (SgenLogEntry*)sgen_alloc_internal (INTERNAL_MEM_LOG_ENTRY); + SGEN_TV_DECLARE (current_time); + SGEN_TV_GETTIME (current_time); + + if (concurrent) { + log_entry->type = SGEN_LOG_MAJOR_CONC_FINISH; + } else { + log_entry->type = SGEN_LOG_MAJOR_SERIAL; + } + log_entry->time = SGEN_TV_ELAPSED (last_major_start, current_time); + log_entry->reason = reason; + log_entry->is_overflow = is_overflow; + log_entry->los_size = los_memory_usage_total; + log_entry->los_size_in_use = los_memory_usage; + + sgen_add_log_entry (log_entry); + } + last_collection_los_memory_usage = los_memory_usage; + total_allocated_major_end = total_allocated_major; if (forced) { sgen_get_major_collector ()->finish_sweeping (); sgen_memgov_calculate_minor_collection_allowance (); @@ -216,15 +284,77 @@ sgen_memgov_collection_start (int generation) { } +static void +sgen_output_log_entry (SgenLogEntry *entry, gint64 stw_time, int generation) +{ + char full_timing_buff [1024]; + full_timing_buff [0] = '\0'; + + if (!entry->is_overflow) + sprintf (full_timing_buff, "stw %.2fms", stw_time / 10000.0f); + + switch (entry->type) { + case SGEN_LOG_NURSERY: + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_MINOR%s: (%s) time %.2fms, %s promoted %zdK major size: %zdK in use: %zdK los size: %zdK in use: %zdK", + entry->is_overflow ? "_OVERFLOW" : "", + entry->reason ? entry->reason : "", + entry->time / 10000.0f, + (generation == GENERATION_NURSERY) ? full_timing_buff : "", + entry->promoted_size / 1024, + entry->major_size / 1024, + entry->major_size_in_use / 1024, + entry->los_size / 1024, + entry->los_size_in_use / 1024); + break; + case SGEN_LOG_MAJOR_SERIAL: + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_MAJOR%s: (%s) time %.2fms, %s los size: %zdK in use: %zdK", + entry->is_overflow ? "_OVERFLOW" : "", + entry->reason ? entry->reason : "", + (int)entry->time / 10000.0f, + full_timing_buff, + entry->los_size / 1024, + entry->los_size_in_use / 1024); + break; + case SGEN_LOG_MAJOR_CONC_START: + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_MAJOR_CONCURRENT_START: (%s)", entry->reason ? entry->reason : ""); + break; + case SGEN_LOG_MAJOR_CONC_FINISH: + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_MAJOR_CONCURRENT_FINISH: (%s) time %.2fms, %s los size: %zdK in use: %zdK", + entry->reason ? entry->reason : "", + entry->time / 10000.0f, + full_timing_buff, + entry->los_size / 1024, + entry->los_size_in_use / 1024); + break; + case SGEN_LOG_MAJOR_SWEEP_FINISH: + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "GC_MAJOR_SWEEP: major size: %zdK in use: %zdK", + entry->major_size / 1024, + entry->major_size_in_use / 1024); + break; + default: + SGEN_ASSERT (0, FALSE, "Invalid log entry type"); + break; + } +} + void -sgen_memgov_collection_end (int generation, GGTimingInfo* info, int info_count) +sgen_memgov_collection_end (int generation, gint64 stw_time) { - int i; - for (i = 0; i < info_count; ++i) { - if (info[i].generation != -1) - sgen_client_log_timing (&info [i], last_major_num_sections, last_los_memory_usage); + /* + * At this moment the world has been restarted which means we can log all pending entries + * without risking deadlocks. + */ + if (mono_trace_is_traced (G_LOG_LEVEL_INFO, MONO_TRACE_GC)) { + size_t i; + SGEN_ASSERT (0, !sgen_is_world_stopped (), "We can't log if the world is stopped"); + mono_os_mutex_lock (&log_entries_mutex); + for (i = 0; i < log_entries.next_slot; i++) { + sgen_output_log_entry (log_entries.data [i], stw_time, generation); + sgen_free_internal (log_entries.data [i], INTERNAL_MEM_LOG_ENTRY); + } + sgen_pointer_queue_clear (&log_entries); + mono_os_mutex_unlock (&log_entries_mutex); } - last_major_num_sections = major_collector.get_num_major_sections (); } /* @@ -254,13 +384,13 @@ sgen_assert_memory_alloc (void *ptr, size_t requested_size, const char *assert_d * This must not require any lock. */ void* -sgen_alloc_os_memory (size_t size, SgenAllocFlags flags, const char *assert_description) +sgen_alloc_os_memory (size_t size, SgenAllocFlags flags, const char *assert_description, MonoMemAccountType type) { void *ptr; g_assert (!(flags & ~(SGEN_ALLOC_HEAP | SGEN_ALLOC_ACTIVATE))); - ptr = mono_valloc (0, size, prot_flags_for_activate (flags & SGEN_ALLOC_ACTIVATE)); + ptr = mono_valloc (0, size, prot_flags_for_activate (flags & SGEN_ALLOC_ACTIVATE), type); sgen_assert_memory_alloc (ptr, size, assert_description); if (ptr) { SGEN_ATOMIC_ADD_P (total_alloc, size); @@ -270,14 +400,15 @@ sgen_alloc_os_memory (size_t size, SgenAllocFlags flags, const char *assert_desc } /* size must be a power of 2 */ +// FIXME: remove assert_description void* -sgen_alloc_os_memory_aligned (size_t size, mword alignment, SgenAllocFlags flags, const char *assert_description) +sgen_alloc_os_memory_aligned (size_t size, mword alignment, SgenAllocFlags flags, const char *assert_description, MonoMemAccountType type) { void *ptr; g_assert (!(flags & ~(SGEN_ALLOC_HEAP | SGEN_ALLOC_ACTIVATE))); - ptr = mono_valloc_aligned (size, alignment, prot_flags_for_activate (flags & SGEN_ALLOC_ACTIVATE)); + ptr = mono_valloc_aligned (size, alignment, prot_flags_for_activate (flags & SGEN_ALLOC_ACTIVATE), type); sgen_assert_memory_alloc (ptr, size, assert_description); if (ptr) { SGEN_ATOMIC_ADD_P (total_alloc, size); @@ -290,11 +421,11 @@ sgen_alloc_os_memory_aligned (size_t size, mword alignment, SgenAllocFlags flags * Free the memory returned by sgen_alloc_os_memory (), returning it to the OS. */ void -sgen_free_os_memory (void *addr, size_t size, SgenAllocFlags flags) +sgen_free_os_memory (void *addr, size_t size, SgenAllocFlags flags, MonoMemAccountType type) { g_assert (!(flags & ~SGEN_ALLOC_HEAP)); - mono_vfree (addr, size); + mono_vfree (addr, size, type); SGEN_ATOMIC_ADD_P (total_alloc, -(gssize)size); total_alloc_max = MAX (total_alloc_max, total_alloc); } @@ -328,7 +459,7 @@ gboolean sgen_memgov_try_alloc_space (mword size, int space) { if (sgen_memgov_available_free_space () < size) { - SGEN_ASSERT (4, !sgen_thread_pool_is_thread_pool_thread (mono_native_thread_id_get ()), "Memory shouldn't run out in worker thread"); + SGEN_ASSERT (4, !sgen_workers_is_worker_thread (mono_native_thread_id_get ()), "Memory shouldn't run out in worker thread"); return FALSE; } @@ -346,8 +477,12 @@ sgen_memgov_init (size_t max_heap, size_t soft_limit, gboolean debug_allowance, debug_print_allowance = debug_allowance; major_collection_trigger_size = MIN_MINOR_COLLECTION_ALLOWANCE; - mono_counters_register ("Memgov alloc", MONO_COUNTER_GC | MONO_COUNTER_WORD | MONO_COUNTER_BYTES | MONO_COUNTER_VARIABLE, &total_alloc); - mono_counters_register ("Memgov max alloc", MONO_COUNTER_GC | MONO_COUNTER_WORD | MONO_COUNTER_BYTES | MONO_COUNTER_MONOTONIC, &total_alloc_max); + mono_counters_register ("Memgov alloc", MONO_COUNTER_GC | MONO_COUNTER_WORD | MONO_COUNTER_BYTES | MONO_COUNTER_VARIABLE, (void*)&total_alloc); + mono_counters_register ("Memgov max alloc", MONO_COUNTER_GC | MONO_COUNTER_WORD | MONO_COUNTER_BYTES | MONO_COUNTER_MONOTONIC, (void*)&total_alloc_max); + + mono_os_mutex_init (&log_entries_mutex); + + sgen_register_fixed_internal_mem_type (INTERNAL_MEM_LOG_ENTRY, sizeof (SgenLogEntry)); if (max_heap == 0) return; @@ -357,11 +492,11 @@ sgen_memgov_init (size_t max_heap, size_t soft_limit, gboolean debug_allowance, max_heap = soft_limit; } - if (max_heap < sgen_nursery_size * 4) { + if (max_heap < SGEN_DEFAULT_NURSERY_SIZE * 4) { sgen_env_var_error (MONO_GC_PARAMS_NAME, "Setting to minimum.", "`max-heap-size` must be at least 4 times as large as `nursery size`."); - max_heap = sgen_nursery_size * 4; + max_heap = SGEN_DEFAULT_NURSERY_SIZE * 4; } - max_heap_size = max_heap - sgen_nursery_size; + max_heap_size = max_heap - SGEN_DEFAULT_NURSERY_SIZE; if (allowance_ratio) default_allowance_nursery_size_ratio = allowance_ratio;