home *** CD-ROM | disk | FTP | other *** search
/ Enter 1999 November / ENTER11_1.bin / WARSZTAT / SDKJava32.exe / data1.cab / fg_Samples / Samples / Profiler / jviewprf / gcprof.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-17  |  13.7 KB  |  536 lines

  1. // gcprof.cpp
  2. //
  3. // Created 01/19/99
  4. //
  5. // (C) Copyright 1995 - 1999 Microsoft Corporation.  All rights reserved.
  6. //
  7.  
  8. #include "project.hpp"
  9. #pragma hdrstop
  10.  
  11. #include <jevmon.h>
  12.  
  13. #include "gcprof.hpp"
  14. #include "utils.hpp"
  15. #include "jviewprf.hpp"
  16. #include "resource.h"
  17.  
  18.  
  19. int GCProfiler::Iterate (POBJITERFN fn, PVOID token)
  20. {
  21.     int res = 1;
  22.     
  23.     for (unsigned i = 0; i < ARRAY_ELEMENTS(m_hash); i++)
  24.     {
  25.         GCProfilerEntry *cur = m_hash[i];
  26.         while (cur != NULL)
  27.         {
  28.             GCProfilerEntry *next = cur->next;
  29.             res = (this->*fn)(cur, token);
  30.             if (res <= 0)
  31.                 break;
  32.             cur = next;
  33.         }
  34.     }
  35.  
  36.     return res;
  37. }
  38.  
  39.  
  40. int GCProfiler::DeleteCB (GCProfilerEntry *ent, PVOID token)
  41. {
  42.     delete(ent);
  43.     return 1;
  44. }
  45.  
  46.  
  47. #define WIDTH_GEN       3
  48. #define WIDTH_TOTAL     5
  49. #define WIDTH_NEW       4
  50. #define WIDTH_LIVE1     4
  51. #define WIDTH_LIVE2     6
  52. #define WIDTH_AGE       8
  53.  
  54. #define TOTAL_FIXED_WIDTH (WIDTH_GEN+1+1+WIDTH_TOTAL+1+WIDTH_NEW+1+WIDTH_LIVE1+1+WIDTH_LIVE2+1+WIDTH_AGE)
  55.  
  56.  
  57. int GCProfiler::InstanceDiscoveryCompletedCB (GCProfilerEntry *cur, PVOID token)
  58. {
  59.     if (cur->nlive)
  60.     {
  61.         IJavaEventMonitorIDInfo *pinfo = m_pmon->GetVMInfoIfc();
  62.  
  63.         PSTR pszNameUtf8;
  64.         __int64 ninstances;
  65.         if (SUCCEEDED(pinfo->ClassInformation(cur->id, &pszNameUtf8, NULL, NULL, NULL, &ninstances)))
  66.         {
  67.             WriteOutputEx(WRITE_LEFT_JUSTIFIED, "u ", WIDTH_GEN, m_nGCs);
  68.             WriteOutputEx(WRITE_FIT | WRITE_WRAP | WRITE_UTF8, "s ", TOTAL_FIXED_WIDTH, 1.0, pszNameUtf8);
  69.             WriteOutputEx(WRITE_LEFT_JUSTIFIED, "I64u ", WIDTH_TOTAL, ninstances);
  70.             WriteOutputEx(WRITE_LEFT_JUSTIFIED, "I64u ", WIDTH_NEW, ninstances - cur->lastcount);
  71.             WriteOutputEx(WRITE_LEFT_JUSTIFIED, "u ", WIDTH_LIVE1, cur->nlive);
  72.             WriteOutputEx(WRITE_LEFT_JUSTIFIED, "u ", WIDTH_LIVE2, cur->cblive);
  73.  
  74.             float avgage = 0;
  75.             if (cur->nlive)
  76.                 avgage = (float)cur->totalage/cur->nlive;
  77.             WriteOutputEx(WRITE_LEFT_JUSTIFIED, ".2f\n", WIDTH_AGE, avgage);
  78.  
  79.             CoTaskMemFree(pszNameUtf8);
  80.  
  81.             cur->lastcount = ninstances;
  82.         }            
  83.  
  84.         cur->nlive = 0;
  85.         cur->cblive = 0;
  86.         cur->totalage = 0;
  87.     }
  88.     
  89.     return 1;
  90. }
  91.  
  92.  
  93. VOID GCProfiler::InstanceDiscoveryCompleted ()
  94. {
  95.     WriteOutput("Gen ");
  96.     WriteOutputEx(WRITE_FIT, "s ", TOTAL_FIXED_WIDTH, 1.0, "Type");
  97.     WriteOutputFmt("Total New%*c Live Bytes%*c Avg.age\n", g_OutputWidth != 0, ' ', g_OutputWidth != 0, ' ');
  98.  
  99.     Iterate(&GCProfiler::InstanceDiscoveryCompletedCB);
  100. }
  101.  
  102.  
  103. STDMETHODIMP GCProfiler::QueryInterface (REFIID riid, void **ppv)
  104. {
  105.     if (   riid == IID_IUnknown
  106.         || riid == IID_IHeapInfoCallback)
  107.     {
  108.         *ppv = (IHeapInfoCallback*)this;
  109.     }
  110.     else
  111.     {
  112.         *ppv = NULL;
  113.         return E_NOINTERFACE;
  114.     }
  115.  
  116.     AddRef();
  117.     return S_OK;
  118. }
  119.  
  120.  
  121. STDMETHODIMP_(ULONG) GCProfiler::AddRef(void)
  122. {
  123.     return InterlockedIncrement(&m_refcount);
  124. }
  125.  
  126.  
  127. STDMETHODIMP_(ULONG) GCProfiler::Release(void)
  128. {
  129.     // This refcount should never reach zero.
  130.     return InterlockedDecrement(&m_refcount);
  131. }
  132.  
  133.  
  134. STDMETHODIMP GCProfiler::BeginContainer(CONTAINER_TYPE type, UniqueID id1, UniqueID id2)
  135. {
  136.     m_CurrentContainer = type;
  137.  
  138.     BOOL fDumpHeap = (type != C_BEGIN && type != C_END) && (g_ProfOptions & OPT_DUMP_HEAP);
  139.  
  140.     if (fDumpHeap)
  141.     {
  142.         PWSTR descr;
  143.         if (SUCCEEDED(m_heapmon->GetContainerDescription(type, NULL, &descr)))
  144.         {
  145.             WriteOutput("Object references from ");
  146.             WriteOutputW(descr);
  147.  
  148.             CoTaskMemFree(descr);
  149.         }
  150.     }
  151.  
  152.     switch (type)
  153.     {
  154.     case C_BEGIN:
  155.  
  156.         // TODO: instead of aborting immediately, uninstall callback
  157.  
  158.         if (!(OPT_PROF_GC & g_ProfOptions))
  159.             return E_FAIL;
  160.  
  161.         m_StartTime = GetProfilerTime();
  162.  
  163.         m_nObjects = 0;
  164.         m_nOrphans = 0;
  165.  
  166.         m_fInHeap = FALSE;
  167.         m_iField = 0;
  168.  
  169.         break;
  170.  
  171.     case C_RT_THREAD:
  172.         if (fDumpHeap)
  173.         {
  174.             IJavaEventMonitorIDInfo2 *pinfo2 = m_pmon->GetVMInfoIfc2();
  175.             if (pinfo2)
  176.             {
  177.                 DWORD tid;
  178.                 if (SUCCEEDED(pinfo2->ThreadInformation((ThreadID)id1, &tid)))
  179.                     WriteOutputFmt(" %x", tid);
  180.             }
  181.         }
  182.         break;
  183.  
  184.     case C_RT_NATIVEGC:
  185.     case C_RT_INTERNALFRAME:
  186.         if (fDumpHeap)
  187.             WriteOutputFmt(" 0x%x", id1);
  188.         break;
  189.  
  190.     case C_RT_JIT:
  191.     case C_RT_NATIVE:
  192.     case C_RT_INTERPRETED:
  193.         if (fDumpHeap)
  194.         {
  195.             PSTR pszMethodUtf8;
  196.             if (SUCCEEDED(m_pmon->GetVMInfoIfc()->MethodInformation((MethodID)id2, &pszMethodUtf8, NULL, NULL, NULL, NULL)))
  197.             {
  198.                 WriteOutputFmt(" 0x%x ", id1);
  199.                 WriteOutputUtf8(pszMethodUtf8);
  200.  
  201.                 CoTaskMemFree(pszMethodUtf8);
  202.             }
  203.         }
  204.         break;
  205.  
  206.     case C_RT_CLASS:
  207.         if (fDumpHeap)
  208.         {
  209.             PSTR pszClassUtf8;
  210.             if (SUCCEEDED(m_pmon->GetVMInfoIfc()->ClassInformation((ClassID)id1, &pszClassUtf8, NULL, NULL, NULL, NULL)))
  211.             {
  212.                 WriteOutput(" ");
  213.                 WriteOutputUtf8(pszClassUtf8);
  214.  
  215.                 CoTaskMemFree(pszClassUtf8);
  216.             }
  217.         }
  218.         break;
  219.  
  220.     case C_HEAP:
  221.         m_fInHeap = TRUE;
  222.         break;
  223.  
  224.     case C_END:
  225.  
  226.         if (!(OPT_PROF_GC & g_ProfOptions))
  227.             return E_FAIL;
  228.  
  229.         DWORD time;
  230.         time = GetProfilerTime() - m_StartTime;
  231.  
  232.         WriteOutputFmt("Heap dump duration: %u ms\n", (unsigned)ConvertProfilerTimeToMS(time));
  233.  
  234.         WriteOutputFmt("Total objects: %d\n", m_nObjects);
  235.  
  236.         if (m_nOrphans)
  237.             WriteOutputFmt("Orphaned objects: %d\n", m_nOrphans);
  238.  
  239.         if (g_ProfOptions & OPT_GC_SUMMARY)
  240.             InstanceDiscoveryCompleted();
  241.         break;
  242.     }
  243.  
  244.     if (fDumpHeap)
  245.         WriteOutput(":\n");
  246.  
  247.     return S_OK;
  248. }
  249.  
  250.  
  251. STDMETHODIMP GCProfiler::RootReferences (const ObjectID *prefs, unsigned nrefs, const DWORD *pflags)
  252. {
  253.     HRESULT hr = S_OK;
  254.  
  255.     if (g_ProfOptions & OPT_DUMP_HEAP)
  256.     {
  257.         for (unsigned i = 0; i < nrefs; i++)
  258.         {
  259.             WriteOutputFmt("from root: %08x\n", prefs[i]);
  260.         }
  261.     }
  262.  
  263.     return hr;
  264. }
  265.  
  266. STDMETHODIMP GCProfiler::ObjectReferences (ObjectID id, DWORD flags, const ObjectID *prefs, unsigned nrefs, const DWORD *pflags)
  267. {
  268.     IJavaEventMonitorIDInfo *pinfo = m_pmon->GetVMInfoIfc();
  269.  
  270.     ClassID clstype;
  271.     if (SUCCEEDED(pinfo->ObjectInformation(id, &clstype)))
  272.     {
  273.         IJavaEventMonitorIDInfo2 *pinfo2 = m_pmon->GetVMInfoIfc2();
  274.  
  275.         if (!(g_ProfOptions & OPT_DUMP_HEAP))
  276.         {
  277.             if (!(flags & JVM_OBJ_MORE_REFERENCES))
  278.             {
  279.                 DWORD age = 0;
  280.                 if (m_heapmon)
  281.                     m_heapmon->GetObjectAge(id, &age);
  282.  
  283.                 DWORD size = 0;
  284.                 if (pinfo2)
  285.                     pinfo2->GetObjectSize(id, &size);
  286.  
  287.                 InstanceDiscovered(clstype, size, age);
  288.             }
  289.         }
  290.         else
  291.         {
  292.             PSTR pszClass = m_pszLastObjectClassName;
  293.             if (!pszClass)
  294.             {
  295.                 PSTR pszClassUtf8;
  296.                 if (FAILED(pinfo->ClassInformation(clstype, &pszClassUtf8, NULL, NULL, NULL, NULL)))
  297.                     return E_OUTOFMEMORY;
  298.  
  299.                 PSTR pszClassAnsi;
  300.                 if (!Utf8ToAnsi(pszClassUtf8, &pszClassAnsi))
  301.                 {
  302.                     CoTaskMemFree(pszClassUtf8);
  303.                     return E_OUTOFMEMORY;
  304.                 }
  305.  
  306.                 pszClass = pszClassAnsi;
  307.                 if (!pszClass)
  308.                 {
  309.                     pszClass = pszClassUtf8;
  310.                     m_fLastObjectClassNameIsUtf8 = TRUE;
  311.                 }
  312.                 
  313.                 m_pszLastObjectClassName = pszClass;
  314.  
  315.                 WriteOutputLongFmt("%08x %s", id, pszClass);
  316.  
  317.                 DWORD size = 0;
  318.                 DWORD age = 0;
  319.  
  320.                 if (pinfo2)
  321.                 {
  322.                     if (SUCCEEDED(pinfo2->GetObjectSize(id, &size)))
  323.                     {
  324.                         WriteOutputFmt(" (%u bytes)", size);
  325.                     }
  326.  
  327.                     PWSTR descr;
  328.                     if (SUCCEEDED(pinfo2->DescribeObject(id, &descr)))
  329.                     {
  330.                         WriteOutput(" (");
  331.                         WriteOutputW(descr);
  332.                         WriteOutput(")");
  333.  
  334.                         CoTaskMemFree(descr);
  335.                     }
  336.                 }
  337.  
  338.                 if (m_heapmon)
  339.                 {
  340.                     m_heapmon->GetObjectAge(id, &age);
  341.                 }
  342.  
  343.                 WriteOutput("\n");
  344.  
  345.                 InstanceDiscovered(clstype, size, age);
  346.             }
  347.  
  348.             // Note:
  349.             // - for some Strings, nfields > nrefs
  350.             // - empty arrays may be reported
  351.  
  352.             if (nrefs)
  353.             {
  354.                 if (pszClass[0] != '[')
  355.                 {
  356.                     if (pinfo2 != NULL)
  357.                     {
  358.                         unsigned nfields;
  359.                         FieldID *pfields;
  360.                         if (SUCCEEDED(pinfo2->GetClassFields(clstype, &nfields, &pfields)))
  361.                         {
  362.                             unsigned ifld = m_iField;
  363.                             unsigned iref = 0;
  364.                             while (ifld < nfields)
  365.                             {
  366.                                 PSTR name;
  367.                                 DWORD flags;
  368.                                 HRESULT hr = pinfo2->FieldInformation(pfields[ifld], &name, &flags);
  369.                                 if (FAILED(hr))
  370.                                     name = "???";
  371.  
  372.                                 ifld++;
  373.  
  374.                                 if (!(flags & JVM_FIELD_STATIC) && (flags & JVM_FIELD_OBJECTREF))
  375.                                 {
  376.                                     WriteOutputLongFmt("        %-23s %08x\n", name, prefs[iref]);
  377.  
  378.                                     iref++;
  379.                                 }
  380.  
  381.                                 if (SUCCEEDED(hr))
  382.                                     CoTaskMemFree(name);
  383.  
  384.                                 if (iref == nrefs)
  385.                                     break;
  386.                             }
  387.  
  388.                             m_iField = ifld;
  389.  
  390.                             CoTaskMemFree(pfields);
  391.                         }
  392.                     }
  393.                 }
  394.                 else
  395.                 {
  396.                     unsigned i;
  397.                     for (i = 0; i < nrefs; i++)
  398.                     {
  399.                         WriteOutputFmt("        %-3d %08x\n", m_iField+i, prefs[i]);
  400.                     }
  401.  
  402.                     m_iField += nrefs;
  403.                 }
  404.             }
  405.  
  406.             if (!(flags & JVM_OBJ_MORE_REFERENCES))
  407.             {
  408.                 m_iField = 0;
  409.  
  410.                 if (m_fLastObjectClassNameIsUtf8)
  411.                     CoTaskMemFree(pszClass);
  412.                 else
  413.                     delete pszClass;
  414.                 m_pszLastObjectClassName = NULL;
  415.             }
  416.         }
  417.     }
  418.  
  419.     return S_OK;
  420. }
  421.  
  422.  
  423. HRESULT GCProfiler::Initialize (EventMonitor *pmon)
  424. {
  425.     (m_pmon = pmon)->AddRef();
  426.  
  427.     HRESULT hr = S_OK;
  428.  
  429.     if (g_ProfOptions & OPT_PROF_GC)
  430.     {
  431.         hr = pmon->GetVMInfoIfc()->QueryInterface(IID_IJavaHeapMonitor, (PVOID*)&m_heapmon);
  432.  
  433.         if (m_heapmon)
  434.         {
  435.             DWORD caps;
  436.             hr = m_heapmon->ModifyHeapMonitorCapabilities(JVM_HEAPMON_OBJECT_AGE, TRUE, &caps);
  437.             if (hr != S_OK || !(caps & JVM_HEAPMON_OBJECT_AGE))
  438.             {
  439.                 Warning(IDS_AGINGNOTSUP);
  440.                 hr = S_OK;
  441.             }
  442.         }
  443.  
  444.         if (hr == S_OK)
  445.         {
  446.             IHeapInfoCallback *heapcb;
  447.             hr = QueryInterface(IID_IHeapInfoCallback, (PVOID*)&heapcb);
  448.             if (hr == S_OK)
  449.             {
  450.                 hr = m_heapmon->GetHeapInfo(heapcb);
  451.  
  452.                 heapcb->Release();
  453.             }
  454.         }
  455.  
  456.         if (hr != S_OK)
  457.         {
  458.             FatalError(IDS_HEAPDUMPNOTSUP);
  459.         }
  460.  
  461.     }
  462.  
  463.     return S_OK;
  464. }
  465.  
  466.  
  467. VOID GCProfiler::Destruct ()
  468. {
  469.     if (m_heapmon)
  470.     {
  471.         m_heapmon->GetHeapInfo(NULL);
  472.         m_heapmon->Release();
  473.     }
  474.  
  475.     if (m_pmon)
  476.         m_pmon->Release();
  477.     
  478.     Iterate(&GCProfiler::DeleteCB);
  479.  
  480.     DeleteCriticalSection(&m_cs);
  481. }
  482.  
  483.  
  484. VOID GCProfiler::GCStarted ()
  485. {
  486.     m_nGCs++;
  487.  
  488.     if (g_ProfOptions & OPT_DUMP_HEAP)
  489.     {
  490.         if (g_OutputWidth)
  491.         {
  492.             WriteOutput("\n\n\n");
  493.             LONG width = g_OutputWidth-1;
  494.             while (width-- > 0)
  495.                 WriteOutput("-");
  496.             WriteOutput("\n");
  497.         }
  498.  
  499.         WriteOutputFmt("Garbage collection %u\n", m_nGCs);
  500.  
  501.         if (g_OutputWidth)
  502.             WriteOutput("\n");
  503.     }
  504.  
  505.     m_StartTime = GetProfilerTime();
  506. }
  507.  
  508.  
  509. VOID GCProfiler::GCFinished ()
  510. {
  511.     PROFTIME gctime = GetProfilerTime() - m_StartTime;
  512.  
  513.     if (g_ProfOptions & OPT_PROF_GC)
  514.     {
  515.         WriteOutputFmt("GC %u duration: %u ms\n", m_nGCs, (unsigned)ConvertProfilerTimeToMS(gctime));
  516.     }
  517. }
  518.  
  519.  
  520. DWORD g_OriginalGCOptions = 0;
  521.  
  522. VOID __stdcall EnableHeapDumping (BOOL fEnable)
  523. {
  524.     if (fEnable)
  525.     {
  526.         DWORD OriginalOptions = (g_OriginalGCOptions & (OPT_PROF_GC | OPT_DUMP_HEAP));
  527.         g_ProfOptions |= OriginalOptions;
  528.     }
  529.     else
  530.     {
  531.         g_OriginalGCOptions = g_ProfOptions;
  532.         g_ProfOptions &= ~(OPT_PROF_GC | OPT_DUMP_HEAP);
  533.     }
  534. }
  535.  
  536.