1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/services/mallocSiteTable.cpp Wed Aug 27 08:19:12 2014 -0400 1.3 @@ -0,0 +1,261 @@ 1.4 +/* 1.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 +#include "precompiled.hpp" 1.28 + 1.29 + 1.30 +#include "memory/allocation.inline.hpp" 1.31 +#include "runtime/atomic.hpp" 1.32 +#include "services/mallocSiteTable.hpp" 1.33 + 1.34 +/* 1.35 + * Early os::malloc() calls come from initializations of static variables, long before entering any 1.36 + * VM code. Upon the arrival of the first os::malloc() call, malloc site hashtable has to be 1.37 + * initialized, along with the allocation site for the hashtable entries. 1.38 + * To ensure that malloc site hashtable can be initialized without triggering any additional os::malloc() 1.39 + * call, the hashtable bucket array and hashtable entry allocation site have to be static. 1.40 + * It is not a problem for hashtable bucket, since it is an array of pointer type, C runtime just 1.41 + * allocates a block memory and zero the memory for it. 1.42 + * But for hashtable entry allocation site object, things get tricky. C runtime not only allocates 1.43 + * memory for it, but also calls its constructor at some later time. If we initialize the allocation site 1.44 + * at the first os::malloc() call, the object will be reinitialized when its constructor is called 1.45 + * by C runtime. 1.46 + * To workaround above issue, we declare a static size_t array with the size of the CallsiteHashtableEntry, 1.47 + * the memory is used to instantiate CallsiteHashtableEntry for the hashtable entry allocation site. 1.48 + * Given it is a primitive type array, C runtime will do nothing other than assign the memory block for the variable, 1.49 + * which is exactly what we want. 1.50 + * The same trick is also applied to create NativeCallStack object for CallsiteHashtableEntry memory allocation. 1.51 + * 1.52 + * Note: C++ object usually aligns to particular alignment, depends on compiler implementation, we declare 1.53 + * the memory as size_t arrays, to ensure the memory is aligned to native machine word alignment. 1.54 + */ 1.55 + 1.56 +// Reserve enough memory for NativeCallStack and MallocSiteHashtableEntry objects 1.57 +size_t MallocSiteTable::_hash_entry_allocation_stack[CALC_OBJ_SIZE_IN_TYPE(NativeCallStack, size_t)]; 1.58 +size_t MallocSiteTable::_hash_entry_allocation_site[CALC_OBJ_SIZE_IN_TYPE(MallocSiteHashtableEntry, size_t)]; 1.59 + 1.60 +// Malloc site hashtable buckets 1.61 +MallocSiteHashtableEntry* MallocSiteTable::_table[MallocSiteTable::table_size]; 1.62 + 1.63 +// concurrent access counter 1.64 +volatile int MallocSiteTable::_access_count = 0; 1.65 + 1.66 +// Tracking hashtable contention 1.67 +NOT_PRODUCT(int MallocSiteTable::_peak_count = 0;) 1.68 + 1.69 + 1.70 +/* 1.71 + * Initialize malloc site table. 1.72 + * Hashtable entry is malloc'd, so it can cause infinite recursion. 1.73 + * To avoid above problem, we pre-initialize a hash entry for 1.74 + * this allocation site. 1.75 + * The method is called during C runtime static variable initialization 1.76 + * time, it is in single-threaded mode from JVM perspective. 1.77 + */ 1.78 +bool MallocSiteTable::initialize() { 1.79 + assert(sizeof(_hash_entry_allocation_stack) >= sizeof(NativeCallStack), "Sanity Check"); 1.80 + assert(sizeof(_hash_entry_allocation_site) >= sizeof(MallocSiteHashtableEntry), 1.81 + "Sanity Check"); 1.82 + assert((size_t)table_size <= MAX_MALLOCSITE_TABLE_SIZE, "Hashtable overflow"); 1.83 + 1.84 + // Fake the call stack for hashtable entry allocation 1.85 + assert(NMT_TrackingStackDepth > 1, "At least one tracking stack"); 1.86 + 1.87 + // Create pseudo call stack for hashtable entry allocation 1.88 + address pc[3]; 1.89 + if (NMT_TrackingStackDepth >= 3) { 1.90 + pc[2] = (address)MallocSiteTable::allocation_at; 1.91 + } 1.92 + if (NMT_TrackingStackDepth >= 2) { 1.93 + pc[1] = (address)MallocSiteTable::lookup_or_add; 1.94 + } 1.95 + pc[0] = (address)MallocSiteTable::new_entry; 1.96 + 1.97 + // Instantiate NativeCallStack object, have to use placement new operator. (see comments above) 1.98 + NativeCallStack* stack = ::new ((void*)_hash_entry_allocation_stack) 1.99 + NativeCallStack(pc, MIN2(((int)(sizeof(pc) / sizeof(address))), ((int)NMT_TrackingStackDepth))); 1.100 + 1.101 + // Instantiate hash entry for hashtable entry allocation callsite 1.102 + MallocSiteHashtableEntry* entry = ::new ((void*)_hash_entry_allocation_site) 1.103 + MallocSiteHashtableEntry(*stack); 1.104 + 1.105 + // Add the allocation site to hashtable. 1.106 + int index = hash_to_index(stack->hash()); 1.107 + _table[index] = entry; 1.108 + 1.109 + return true; 1.110 +} 1.111 + 1.112 +// Walks entries in the hashtable. 1.113 +// It stops walk if the walker returns false. 1.114 +bool MallocSiteTable::walk(MallocSiteWalker* walker) { 1.115 + MallocSiteHashtableEntry* head; 1.116 + for (int index = 0; index < table_size; index ++) { 1.117 + head = _table[index]; 1.118 + while (head != NULL) { 1.119 + if (!walker->do_malloc_site(head->peek())) { 1.120 + return false; 1.121 + } 1.122 + head = (MallocSiteHashtableEntry*)head->next(); 1.123 + } 1.124 + } 1.125 + return true; 1.126 +} 1.127 + 1.128 +/* 1.129 + * The hashtable does not have deletion policy on individual entry, 1.130 + * and each linked list node is inserted via compare-and-swap, 1.131 + * so each linked list is stable, the contention only happens 1.132 + * at the end of linked list. 1.133 + * This method should not return NULL under normal circumstance. 1.134 + * If NULL is returned, it indicates: 1.135 + * 1. Out of memory, it cannot allocate new hash entry. 1.136 + * 2. Overflow hash bucket. 1.137 + * Under any of above circumstances, caller should handle the situation. 1.138 + */ 1.139 +MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, size_t* bucket_idx, 1.140 + size_t* pos_idx) { 1.141 + int index = hash_to_index(key.hash()); 1.142 + assert(index >= 0, "Negative index"); 1.143 + *bucket_idx = (size_t)index; 1.144 + *pos_idx = 0; 1.145 + 1.146 + // First entry for this hash bucket 1.147 + if (_table[index] == NULL) { 1.148 + MallocSiteHashtableEntry* entry = new_entry(key); 1.149 + // OOM check 1.150 + if (entry == NULL) return NULL; 1.151 + 1.152 + // swap in the head 1.153 + if (Atomic::cmpxchg_ptr((void*)entry, (volatile void *)&_table[index], NULL) == NULL) { 1.154 + return entry->data(); 1.155 + } 1.156 + 1.157 + delete entry; 1.158 + } 1.159 + 1.160 + MallocSiteHashtableEntry* head = _table[index]; 1.161 + while (head != NULL && (*pos_idx) <= MAX_BUCKET_LENGTH) { 1.162 + MallocSite* site = head->data(); 1.163 + if (site->equals(key)) { 1.164 + // found matched entry 1.165 + return head->data(); 1.166 + } 1.167 + 1.168 + if (head->next() == NULL && (*pos_idx) < MAX_BUCKET_LENGTH) { 1.169 + MallocSiteHashtableEntry* entry = new_entry(key); 1.170 + // OOM check 1.171 + if (entry == NULL) return NULL; 1.172 + if (head->atomic_insert(entry)) { 1.173 + (*pos_idx) ++; 1.174 + return entry->data(); 1.175 + } 1.176 + // contended, other thread won 1.177 + delete entry; 1.178 + } 1.179 + head = (MallocSiteHashtableEntry*)head->next(); 1.180 + (*pos_idx) ++; 1.181 + } 1.182 + return NULL; 1.183 +} 1.184 + 1.185 +// Access malloc site 1.186 +MallocSite* MallocSiteTable::malloc_site(size_t bucket_idx, size_t pos_idx) { 1.187 + assert(bucket_idx < table_size, "Invalid bucket index"); 1.188 + MallocSiteHashtableEntry* head = _table[bucket_idx]; 1.189 + for (size_t index = 0; index < pos_idx && head != NULL; 1.190 + index ++, head = (MallocSiteHashtableEntry*)head->next()); 1.191 + assert(head != NULL, "Invalid position index"); 1.192 + return head->data(); 1.193 +} 1.194 + 1.195 +// Allocates MallocSiteHashtableEntry object. Special call stack 1.196 +// (pre-installed allocation site) has to be used to avoid infinite 1.197 +// recursion. 1.198 +MallocSiteHashtableEntry* MallocSiteTable::new_entry(const NativeCallStack& key) { 1.199 + void* p = AllocateHeap(sizeof(MallocSiteHashtableEntry), mtNMT, 1.200 + *hash_entry_allocation_stack(), AllocFailStrategy::RETURN_NULL); 1.201 + return ::new (p) MallocSiteHashtableEntry(key); 1.202 +} 1.203 + 1.204 +void MallocSiteTable::reset() { 1.205 + for (int index = 0; index < table_size; index ++) { 1.206 + MallocSiteHashtableEntry* head = _table[index]; 1.207 + _table[index] = NULL; 1.208 + delete_linked_list(head); 1.209 + } 1.210 +} 1.211 + 1.212 +void MallocSiteTable::delete_linked_list(MallocSiteHashtableEntry* head) { 1.213 + MallocSiteHashtableEntry* p; 1.214 + while (head != NULL) { 1.215 + p = head; 1.216 + head = (MallocSiteHashtableEntry*)head->next(); 1.217 + if (p != (MallocSiteHashtableEntry*)_hash_entry_allocation_site) { 1.218 + delete p; 1.219 + } 1.220 + } 1.221 +} 1.222 + 1.223 +void MallocSiteTable::shutdown() { 1.224 + AccessLock locker(&_access_count); 1.225 + locker.exclusiveLock(); 1.226 + reset(); 1.227 +} 1.228 + 1.229 +bool MallocSiteTable::walk_malloc_site(MallocSiteWalker* walker) { 1.230 + assert(walker != NULL, "NuLL walker"); 1.231 + AccessLock locker(&_access_count); 1.232 + if (locker.sharedLock()) { 1.233 + NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);) 1.234 + return walk(walker); 1.235 + } 1.236 + return false; 1.237 +} 1.238 + 1.239 + 1.240 +void MallocSiteTable::AccessLock::exclusiveLock() { 1.241 + jint target; 1.242 + jint val; 1.243 + 1.244 + assert(_lock_state != ExclusiveLock, "Can only call once"); 1.245 + assert(*_lock >= 0, "Can not content exclusive lock"); 1.246 + 1.247 + // make counter negative to block out shared locks 1.248 + do { 1.249 + val = *_lock; 1.250 + target = _MAGIC_ + *_lock; 1.251 + } while (Atomic::cmpxchg(target, _lock, val) != val); 1.252 + 1.253 + // wait for all readers to exit 1.254 + while (*_lock != _MAGIC_) { 1.255 +#ifdef _WINDOWS 1.256 + os::naked_short_sleep(1); 1.257 +#else 1.258 + os::NakedYield(); 1.259 +#endif 1.260 + } 1.261 + _lock_state = ExclusiveLock; 1.262 +} 1.263 + 1.264 +