Path: blob/master/runtime/jcl/common/mgmtinit.c
6000 views
/*******************************************************************************1* Copyright (c) 1998, 2020 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "jni.h"23#include "j9.h"24#include "mmhook.h"25#include "mmomrhook.h"26#include "jithook.h"27#include "j9consts.h"28#include "omrgcconsts.h"29#include "j9modron.h"30#include "jcl_internal.h"3132#include "mgmtinit.h"3334/* required for memset */35#include <string.h>3637#include "ut_j9jcl.h"3839typedef enum {40CLASS_MEMORY=0,41MISC_MEMORY,42JIT_CODECACHE,43JIT_DATACACHE44} nonHeapMemoryPoolIndex;4546static void managementClassLoadCounter(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);47#if (defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING))48static void managementClassUnloadCounter(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);49#endif50static void managementCompilingStartTime(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);51static void managementCompilingEndTime(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);52static void managementThreadStartCounter(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);53static void managementThreadEndCounter(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);5455static VMINLINE void managementGC(OMR_VMThread *omrVMThread, void *userData, BOOLEAN isEnd);56static void managementGlobalGCStart(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);57static void managementGlobalGCEnd(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);58static void managementLocalGCStart(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);59static void managementLocalGCEnd(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);6061static void managementCompactEnd(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData);62static void gcStartEvent(J9JavaVM *vm, UDATA heapSize, UDATA heapUsed, UDATA *totals, UDATA *frees, UDATA collectorID);63static void gcEndEvent(J9JavaVM *vm, UDATA heapSize, UDATA heapUsed, UDATA *totals, UDATA *frees, UDATA *maxs, UDATA collectorID, OMR_VMThread *omrVMThread);64static jint initMemoryManagement(J9JavaVM *vm);65static U_32 getNumberSupported(U_32 supportedIDs);66static UDATA getArrayIndexFromManagerID(J9JavaLangManagementData *mgmt, UDATA id);67static void getSegmentSizes(J9JavaVM *javaVM, J9MemorySegmentList *segList, U_64 *storedSize, U_64 *storedUsed, U_64 *storedPeakSize, U_64 *storedPeakUsed, BOOLEAN isCodeCacheSegment);68static void updateNonHeapMemoryPoolSizes(J9JavaVM *vm, J9JavaLangManagementData *mgmt, BOOLEAN isGCEnd);6970/* initialize java.lang.management data structures and hooks */71jint72managementInit(J9JavaVM *vm)73{74J9HookInterface **vmHooks = NULL;75J9HookInterface **omrGCHooks = NULL;76J9VMThread *walkThread = NULL;77J9JavaLangManagementData *mgmt = NULL;78J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions;79#if defined (J9VM_INTERP_NATIVE_SUPPORT)80J9HookInterface **jitHooks = NULL;81#endif82omrthread_t self = omrthread_self();83PORT_ACCESS_FROM_JAVAVM(vm);8485/* allocate management data struct */86vm->managementData = j9mem_allocate_memory(sizeof(J9JavaLangManagementData), J9MEM_CATEGORY_VM_JCL);87mgmt = vm->managementData;88if (NULL == mgmt) {89return JNI_ERR;90}91memset(mgmt, 0, sizeof(J9JavaLangManagementData));9293/* init monitor used to protect access to the U64 fields in the management data */94if (omrthread_rwmutex_init(&mgmt->managementDataLock, 0, "management fields lock")) {95return JNI_ERR;96}9798if (JNI_ERR == initMemoryManagement(vm)) {99return JNI_ERR;100}101102/* init monitor used to wake up the heap threshold notification thread */103if (omrthread_monitor_init(&mgmt->notificationMonitor, 0)) {104return JNI_ERR;105}106107mgmt->threadCpuTimeEnabledFlag = 1;108if (0 <= omrthread_get_cpu_time(self)) {109mgmt->isThreadCpuTimeSupported = 1;110} else {111mgmt->isThreadCpuTimeSupported = 0;112}113if (0 <= omrthread_get_self_cpu_time(self)) {114mgmt->isCurrentThreadCpuTimeSupported = 1;115} else {116mgmt->isCurrentThreadCpuTimeSupported = 0;117}118/* isThreadCpuTimeSupported and isCurrentThreadCpuTimeSupported are read-only after this point */119120mgmt->vmStartTime = j9time_current_time_millis();121122/* vm->memoryManagerFunctions will be NULL if we failed to load the gc dll */123if (NULL == mmFuncs) {124return JNI_ERR;125}126127mgmt->initialHeapSize = mmFuncs->j9gc_get_initial_heap_size(vm);128mgmt->maximumHeapSize = mmFuncs->j9gc_get_maximum_heap_size(vm);129130/* hook class load and unload */131vmHooks = vm->internalVMFunctions->getVMHookInterface(vm);132if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_INTERNAL_CLASS_LOAD, managementClassLoadCounter, OMR_GET_CALLSITE(), mgmt)) {133return JNI_ERR;134}135136#ifdef J9VM_GC_DYNAMIC_CLASS_UNLOADING137if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_CLASSES_UNLOAD, managementClassUnloadCounter, OMR_GET_CALLSITE(), mgmt)) {138return JNI_ERR;139}140#endif141142/* hook GC start/end events */143omrGCHooks = mmFuncs->j9gc_get_omr_hook_interface(vm->omrVM);144145if ((*omrGCHooks)->J9HookRegisterWithCallSite(omrGCHooks, J9HOOK_MM_OMR_GLOBAL_GC_START, managementGlobalGCStart, OMR_GET_CALLSITE(), vm)) {146return JNI_ERR;147}148if ((*omrGCHooks)->J9HookRegisterWithCallSite(omrGCHooks, J9HOOK_MM_OMR_LOCAL_GC_START, managementLocalGCStart, OMR_GET_CALLSITE(), vm)) {149return JNI_ERR;150}151if ((*omrGCHooks)->J9HookRegisterWithCallSite(omrGCHooks, J9HOOK_MM_OMR_GLOBAL_GC_END, managementGlobalGCEnd, OMR_GET_CALLSITE(), vm)) {152return JNI_ERR;153}154if ((*omrGCHooks)->J9HookRegisterWithCallSite(omrGCHooks, J9HOOK_MM_OMR_LOCAL_GC_END, managementLocalGCEnd, OMR_GET_CALLSITE(), vm)) {155return JNI_ERR;156}157if ((*omrGCHooks)->J9HookRegisterWithCallSite(omrGCHooks, J9HOOK_MM_OMR_COMPACT_END, managementCompactEnd, OMR_GET_CALLSITE(), vm)) {158return JNI_ERR;159}160161/* lock the thread list */162omrthread_monitor_enter(vm->vmThreadListMutex);163164/* count existing threads */165walkThread = vm->mainThread;166do {167mgmt->liveJavaThreads++;168if (walkThread->privateFlags & J9_PRIVATE_FLAGS_DAEMON_THREAD) {169mgmt->liveJavaDaemonThreads++;170}171} while((walkThread = walkThread->linkNext) != vm->mainThread);172173mgmt->totalJavaThreadsStarted = mgmt->liveJavaThreads;174mgmt->peakLiveJavaThreads = mgmt->liveJavaThreads;175176/* hook thread create and destroy while holding the thread list mutex, so our initial counts stay correct */177if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_THREAD_CREATED, managementThreadStartCounter, OMR_GET_CALLSITE(), mgmt)) {178omrthread_monitor_exit(vm->vmThreadListMutex);179return JNI_ERR;180}181if ((*vmHooks)->J9HookRegisterWithCallSite(vmHooks, J9HOOK_VM_THREAD_DESTROY, managementThreadEndCounter, OMR_GET_CALLSITE(), mgmt)) {182omrthread_monitor_exit(vm->vmThreadListMutex);183return JNI_ERR;184}185186omrthread_monitor_exit(vm->vmThreadListMutex);187188#if defined (J9VM_INTERP_NATIVE_SUPPORT)189/* hook jit compile start/end events */190jitHooks = vm->internalVMFunctions->getJITHookInterface(vm);191if (jitHooks) {192if ((*jitHooks)->J9HookRegisterWithCallSite(jitHooks, J9HOOK_JIT_COMPILING_START, managementCompilingStartTime, OMR_GET_CALLSITE(), mgmt)) {193return JNI_ERR;194}195if ((*jitHooks)->J9HookRegisterWithCallSite(jitHooks, J9HOOK_JIT_COMPILING_END, managementCompilingEndTime, OMR_GET_CALLSITE(), mgmt)) {196return JNI_ERR;197}198}199#endif200201/* Initialization for OperatingSystemNotificationThread (mgmtos.c)202* OperatingSystemNotificationThread must be a singleton class.203*/204if (J9THREAD_SUCCESS != omrthread_monitor_init(&mgmt->dlparNotificationMonitor, 0)) {205mgmt->dlparNotificationMonitor = NULL;206}207mgmt->dlparNotificationQueue = NULL;208mgmt->dlparNotificationsPending = 0;209mgmt->isCounterPathInitialized = 0;210return 0;211}212213static void214managementClassLoadCounter(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)215{216J9JavaLangManagementData *mgmt = userData;217218omrthread_rwmutex_enter_write(mgmt->managementDataLock);219220mgmt->totalClassLoads++;221222omrthread_rwmutex_exit_write(mgmt->managementDataLock);223}224225226#if (defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING))227228static void229managementClassUnloadCounter(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)230{231J9VMClassesUnloadEvent *data = eventData;232J9JavaLangManagementData *mgmt = userData;233234omrthread_rwmutex_enter_write(mgmt->managementDataLock);235mgmt->totalClassUnloads += data->classUnloadCount;236omrthread_rwmutex_exit_write(mgmt->managementDataLock);237}238#endif239240241static void242managementCompilingStartTime(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)243{244J9CompilingStartEvent *event = eventData;245J9JavaVM *vm = event->currentThread->javaVM;246PORT_ACCESS_FROM_JAVAVM(vm);247J9JavaLangManagementData *mgmt = userData;248I_64 now;249250omrthread_rwmutex_enter_write(mgmt->managementDataLock);251252now = j9time_nano_time();253if (0 < mgmt->threadsCompiling) {254mgmt->totalCompilationTime += checkedTimeInterval((U_64)now, (U_64)mgmt->lastCompilationStart) * mgmt->threadsCompiling;255}256257mgmt->lastCompilationStart = now;258mgmt->threadsCompiling++;259260omrthread_rwmutex_exit_write(mgmt->managementDataLock);261}262static void263managementCompilingEndTime(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)264{265J9CompilingEndEvent *event = eventData;266J9JavaVM* vm = event->currentThread->javaVM;267PORT_ACCESS_FROM_JAVAVM(vm);268J9JavaLangManagementData *mgmt = userData;269270omrthread_rwmutex_enter_write(mgmt->managementDataLock);271272mgmt->totalCompilationTime += checkedTimeInterval((U_64)j9time_nano_time(), (U_64)mgmt->lastCompilationStart);273mgmt->threadsCompiling--;274275omrthread_rwmutex_exit_write(mgmt->managementDataLock);276}277/* tear down java.lang.management data structures and hooks */278void279managementTerminate(J9JavaVM *vm)280{281J9HookInterface **vmHooks = NULL;282J9HookInterface **omrGCHooks = NULL;283J9JavaLangManagementData *mgmt = vm->managementData;284J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions;285#if defined (J9VM_INTERP_NATIVE_SUPPORT)286J9HookInterface **jitHooks;287#endif288PORT_ACCESS_FROM_JAVAVM(vm);289290if (NULL == mgmt) {291/* managementInit was never called, we have nothing to clean up */292return;293}294295/* unhook class load and unload */296vmHooks = vm->internalVMFunctions->getVMHookInterface(vm);297(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_INTERNAL_CLASS_LOAD, managementClassLoadCounter, mgmt);298299#ifdef J9VM_GC_DYNAMIC_CLASS_UNLOADING300(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_CLASSES_UNLOAD, managementClassUnloadCounter, mgmt);301#endif302303304/* vm->memoryManagerFunctions will be NULL if we failed to load the gc dll */305if (NULL != mmFuncs) {306/* unhook GC start/end */307omrGCHooks = mmFuncs->j9gc_get_omr_hook_interface(vm->omrVM);308309(*omrGCHooks)->J9HookUnregister(omrGCHooks, J9HOOK_MM_OMR_GLOBAL_GC_START, managementGlobalGCStart, vm);310(*omrGCHooks)->J9HookUnregister(omrGCHooks, J9HOOK_MM_OMR_GLOBAL_GC_END, managementGlobalGCEnd, vm);311(*omrGCHooks)->J9HookUnregister(omrGCHooks, J9HOOK_MM_OMR_LOCAL_GC_START, managementLocalGCStart, vm);312(*omrGCHooks)->J9HookUnregister(omrGCHooks, J9HOOK_MM_OMR_LOCAL_GC_END, managementLocalGCEnd, vm);313(*omrGCHooks)->J9HookUnregister(omrGCHooks, J9HOOK_MM_OMR_COMPACT_END, managementCompactEnd, vm);314}315316/* unhook thread start and end */317(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_THREAD_CREATED, managementThreadStartCounter, mgmt);318(*vmHooks)->J9HookUnregister(vmHooks, J9HOOK_VM_THREAD_DESTROY, managementThreadEndCounter, mgmt);319320#if defined (J9VM_INTERP_NATIVE_SUPPORT)321/* unhook jit compile start/end events */322jitHooks = vm->internalVMFunctions->getJITHookInterface(vm);323if (jitHooks) {324(*jitHooks)->J9HookUnregister(jitHooks, J9HOOK_JIT_COMPILING_START, managementCompilingStartTime, mgmt);325(*jitHooks)->J9HookUnregister(jitHooks, J9HOOK_JIT_COMPILING_END, managementCompilingEndTime, mgmt);326}327#endif328329/* destroy monitor */330omrthread_rwmutex_destroy(mgmt->managementDataLock);331332omrthread_monitor_destroy(mgmt->notificationMonitor);333334/* Cleanup for OperatingSystemNotificationThread (mgmtos.c) */335if (NULL != mgmt->dlparNotificationMonitor) {336omrthread_monitor_destroy(mgmt->dlparNotificationMonitor);337}338339/* deallocate management data struct */340j9mem_free_memory(mgmt->memoryPools);341j9mem_free_memory(mgmt->garbageCollectors);342j9mem_free_memory(mgmt->nonHeapMemoryPools);343j9mem_free_memory(vm->managementData);344}345346static void347managementThreadStartCounter(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)348{349J9JavaLangManagementData *mgmt = userData;350J9VMThreadCreatedEvent *event = (J9VMThreadCreatedEvent *)eventData;351J9VMThread *vmThread = event->vmThread;352353if (NULL != vmThread) {354omrthread_rwmutex_enter_write(mgmt->managementDataLock);355356mgmt->totalJavaThreadsStarted++;357mgmt->liveJavaThreads++;358if (mgmt->liveJavaThreads > mgmt->peakLiveJavaThreads) {359mgmt->peakLiveJavaThreads = mgmt->liveJavaThreads;360}361if (J9_PRIVATE_FLAGS_DAEMON_THREAD & vmThread->privateFlags) {362mgmt->liveJavaDaemonThreads++;363}364365omrthread_rwmutex_exit_write(mgmt->managementDataLock);366}367}368static void369managementThreadEndCounter(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)370{371J9JavaLangManagementData *mgmt = userData;372J9VMThreadDestroyEvent *event = (J9VMThreadDestroyEvent *)eventData;373J9VMThread *vmThread = event->vmThread;374375if (NULL != vmThread) {376omrthread_rwmutex_enter_write(mgmt->managementDataLock);377378mgmt->liveJavaThreads--;379if (J9_PRIVATE_FLAGS_DAEMON_THREAD & vmThread->privateFlags) {380mgmt->liveJavaDaemonThreads--;381}382383omrthread_rwmutex_exit_write(mgmt->managementDataLock);384}385}386387static void388managementGC(OMR_VMThread *omrVMThread, void *userData, BOOLEAN isEnd)389{390J9JavaVM *vm = userData;391UDATA heapSize = 0;392UDATA heapFree = 0;393UDATA heapUsed = 0;394UDATA totals[J9VM_MAX_HEAP_MEMORYPOOL_COUNT];395UDATA frees[J9VM_MAX_HEAP_MEMORYPOOL_COUNT];396UDATA maxs[J9VM_MAX_HEAP_MEMORYPOOL_COUNT];397UDATA collectorID = 0;398J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions;399U_32 supportedMemoryPoolIDs = 0;400U_32 id = 0;401U_32 mask = 0;402UDATA idx = 0;403UDATA count = 0;404405collectorID = mmFuncs->j9gc_get_collector_id(omrVMThread);406407if (0 == collectorID) {408/* only record data for "stop the world" collector */409return;410}411412heapSize = mmFuncs->j9gc_heap_total_memory(vm);413heapFree = mmFuncs->j9gc_heap_free_memory(vm);414heapUsed = heapSize - heapFree;415416mmFuncs->j9gc_pools_memory(vm, 0, &totals[0], &frees[0], isEnd);417if (isEnd) {418supportedMemoryPoolIDs = (U_32)mmFuncs->j9gc_allsupported_memorypools(vm);419for (count = 0, mask = 1, idx = 0; count < J9_GC_MANAGEMENT_MAX_POOL; ++count, mask <<= 1) {420id = (supportedMemoryPoolIDs & mask);421if (0 != id) {422maxs[idx] = mmFuncs->j9gc_pool_maxmemory(vm, id);423idx += 1;424}425}426gcEndEvent(vm, heapSize, heapUsed, &totals[0], &frees[0], &maxs[0], collectorID, omrVMThread);427} else {428gcStartEvent(vm, heapSize, heapUsed, &totals[0], &frees[0], collectorID);429}430}431432433static void434managementGlobalGCStart(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)435{436MM_GlobalGCStartEvent *event = (MM_GlobalGCStartEvent *)eventData;437managementGC(event->currentThread, userData, FALSE);438}439static void managementGlobalGCEnd(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)440{441MM_GlobalGCEndEvent *event = (MM_GlobalGCEndEvent *)eventData;442managementGC(event->currentThread, userData, TRUE);443}444static void managementLocalGCStart(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)445{446MM_LocalGCStartEvent *event = (MM_LocalGCStartEvent*)eventData;447managementGC(event->currentThread, userData, FALSE);448}449static void managementLocalGCEnd(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)450{451MM_LocalGCEndEvent *event = (MM_LocalGCEndEvent*)eventData;452managementGC(event->currentThread, userData, TRUE);453}454455static void456managementCompactEnd(J9HookInterface **hook, UDATA eventNum, void *eventData, void *userData)457{458J9JavaVM *vm = userData;459J9JavaLangManagementData *mgmt = vm->managementData;460UDATA idx = 0;461462omrthread_rwmutex_enter_write(mgmt->managementDataLock);463464for (idx = 0; idx < (UDATA)mgmt->supportedCollectors; ++idx) {465if (0 == (mgmt->garbageCollectors[idx].id & J9VM_MANAGEMENT_GC_LOCAL)) {466mgmt->garbageCollectors[idx].totalCompacts += 1;467break;468}469}470471omrthread_rwmutex_exit_write(mgmt->managementDataLock);472}473474/* Updates java.lang.management data for the start of a GC. */475static void476gcStartEvent(J9JavaVM *vm, UDATA heapSize, UDATA heapUsed, UDATA *totals, UDATA *frees, UDATA collectorID)477{478J9JavaLangManagementData *mgmt = vm->managementData;479J9GarbageCollectorData *gcData = &mgmt->garbageCollectors[getArrayIndexFromManagerID(mgmt, collectorID)];480J9MemoryPoolData *memoryPools = mgmt->memoryPools;481J9MemoryNotification *notification = NULL;482J9MemoryNotification *last = NULL;483J9GarbageCollectionInfo* gcInfo = NULL;484485UDATA total = 0;486UDATA used = 0;487UDATA idx = 0;488489PORT_ACCESS_FROM_JAVAVM(vm);490/* lock the management struct */491omrthread_rwmutex_enter_write(mgmt->managementDataLock);492493/* check the wall clock */494/* the start time in milliseconds since the Java virtual machine was started */495gcInfo = &gcData->lastGcInfo;496gcInfo->startTime = j9time_current_time_millis();497if (gcInfo->startTime < (U_64)mgmt->vmStartTime) {498/* startTime is earlier than vmStartTime in case of wall clock correction while interval is measuring */499gcInfo->startTime = 0;500} else {501gcInfo->startTime -= mgmt->vmStartTime;502}503504mgmt->preCollectionHeapSize = heapSize;505mgmt->preCollectionHeapUsed = heapUsed;506507for (idx = 0; idx < mgmt->supportedMemoryPools; ++idx) {508J9MemoryPoolData *memoryPool = &memoryPools[idx];509total = totals[idx];510used = totals[idx] - frees[idx];511512/* update pre Memory Usage of last GcInfo for the collector */513gcInfo->preUsed[idx] = used;514gcInfo->preCommitted[idx] = total;515516gcInfo->preMax[idx] = 0;517if (0 != mgmt->lastGCID) {518J9GarbageCollectorData *lastGcData = &mgmt->garbageCollectors[getArrayIndexFromManagerID(mgmt, mgmt->lastGCID)];519J9GarbageCollectionInfo* lastGcInfo = &lastGcData->lastGcInfo;520gcInfo->preMax[idx] = lastGcInfo->postMax[idx];521}522if (0 == gcInfo->preMax[idx]) {523gcInfo->preMax[idx] = memoryPool->postCollectionMaxSize;524}525526/* check the peak usage and update */527if (memoryPool->peakUsed < used) {528memoryPool->peakUsed = used;529memoryPool->peakSize = total;530memoryPool->peakMax = gcInfo->preMax[idx];531}532533/* if a heap usage threshold is set, check whether we are above or below */534if (0 < memoryPool->usageThreshold) {535if (memoryPool->usageThreshold < used) {536/* usage above threshold now, was it below threshold last time? */537if (0 == (memoryPool->notificationState & THRESHOLD_EXCEEDED)) {538539/* if so, generate a notification and set the flag */540memoryPool->notificationState |= THRESHOLD_EXCEEDED;541memoryPool->usageThresholdCrossedCount++;542543/* if the queue is full, silently discard this notification */544if (NOTIFICATION_QUEUE_MAX > mgmt->notificationsPending) {545notification = j9mem_allocate_memory(sizeof(*notification), J9MEM_CATEGORY_VM_JCL);546if (NULL != notification) {547notification->gcInfo = NULL;548notification->usageThreshold = j9mem_allocate_memory(sizeof(*notification->usageThreshold), J9MEM_CATEGORY_VM_JCL);549if (NULL == notification->usageThreshold) {550j9mem_free_memory(notification);551notification = NULL;552}553}554/* in case of allocation failure, silently discard the notification */555if (NULL != notification) {556/* populate the notification data */557notification->type = THRESHOLD_EXCEEDED;558notification->next = NULL;559notification->usageThreshold->poolID = memoryPool->id;560notification->usageThreshold->usedSize = used;561notification->usageThreshold->totalSize = total;562notification->usageThreshold->maxSize = gcInfo->preMax[idx];563notification->usageThreshold->thresholdCrossingCount = memoryPool->usageThresholdCrossedCount;564notification->sequenceNumber = mgmt->notificationCount++;565566/* notify the thread that dispatches notifications to Java handlers */567omrthread_monitor_enter(mgmt->notificationMonitor);568569/* find the end of the queue and count the entries */570last = mgmt->notificationQueue;571while ((last != NULL) && (last->next != NULL)) {572last = last->next;573}574/* add to queue */575if (NULL == last) {576mgmt->notificationQueue = notification;577last = notification;578} else {579last->next = notification;580}581mgmt->notificationsPending += 1;582583omrthread_monitor_notify(mgmt->notificationMonitor);584omrthread_monitor_exit(mgmt->notificationMonitor);585}586}587}588} else {589/* usage below threshold now, was it above threshold last time? */590if (0 != (memoryPool->notificationState & THRESHOLD_EXCEEDED)) {591/* if so, clear the flag */592memoryPool->notificationState &= ~THRESHOLD_EXCEEDED;593}594}595}596}597598omrthread_rwmutex_exit_write(mgmt->managementDataLock);599600/* update nonHeap memory pools for preCollection */601updateNonHeapMemoryPoolSizes(vm, mgmt, FALSE);602}603604/* Updates java.lang.management data for the end of a GC. */605static void606gcEndEvent(J9JavaVM *vm, UDATA heapSize, UDATA heapUsed, UDATA *totals, UDATA *frees, UDATA *maxs, UDATA collectorID, OMR_VMThread *omrVMThread)607{608J9JavaLangManagementData *mgmt = vm->managementData;609J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions;610J9GarbageCollectorData *gcData = &mgmt->garbageCollectors[getArrayIndexFromManagerID(mgmt, collectorID)];611J9MemoryPoolData *memoryPools = mgmt->memoryPools;612J9MemoryNotification *notification = NULL;613J9MemoryNotification *last = NULL;614615UDATA total = 0;616UDATA used = 0;617UDATA max = 0;618UDATA idx = 0;619U_32 notificationEnabled = 0;620621UDATA supportedMemoryPools = mgmt->supportedMemoryPools;622UDATA supportedNonHeapMemoryPools = mgmt->supportedNonHeapMemoryPools;623J9GarbageCollectionInfo* gcInfo = NULL;624625PORT_ACCESS_FROM_JAVAVM(vm);626627/* lock the management struct */628omrthread_rwmutex_enter_write(mgmt->managementDataLock);629630mgmt->lastGCID = (U_32)collectorID;631mgmt->postCollectionHeapSize = heapSize;632mgmt->postCollectionHeapUsed = heapUsed;633gcInfo = &gcData->lastGcInfo;634635for (idx = 0; idx < mgmt->supportedMemoryPools; ++idx) {636J9MemoryPoolData *memoryPool = &memoryPools[idx];637total = totals[idx];638used = totals[idx] - frees[idx];639max = maxs[idx];640641/* update post Memory Usage of last GcInfo for the collector */642gcInfo->postUsed[idx] = used;643gcInfo->postCommitted[idx] = total;644gcInfo->postMax[idx] = max;645646/* check the peak usage and update */647if (memoryPool->peakUsed < used) {648memoryPool->peakUsed = used;649memoryPool->peakSize = total;650memoryPool->peakMax = max;651}652653/* if a memory pool collection threshold is set and the memory pool is managed by the collector, check whether we are above or below */654if ((0 < memoryPool->collectionUsageThreshold) && mmFuncs->j9gc_is_managedpool_by_collector(vm, (UDATA)(gcData->id & J9VM_MANAGEMENT_GC_HEAP_ID_MASK), (UDATA)(memoryPool->id & J9VM_MANAGEMENT_POOL_HEAP_ID_MASK))) {655if (memoryPool->collectionUsageThreshold < used) {656/* usage above threshold now, was it below threshold last time? */657if (0 == (memoryPool->notificationState & COLLECTION_THRESHOLD_EXCEEDED)) {658659/* if so, generate a notification and set the flag */660memoryPool->notificationState |= COLLECTION_THRESHOLD_EXCEEDED;661memoryPool->collectionUsageThresholdCrossedCount++;662663/* if the queue is full, silently discard this notification */664if (NOTIFICATION_QUEUE_MAX > mgmt->notificationsPending) {665notification = j9mem_allocate_memory(sizeof(*notification), J9MEM_CATEGORY_VM_JCL);666/* in case of allocation failure, silently discard the notification */667if (NULL != notification) {668notification->gcInfo = NULL;669notification->usageThreshold = j9mem_allocate_memory(sizeof(*notification->usageThreshold), J9MEM_CATEGORY_VM_JCL);670if (NULL == notification->usageThreshold) {671j9mem_free_memory(notification);672notification = NULL;673}674}675if (NULL != notification) {676/* populate the notification data */677notification->type = COLLECTION_THRESHOLD_EXCEEDED;678notification->next = NULL;679notification->usageThreshold->poolID = memoryPool->id;680notification->usageThreshold->usedSize = used;681notification->usageThreshold->totalSize = total;682notification->usageThreshold->maxSize = max;683notification->usageThreshold->thresholdCrossingCount = memoryPool->collectionUsageThresholdCrossedCount;684notification->sequenceNumber = mgmt->notificationCount++;685686/* notify the thread that dispatches notifications to Java handlers */687omrthread_monitor_enter(mgmt->notificationMonitor);688/* find the end of the queue and count the entries */689last = mgmt->notificationQueue;690/* find the end of the queue and count the entries */691while ((NULL != last) && (NULL != last->next)) {692last = last->next;693}694/* add to queue */695if (NULL == last) {696mgmt->notificationQueue = notification;697last = notification;698} else {699last->next = notification;700}701702mgmt->notificationsPending += 1;703omrthread_monitor_notify(mgmt->notificationMonitor);704omrthread_monitor_exit(mgmt->notificationMonitor);705}706}707}708} else {709/* usage below threshold now, was it above threshold last time? */710if (0 != (memoryPool->notificationState & COLLECTION_THRESHOLD_EXCEEDED)) {711/* if so, clear the flag */712memoryPool->notificationState &= ~COLLECTION_THRESHOLD_EXCEEDED;713}714}715}716}717718/* update the relevant stats */719/* the end time in milliseconds since the Java virtual machine was started */720gcData->lastGcInfo.endTime = j9time_current_time_millis();721if (gcData->lastGcInfo.endTime < (U_64)mgmt->vmStartTime) {722/* endTime is earlier than vmStartTime in case of wall clock correction while interval is measuring */723gcData->lastGcInfo.endTime = 0;724} else {725gcData->lastGcInfo.endTime -= mgmt->vmStartTime;726}727/* endTime is earlier than startTime in case of wall clock correction while interval is measuring */728if (gcData->lastGcInfo.endTime >= gcData->lastGcInfo.startTime) {729gcData->totalGCTime += (gcData->lastGcInfo.endTime - gcData->lastGcInfo.startTime);730} else {731gcData->lastGcInfo.endTime = gcData->lastGcInfo.startTime;732}733734/* collectionCount */735gcData->lastGcInfo.index += 1;736gcData->memoryUsed = 0;737738for (idx = 0; idx < mgmt->supportedMemoryPools; ++idx) {739if (0 != mmFuncs->j9gc_is_managedpool_by_collector(vm, (gcData->id & J9VM_MANAGEMENT_GC_HEAP_ID_MASK), (memoryPools[idx].id & J9VM_MANAGEMENT_POOL_HEAP_ID_MASK))) {740gcData->memoryUsed += memoryPools[idx].postCollectionUsed;741}742}743744gcData->totalMemoryFreed += (I_64)(mgmt->preCollectionHeapUsed - mgmt->postCollectionHeapUsed);745746/* update the GC CPU usage */747mmFuncs->j9gc_get_CPU_times(vm, &mgmt->gcMainCpuTime, &mgmt->gcWorkerCpuTime, &mgmt->gcMaxThreads, &mgmt->gcCurrentThreads);748749/* update nonHeap memory pools for postCollection */750updateNonHeapMemoryPoolSizes(vm, mgmt, TRUE);751/* update J9GarbageCollectionInfo for the collector */752753gcInfo->gcID = gcData->id;754gcInfo->gcAction = mmFuncs->j9gc_get_gc_action(vm, (gcInfo->gcID & J9VM_MANAGEMENT_GC_HEAP_ID_MASK));755gcInfo->gcCause = mmFuncs->j9gc_get_gc_cause(omrVMThread);756gcInfo->arraySize =(U_32) (supportedMemoryPools + supportedNonHeapMemoryPools);757/* heap memory pools */758for (idx = 0; supportedMemoryPools > idx; ++idx) {759J9MemoryPoolData *memoryPool = &memoryPools[idx];760gcInfo->initialSize[idx] = memoryPool->initialSize;761if (mmFuncs->j9gc_is_managedpool_by_collector(vm, (UDATA)(gcData->id & J9VM_MANAGEMENT_GC_HEAP_ID_MASK), (UDATA)(memoryPool->id & J9VM_MANAGEMENT_POOL_HEAP_ID_MASK))) {762/**763* the memoryPool is managed by this collection, update preCollection postCollection Memory Usage of this memory Pool764* gcInfo keep memory Usage before and after this gc765* preCollection postCollection Memory Usage in memoryPool only keep information for the GC, which recycle the memory pool766*/767memoryPool->preCollectionUsed = gcInfo->preUsed[idx];768memoryPool->preCollectionSize = gcInfo->preCommitted[idx];769memoryPool->preCollectionMaxSize = (U_64)gcInfo->preMax[idx];770memoryPool->postCollectionUsed = gcInfo->postUsed[idx];771memoryPool->postCollectionSize = gcInfo->postCommitted[idx];772memoryPool->postCollectionMaxSize = (U_64)gcInfo->postMax[idx];773}774}775/* non heap memory pools */776for (; supportedMemoryPools + supportedNonHeapMemoryPools > idx; ++idx) {777J9NonHeapMemoryData *nonHeapMemory = &mgmt->nonHeapMemoryPools[idx-supportedMemoryPools];778gcInfo->initialSize[idx] = nonHeapMemory->initialSize;779gcInfo->preUsed[idx] = nonHeapMemory->preCollectionUsed;780gcInfo->preCommitted[idx] = nonHeapMemory->preCollectionSize;781gcInfo->preMax[idx] = nonHeapMemory->maxSize;782gcInfo->postUsed[idx] = nonHeapMemory->postCollectionUsed;783gcInfo->postCommitted[idx] = nonHeapMemory->postCollectionSize;784gcInfo->postMax[idx] = nonHeapMemory->maxSize;785}786787/* garbage collection notification */788notificationEnabled = mgmt->notificationEnabled;789omrthread_rwmutex_exit_write(mgmt->managementDataLock);790791if (0 !=notificationEnabled) {792notification = j9mem_allocate_memory(sizeof(*notification), J9MEM_CATEGORY_VM_JCL);793/* in case of allocation failure, silently discard the notification */794if (NULL != notification) {795notification->usageThreshold = NULL;796notification->gcInfo = j9mem_allocate_memory(sizeof(*notification->gcInfo), J9MEM_CATEGORY_VM_JCL);797if (NULL == notification->gcInfo) {798j9mem_free_memory(notification);799notification = NULL;800}801}802if (NULL != notification) {803memcpy(notification->gcInfo, gcInfo, sizeof(*notification->gcInfo));804805notification->type = END_OF_GARBAGE_COLLECTION;806notification->next = NULL;807notification->sequenceNumber = mgmt->notificationCount++;808809/* notify the thread that dispatches notifications to Java handlers */810omrthread_monitor_enter(mgmt->notificationMonitor);811/* find the end of the queue and count the entries */812last = mgmt->notificationQueue;813/* find the end of the queue and count the entries */814while ((NULL != last) && (NULL != last->next)) {815last = last->next;816}817/* add to queue */818if (NULL == last) {819mgmt->notificationQueue = notification;820last = notification;821} else {822last->next = notification;823}824825mgmt->notificationsPending += 1;826omrthread_monitor_notify(mgmt->notificationMonitor);827omrthread_monitor_exit(mgmt->notificationMonitor);828}829}830}831832static jint833initMemoryManagement(J9JavaVM *vm)834{835J9JavaLangManagementData *mgmt = vm->managementData;836J9MemoryManagerFunctions *mmFuncs = vm->memoryManagerFunctions;837U_32 supportedMemoryPoolIDs = (U_32)mmFuncs->j9gc_allsupported_memorypools(vm);838U_32 supportedCollectorIDs = (U_32)mmFuncs->j9gc_allsupported_garbagecollectors(vm);839U_32 id = 0;840U_32 mask = 0;841UDATA idx = 0;842UDATA count = 0;843UDATA totals[J9VM_MAX_HEAP_MEMORYPOOL_COUNT];844UDATA frees[J9VM_MAX_HEAP_MEMORYPOOL_COUNT];845U_64 used = 0;846J9MemorySegmentList *segList = NULL;847848PORT_ACCESS_FROM_JAVAVM(vm);849mgmt->supportedMemoryPools = getNumberSupported(supportedMemoryPoolIDs);850mgmt->supportedCollectors = getNumberSupported(supportedCollectorIDs);851852/* initialize Heap memory pools (initSize, maxSize) */853mgmt->memoryPools = j9mem_allocate_memory((sizeof(*mgmt->memoryPools) * mgmt->supportedMemoryPools), J9MEM_CATEGORY_VM_JCL);854if (NULL == mgmt->memoryPools) {855return JNI_ERR;856}857memset(mgmt->memoryPools, 0, (sizeof(*mgmt->memoryPools) * mgmt->supportedMemoryPools));858/* request all supported pool data for initial size */859mmFuncs->j9gc_pools_memory(vm, 0, &totals[0], &frees[0], FALSE);860861for (count = 0, mask = 1, idx = 0; count < J9_GC_MANAGEMENT_MAX_POOL; ++count, mask <<= 1) {862863id = (supportedMemoryPoolIDs & mask);864if (0 != id) {865strcpy(mgmt->memoryPools[idx].name, mmFuncs->j9gc_pool_name(vm, id));866mgmt->memoryPools[idx].id = (U_32) (id | J9VM_MANAGEMENT_POOL_HEAP);867mgmt->memoryPools[idx].initialSize = totals[idx];868mgmt->memoryPools[idx].preCollectionMaxSize = mmFuncs->j9gc_pool_maxmemory(vm, id);869mgmt->memoryPools[idx].postCollectionMaxSize = mgmt->memoryPools[idx].preCollectionMaxSize;870idx += 1;871}872}873874/* initialize Garbage Collectors */875mgmt->garbageCollectors = j9mem_allocate_memory((sizeof(*mgmt->garbageCollectors) * mgmt->supportedCollectors), J9MEM_CATEGORY_VM_JCL);876if (NULL == mgmt->garbageCollectors) {877return JNI_ERR;878}879memset(mgmt->garbageCollectors, 0, (sizeof(*mgmt->garbageCollectors) * mgmt->supportedCollectors));880881for (count = 0, mask = 1, idx = 0; count < J9_GC_MANAGEMENT_MAX_COLLECTOR; ++count, mask <<= 1) {882883id = supportedCollectorIDs&mask;884if (0 != id) {885strcpy(mgmt->garbageCollectors[idx].name, mmFuncs->j9gc_garbagecollector_name(vm, id));886mgmt->garbageCollectors[idx].id = (U_32) (id | J9VM_MANAGEMENT_GC_HEAP);887if (mmFuncs->j9gc_is_local_collector(vm, id)) {888mgmt->garbageCollectors[idx].id |= J9VM_MANAGEMENT_GC_LOCAL;889}890idx += 1;891}892}893894/* initialize nonHeap memory pools (initSize) */895mgmt->supportedNonHeapMemoryPools = 2; /* "class storage", "miscellaneous non-heap storage" */896#if defined( J9VM_INTERP_NATIVE_SUPPORT )897if (vm->jitConfig) {898mgmt->supportedNonHeapMemoryPools += 2; /* "JIT code cache", "JIT data cache" */899}900#endif901mgmt->nonHeapMemoryPools = j9mem_allocate_memory((sizeof(*mgmt->nonHeapMemoryPools) * mgmt->supportedNonHeapMemoryPools), J9MEM_CATEGORY_VM_JCL);902if (NULL == mgmt->nonHeapMemoryPools) {903return JNI_ERR;904}905memset(mgmt->nonHeapMemoryPools, 0, (sizeof(*mgmt->nonHeapMemoryPools) * mgmt->supportedNonHeapMemoryPools));906907for (idx = 0; idx < mgmt->supportedNonHeapMemoryPools; idx++) {908switch (idx) {909case CLASS_MEMORY:910mgmt->nonHeapMemoryPools[idx].id = J9VM_MANAGEMENT_POOL_NONHEAP_SEG_CLASSES;911strcpy(mgmt->nonHeapMemoryPools[idx].name, J9VM_MANAGEMENT_NONHEAPPOOL_NAME_CLASSES);912segList = vm->classMemorySegments;913mgmt->nonHeapMemoryPools[idx].maxSize = -1;914break;915case MISC_MEMORY:916mgmt->nonHeapMemoryPools[idx].id = J9VM_MANAGEMENT_POOL_NONHEAP_SEG_MISC;917strcpy(mgmt->nonHeapMemoryPools[idx].name, J9VM_MANAGEMENT_NONHEAPPOOL_NAME_MISC);918segList = vm->memorySegments;919mgmt->nonHeapMemoryPools[idx].maxSize = -1;920break;921case JIT_CODECACHE:922mgmt->nonHeapMemoryPools[idx].id = J9VM_MANAGEMENT_POOL_NONHEAP_SEG_JIT_CODE;923strcpy(mgmt->nonHeapMemoryPools[idx].name, J9VM_MANAGEMENT_NONHEAPPOOL_NAME_JITCODE);924segList = vm->jitConfig->codeCacheList;925mgmt->nonHeapMemoryPools[idx].maxSize = vm->jitConfig->codeCacheTotalKB * 1024;926break;927case JIT_DATACACHE:928mgmt->nonHeapMemoryPools[idx].id = J9VM_MANAGEMENT_POOL_NONHEAP_SEG_JIT_DATA;929strcpy(mgmt->nonHeapMemoryPools[idx].name, J9VM_MANAGEMENT_NONHEAPPOOL_NAME_JITDATA);930segList = vm->jitConfig->dataCacheList;931mgmt->nonHeapMemoryPools[idx].maxSize = vm->jitConfig->dataCacheTotalKB * 1024;932break;933default:934/* Unreachable */935Assert_JCL_unreachable();936}937getSegmentSizes(vm, segList, &mgmt->nonHeapMemoryPools[idx].initialSize, &used, &mgmt->nonHeapMemoryPools[idx].peakSize, &mgmt->nonHeapMemoryPools[idx].peakUsed, (JIT_CODECACHE == idx));938}939return 0;940941}942943static U_32944getNumberSupported(U_32 supportedIDs)945{946U_32 numSupported = 0;947U_32 ids = supportedIDs;948while (0 != ids) {949ids &= ids - 1; /* clear the least bit set */950numSupported += 1;951}952return numSupported;953}954955static UDATA956getArrayIndexFromManagerID(J9JavaLangManagementData *mgmt, UDATA id)957{958UDATA idx = 0;959960for(; idx < mgmt->supportedCollectors; ++idx) {961if ((J9VM_MANAGEMENT_GC_HEAP_ID_MASK & mgmt->garbageCollectors[idx].id) == (J9VM_MANAGEMENT_GC_HEAP_ID_MASK & id)) {962return idx;963}964}965return 0;966}967968static void969getSegmentSizes(J9JavaVM *javaVM, J9MemorySegmentList *segList, U_64 *storedSize, U_64 *storedUsed, U_64 *storedPeakSize, U_64 *storedPeakUsed, BOOLEAN isCodeCacheSegment)970{971U_64 used = 0;972U_64 committed = 0;973J9JavaLangManagementData *mgmt = javaVM->managementData;974975omrthread_monitor_enter(segList->segmentMutex);976977MEMORY_SEGMENT_LIST_DO(segList, seg)978if (isCodeCacheSegment) {979/* Set default values for warmAlloc and coldAlloc pointers */980UDATA warmAlloc = (UDATA)seg->heapBase;981UDATA coldAlloc = (UDATA)seg->heapTop;982983/* The JIT code cache grows from both ends of the segment: the warmAlloc pointer upwards from the start of the segment984* and the coldAlloc pointer downwards from the end of the segment. The free space in a JIT code cache segment is the985* space between the warmAlloc and coldAlloc pointers. See compiler/runtime/OMRCodeCache.hpp, the contract with the JVM is986* that the address of the TR::CodeCache structure is stored at the beginning of the segment.987*/988#ifdef J9VM_INTERP_NATIVE_SUPPORT989UDATA *mccCodeCache = *((UDATA**)seg->heapBase);990if (mccCodeCache) {991J9JITConfig* jitConfig = javaVM->jitConfig;992if (jitConfig) {993warmAlloc = (UDATA)jitConfig->codeCacheWarmAlloc(mccCodeCache);994coldAlloc = (UDATA)jitConfig->codeCacheColdAlloc(mccCodeCache);995}996}997#endif998used += seg->size - (coldAlloc - warmAlloc);999} else {1000used += seg->heapAlloc - seg->heapBase;1001}1002committed += seg->size;1003END_MEMORY_SEGMENT_LIST_DO(seg)10041005omrthread_monitor_exit(segList->segmentMutex);10061007omrthread_rwmutex_enter_write(mgmt->managementDataLock);1008*storedSize = committed;1009*storedUsed = used;1010if (used > *storedPeakUsed) {1011*storedPeakUsed = used;1012*storedPeakSize = committed;1013}1014omrthread_rwmutex_exit_write(mgmt->managementDataLock);1015}10161017static void1018updateNonHeapMemoryPoolSizes(J9JavaVM *vm, J9JavaLangManagementData *mgmt, BOOLEAN isGCEND)1019{1020U_32 idx = 0;1021U_64 *storedSize = NULL;1022U_64 *storedUsed = NULL;1023J9MemorySegmentList *segList = NULL;10241025for (; idx < mgmt->supportedNonHeapMemoryPools; ++idx) {1026switch (idx) {1027case CLASS_MEMORY:1028segList = vm->classMemorySegments;1029break;1030case MISC_MEMORY:1031segList = vm->memorySegments;1032break;1033case JIT_CODECACHE:1034segList = vm->jitConfig->codeCacheList;1035break;1036case JIT_DATACACHE:1037segList = vm->jitConfig->dataCacheList;1038break;1039default:1040/* Unreachable */1041Assert_JCL_unreachable();1042}1043if (isGCEND) {1044storedSize = &mgmt->nonHeapMemoryPools[idx].postCollectionSize;1045storedUsed = &mgmt->nonHeapMemoryPools[idx].postCollectionUsed;1046} else {1047storedSize = &mgmt->nonHeapMemoryPools[idx].preCollectionSize;1048storedUsed = &mgmt->nonHeapMemoryPools[idx].preCollectionUsed;1049}1050getSegmentSizes(vm, segList, storedSize, storedUsed, &mgmt->nonHeapMemoryPools[idx].peakSize, &mgmt->nonHeapMemoryPools[idx].peakUsed, (JIT_CODECACHE== idx));1051}1052}105310541055