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