home *** CD-ROM | disk | FTP | other *** search
- // gcprof.cpp
- //
- // Created 01/19/99
- //
- // (C) Copyright 1995 - 1999 Microsoft Corporation. All rights reserved.
- //
-
- #include "project.hpp"
- #pragma hdrstop
-
- #include <jevmon.h>
-
- #include "gcprof.hpp"
- #include "utils.hpp"
- #include "jviewprf.hpp"
- #include "resource.h"
-
-
- int GCProfiler::Iterate (POBJITERFN fn, PVOID token)
- {
- int res = 1;
-
- for (unsigned i = 0; i < ARRAY_ELEMENTS(m_hash); i++)
- {
- GCProfilerEntry *cur = m_hash[i];
- while (cur != NULL)
- {
- GCProfilerEntry *next = cur->next;
- res = (this->*fn)(cur, token);
- if (res <= 0)
- break;
- cur = next;
- }
- }
-
- return res;
- }
-
-
- int GCProfiler::DeleteCB (GCProfilerEntry *ent, PVOID token)
- {
- delete(ent);
- return 1;
- }
-
-
- #define WIDTH_GEN 3
- #define WIDTH_TOTAL 5
- #define WIDTH_NEW 4
- #define WIDTH_LIVE1 4
- #define WIDTH_LIVE2 6
- #define WIDTH_AGE 8
-
- #define TOTAL_FIXED_WIDTH (WIDTH_GEN+1+1+WIDTH_TOTAL+1+WIDTH_NEW+1+WIDTH_LIVE1+1+WIDTH_LIVE2+1+WIDTH_AGE)
-
-
- int GCProfiler::InstanceDiscoveryCompletedCB (GCProfilerEntry *cur, PVOID token)
- {
- if (cur->nlive)
- {
- IJavaEventMonitorIDInfo *pinfo = m_pmon->GetVMInfoIfc();
-
- PSTR pszNameUtf8;
- __int64 ninstances;
- if (SUCCEEDED(pinfo->ClassInformation(cur->id, &pszNameUtf8, NULL, NULL, NULL, &ninstances)))
- {
- WriteOutputColumnULONG(WRITE_LEFT_JUSTIFIED | WRITE_SPACE, WIDTH_GEN, m_nGCs);
- WriteOutputFitString(WRITE_FIT | WRITE_WRAP | WRITE_UTF8 | WRITE_SPACE, TOTAL_FIXED_WIDTH, 100, pszNameUtf8);
- WriteOutputColumnUINT64(WRITE_LEFT_JUSTIFIED | WRITE_SPACE, WIDTH_TOTAL, ninstances);
- WriteOutputColumnUINT64(WRITE_LEFT_JUSTIFIED | WRITE_SPACE, WIDTH_NEW, ninstances - cur->lastcount);
- WriteOutputColumnULONG(WRITE_LEFT_JUSTIFIED | WRITE_SPACE, WIDTH_LIVE1, cur->nlive);
- WriteOutputColumnULONG(WRITE_LEFT_JUSTIFIED | WRITE_SPACE, WIDTH_LIVE2, cur->cblive);
-
- float avgage = 0;
- if (cur->nlive)
- avgage = (float)cur->totalage/cur->nlive;
- WriteOutputFixedFloat(0, avgage, 2);
-
- WriteOutput("\n");
-
- CoTaskMemFree(pszNameUtf8);
-
- cur->lastcount = ninstances;
- }
-
- cur->nlive = 0;
- cur->cblive = 0;
- cur->totalage = 0;
- }
-
- return 1;
- }
-
-
- VOID GCProfiler::InstanceDiscoveryCompleted ()
- {
- WriteOutput("Gen ");
- WriteOutputFitString(WRITE_FIT | WRITE_SPACE, TOTAL_FIXED_WIDTH, 100, "Type");
- WriteOutputFmt("Total New Live Bytes Avg.age\n");
-
- Iterate(&GCProfiler::InstanceDiscoveryCompletedCB);
- }
-
-
- STDMETHODIMP GCProfiler::QueryInterface (REFIID riid, void **ppv)
- {
- if ( riid == IID_IUnknown
- || riid == IID_IHeapInfoCallback)
- {
- *ppv = (IHeapInfoCallback*)this;
- }
- else
- {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
-
- AddRef();
- return S_OK;
- }
-
-
- STDMETHODIMP_(ULONG) GCProfiler::AddRef(void)
- {
- return InterlockedIncrement(&m_refcount);
- }
-
-
- STDMETHODIMP_(ULONG) GCProfiler::Release(void)
- {
- // This refcount should never reach zero.
- return InterlockedDecrement(&m_refcount);
- }
-
-
- STDMETHODIMP GCProfiler::BeginContainer(CONTAINER_TYPE type, UniqueID id1, UniqueID id2)
- {
- m_CurrentContainer = type;
-
- BOOL fDumpHeap = (type != C_BEGIN && type != C_END) && (g_ProfOptions & OPT_DUMP_HEAP);
-
- if (fDumpHeap)
- {
- PWSTR descr;
- if (SUCCEEDED(m_heapmon->GetContainerDescription(type, NULL, &descr)))
- {
- WriteOutput("Object references from ");
- WriteOutputW(descr);
-
- CoTaskMemFree(descr);
- }
- }
-
- switch (type)
- {
- case C_BEGIN:
-
- // TODO: instead of aborting immediately, uninstall callback
-
- if (!(OPT_PROF_GC & g_ProfOptions))
- return E_FAIL;
-
- m_StartTime = GetProfilerTime();
-
- m_nObjects = 0;
- m_nOrphans = 0;
-
- m_fInHeap = FALSE;
- m_iField = 0;
-
- break;
-
- case C_RT_THREAD:
- if (fDumpHeap)
- {
- IJavaEventMonitorIDInfo2 *pinfo2 = m_pmon->GetVMInfoIfc2();
- if (pinfo2)
- {
- DWORD tid;
- if (SUCCEEDED(pinfo2->ThreadInformation((ThreadID)id1, &tid)))
- WriteOutputFmt(" %x", tid);
- }
- }
- break;
-
- case C_RT_NATIVEGC:
- case C_RT_INTERNALFRAME:
- if (fDumpHeap)
- WriteOutputFmt(" 0x%x", id1);
- break;
-
- case C_RT_JIT:
- case C_RT_NATIVE:
- case C_RT_INTERPRETED:
- if (fDumpHeap)
- {
- PSTR pszMethodUtf8;
- if (SUCCEEDED(m_pmon->GetVMInfoIfc()->MethodInformation((MethodID)id2, &pszMethodUtf8, NULL, NULL, NULL, NULL)))
- {
- WriteOutputFmt(" 0x%x ", id1);
- WriteOutputUtf8(pszMethodUtf8);
-
- CoTaskMemFree(pszMethodUtf8);
- }
- }
- break;
-
- case C_RT_CLASS:
- if (fDumpHeap)
- {
- PSTR pszClassUtf8;
- if (SUCCEEDED(m_pmon->GetVMInfoIfc()->ClassInformation((ClassID)id1, &pszClassUtf8, NULL, NULL, NULL, NULL)))
- {
- WriteOutput(" ");
- WriteOutputUtf8(pszClassUtf8);
-
- CoTaskMemFree(pszClassUtf8);
- }
- }
- break;
-
- case C_HEAP:
- m_fInHeap = TRUE;
- break;
-
- case C_END:
-
- if (!(OPT_PROF_GC & g_ProfOptions))
- return E_FAIL;
-
- PROFTIME time;
- time = GetProfilerTime() - m_StartTime;
-
- WriteOutput("Heap dump duration: ");
- WriteOutputFixedFloat(0, ConvertProfilerTimeToMS(time), 1);
- WriteOutput(" ms\n");
-
- WriteOutputFmt("Total objects: %d\n", m_nObjects);
-
- if (m_nOrphans)
- WriteOutputFmt("Orphaned objects: %d\n", m_nOrphans);
-
- if (g_ProfOptions & OPT_GC_SUMMARY)
- InstanceDiscoveryCompleted();
- break;
- }
-
- if (fDumpHeap)
- WriteOutput(":\n");
-
- return S_OK;
- }
-
-
- STDMETHODIMP GCProfiler::RootReferences (const ObjectID *prefs, unsigned nrefs, const DWORD *pflags)
- {
- HRESULT hr = S_OK;
-
- if (g_ProfOptions & OPT_DUMP_HEAP)
- {
- for (unsigned i = 0; i < nrefs; i++)
- {
- WriteOutputFmt("from root: %08x\n", prefs[i]);
- }
- }
-
- return hr;
- }
-
- STDMETHODIMP GCProfiler::ObjectReferences (ObjectID id, DWORD flags, const ObjectID *prefs, unsigned nrefs, const DWORD *pflags)
- {
- IJavaEventMonitorIDInfo *pinfo = m_pmon->GetVMInfoIfc();
-
- ClassID clstype;
- if (SUCCEEDED(pinfo->ObjectInformation(id, &clstype)))
- {
- IJavaEventMonitorIDInfo2 *pinfo2 = m_pmon->GetVMInfoIfc2();
-
- if (!(g_ProfOptions & OPT_DUMP_HEAP))
- {
- if (!(flags & JVM_OBJ_MORE_REFERENCES))
- {
- DWORD age = 0;
- if (m_heapmon)
- m_heapmon->GetObjectAge(id, &age);
-
- DWORD size = 0;
- if (pinfo2)
- pinfo2->GetObjectSize(id, &size);
-
- InstanceDiscovered(clstype, size, age);
- }
- }
- else
- {
- PSTR pszClass = m_pszLastObjectClassName;
- if (!pszClass)
- {
- PSTR pszClassUtf8;
- if (FAILED(pinfo->ClassInformation(clstype, &pszClassUtf8, NULL, NULL, NULL, NULL)))
- return E_OUTOFMEMORY;
-
- PSTR pszClassAnsi;
- if (!Utf8ToAnsi(pszClassUtf8, &pszClassAnsi))
- {
- CoTaskMemFree(pszClassUtf8);
- return E_OUTOFMEMORY;
- }
-
- pszClass = pszClassAnsi;
- if (!pszClass)
- {
- pszClass = pszClassUtf8;
- m_fLastObjectClassNameIsUtf8 = TRUE;
- }
-
- m_pszLastObjectClassName = pszClass;
-
- WriteOutputFmt("%08x %s", id, pszClass);
-
- DWORD size = 0;
- DWORD age = 0;
-
- if (pinfo2)
- {
- if (SUCCEEDED(pinfo2->GetObjectSize(id, &size)))
- {
- WriteOutputFmt(" (%u bytes)", size);
- }
-
- PWSTR descr;
- if (SUCCEEDED(pinfo2->DescribeObject(id, &descr)))
- {
- WriteOutput(" (");
- WriteOutputW(descr);
- WriteOutput(")");
-
- CoTaskMemFree(descr);
- }
- }
-
- if (m_heapmon)
- {
- m_heapmon->GetObjectAge(id, &age);
- }
-
- WriteOutput("\n");
-
- InstanceDiscovered(clstype, size, age);
- }
-
- // Note:
- // - for some Strings, nfields > nrefs
- // - empty arrays may be reported
-
- if (nrefs)
- {
- if (pszClass[0] != '[')
- {
- if (pinfo2 != NULL)
- {
- unsigned nfields;
- FieldID *pfields;
- if (SUCCEEDED(pinfo2->GetClassFields(clstype, &nfields, &pfields)))
- {
- unsigned ifld = m_iField;
- unsigned iref = 0;
- while (ifld < nfields)
- {
- PSTR name;
- DWORD flags;
- HRESULT hr = pinfo2->FieldInformation(pfields[ifld], &name, &flags);
- if (FAILED(hr))
- name = "???";
-
- ifld++;
-
- if (!(flags & JVM_FIELD_STATIC) && (flags & JVM_FIELD_OBJECTREF))
- {
- WriteOutputFmt(" %-23s %08x\n", name, prefs[iref]);
-
- iref++;
- }
-
- if (SUCCEEDED(hr))
- CoTaskMemFree(name);
-
- if (iref == nrefs)
- break;
- }
-
- m_iField = ifld;
-
- CoTaskMemFree(pfields);
- }
- }
- }
- else
- {
- unsigned i;
- for (i = 0; i < nrefs; i++)
- {
- WriteOutputFmt(" %-3d %08x\n", m_iField+i, prefs[i]);
- }
-
- m_iField += nrefs;
- }
- }
-
- if (!(flags & JVM_OBJ_MORE_REFERENCES))
- {
- m_iField = 0;
-
- if (m_fLastObjectClassNameIsUtf8)
- CoTaskMemFree(pszClass);
- else
- delete pszClass;
- m_pszLastObjectClassName = NULL;
- }
- }
- }
-
- return S_OK;
- }
-
-
- HRESULT GCProfiler::Initialize (EventMonitor *pmon)
- {
- (m_pmon = pmon)->AddRef();
-
- HRESULT hr = S_OK;
-
- if (g_ProfOptions & OPT_PROF_GC)
- {
- hr = pmon->GetVMInfoIfc()->QueryInterface(IID_IJavaHeapMonitor, (PVOID*)&m_heapmon);
-
- if (m_heapmon)
- {
- DWORD caps;
- hr = m_heapmon->ModifyHeapMonitorCapabilities(JVM_HEAPMON_OBJECT_AGE, TRUE, &caps);
- if (hr != S_OK || !(caps & JVM_HEAPMON_OBJECT_AGE))
- {
- Warning(IDS_AGINGNOTSUP);
- hr = S_OK;
- }
- }
-
- if (hr == S_OK)
- {
- IHeapInfoCallback *heapcb;
- hr = QueryInterface(IID_IHeapInfoCallback, (PVOID*)&heapcb);
- if (hr == S_OK)
- {
- hr = m_heapmon->GetHeapInfo(heapcb);
-
- heapcb->Release();
- }
- }
-
- if (hr != S_OK)
- {
- FatalError(IDS_HEAPDUMPNOTSUP);
- }
-
- }
-
- return S_OK;
- }
-
-
- VOID GCProfiler::Destruct ()
- {
- if (m_heapmon)
- {
- m_heapmon->GetHeapInfo(NULL);
- m_heapmon->Release();
- }
-
- if (m_pmon)
- m_pmon->Release();
-
- Iterate(&GCProfiler::DeleteCB);
-
- DeleteCriticalSection(&m_cs);
- }
-
-
- VOID GCProfiler::GCStarted ()
- {
- m_nGCs++;
-
- if (g_ProfOptions & OPT_DUMP_HEAP)
- {
- if (g_OutputWidth)
- {
- WriteOutput("\n\n\n");
- LONG width = g_OutputWidth-1;
- while (width-- > 0)
- WriteOutput("-");
- WriteOutput("\n");
- }
-
- WriteOutputFmt("Garbage collection %u\n", m_nGCs);
-
- if (g_OutputWidth)
- WriteOutput("\n");
- }
-
- m_StartTime = GetProfilerTime();
- }
-
-
- VOID GCProfiler::GCFinished ()
- {
- PROFTIME gctime = GetProfilerTime() - m_StartTime;
-
- if (g_ProfOptions & OPT_PROF_GC)
- {
- WriteOutputFmt("GC %u duration: ", m_nGCs);
- WriteOutputFixedFloat(0, ConvertProfilerTimeToMS(gctime), 1);
- WriteOutput(" ms\n");
- }
- }
-
-
- DWORD g_OriginalGCOptions = 0;
-
- VOID __stdcall EnableHeapDumping (BOOL fEnable)
- {
- if (fEnable)
- {
- DWORD OriginalOptions = (g_OriginalGCOptions & (OPT_PROF_GC | OPT_DUMP_HEAP));
- g_ProfOptions |= OriginalOptions;
- }
- else
- {
- g_OriginalGCOptions = g_ProfOptions;
- g_ProfOptions &= ~(OPT_PROF_GC | OPT_DUMP_HEAP);
- }
- }
-
-