mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 03:28:20 +02:00
Added diagnostics panel
This commit is contained in:
parent
efa9566f88
commit
f034880723
12 changed files with 1017 additions and 51 deletions
|
@ -663,6 +663,15 @@ BFGC::BFGC()
|
||||||
for (int i = 0; i < kNumClasses; i++)
|
for (int i = 0; i < kNumClasses; i++)
|
||||||
gGCDbgData.mSizeClasses[i] = Static::sizemap()->ByteSizeForClass(i);
|
gGCDbgData.mSizeClasses[i] = Static::sizemap()->ByteSizeForClass(i);
|
||||||
|
|
||||||
|
mStats = NULL;
|
||||||
|
Beefy::String memName = StrFormat("BFGC_stats_%d", GetCurrentProcessId());
|
||||||
|
auto* fileMapping = ::CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Stats), memName.c_str());
|
||||||
|
if (fileMapping != NULL)
|
||||||
|
{
|
||||||
|
mStats = (Stats*)MapViewOfFile(fileMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(Stats));
|
||||||
|
mStats->mHeapSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
RawInit();
|
RawInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1816,6 +1825,13 @@ void BFGC::FinishCollect()
|
||||||
mStage = 4;
|
mStage = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BFGC::UpdateStats()
|
||||||
|
{
|
||||||
|
if (mStats == NULL)
|
||||||
|
return;
|
||||||
|
mStats->mHeapSize = TCMalloc_SystemTaken;
|
||||||
|
}
|
||||||
|
|
||||||
void BFGC::Run()
|
void BFGC::Run()
|
||||||
{
|
{
|
||||||
BfpThread_SetName(BfpThread_GetCurrent(), "BFGC", NULL);
|
BfpThread_SetName(BfpThread_GetCurrent(), "BFGC", NULL);
|
||||||
|
@ -1824,6 +1840,8 @@ void BFGC::Run()
|
||||||
|
|
||||||
while (!mExiting)
|
while (!mExiting)
|
||||||
{
|
{
|
||||||
|
UpdateStats();
|
||||||
|
|
||||||
float fullGCPeriod = mFullGCPeriod;
|
float fullGCPeriod = mFullGCPeriod;
|
||||||
if ((fullGCPeriod != -1) && (mMaxPausePercentage > 0) && (!mCollectReports.IsEmpty()))
|
if ((fullGCPeriod != -1) && (mMaxPausePercentage > 0) && (!mCollectReports.IsEmpty()))
|
||||||
{
|
{
|
||||||
|
@ -1835,7 +1853,7 @@ void BFGC::Run()
|
||||||
fullGCPeriod = BF_MIN(fullGCPeriod, maxExpandPeriod);
|
fullGCPeriod = BF_MIN(fullGCPeriod, maxExpandPeriod);
|
||||||
}
|
}
|
||||||
|
|
||||||
int waitPeriod = fullGCPeriod;
|
int waitPeriod = BF_MIN(fullGCPeriod, 100);
|
||||||
if (waitPeriod == 0)
|
if (waitPeriod == 0)
|
||||||
waitPeriod = -1;
|
waitPeriod = -1;
|
||||||
mCollectEvent.WaitFor(waitPeriod);
|
mCollectEvent.WaitFor(waitPeriod);
|
||||||
|
|
|
@ -164,6 +164,11 @@ namespace tcmalloc_raw
|
||||||
class BFGC
|
class BFGC
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
struct Stats
|
||||||
|
{
|
||||||
|
intptr mHeapSize;
|
||||||
|
};
|
||||||
|
|
||||||
struct ThreadInfo
|
struct ThreadInfo
|
||||||
{
|
{
|
||||||
static BF_TLS_DECLSPEC ThreadInfo* sCurThreadInfo;
|
static BF_TLS_DECLSPEC ThreadInfo* sCurThreadInfo;
|
||||||
|
@ -276,6 +281,7 @@ public:
|
||||||
|
|
||||||
BfpThreadId mThreadId;
|
BfpThreadId mThreadId;
|
||||||
|
|
||||||
|
Stats* mStats;
|
||||||
volatile bool mExiting;
|
volatile bool mExiting;
|
||||||
volatile bool mRunning;
|
volatile bool mRunning;
|
||||||
bool mGracelessShutdown;
|
bool mGracelessShutdown;
|
||||||
|
@ -368,6 +374,7 @@ public:
|
||||||
|
|
||||||
void DoCollect(bool doingFullGC);
|
void DoCollect(bool doingFullGC);
|
||||||
void FinishCollect();
|
void FinishCollect();
|
||||||
|
void UpdateStats();
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
static void BFP_CALLTYPE RunStub(void* gc);
|
static void BFP_CALLTYPE RunStub(void* gc);
|
||||||
|
|
|
@ -12873,6 +12873,7 @@ namespace IDE
|
||||||
for (var project in mWorkspace.mProjects)
|
for (var project in mWorkspace.mProjects)
|
||||||
project.Update();
|
project.Update();
|
||||||
UpdateCompilersAndDebugger();
|
UpdateCompilersAndDebugger();
|
||||||
|
gApp.mDiagnosticsPanel.UpdateStats();
|
||||||
if (mScriptManager != null)
|
if (mScriptManager != null)
|
||||||
mScriptManager.Update();
|
mScriptManager.Update();
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,695 @@
|
||||||
using System;
|
using System;
|
||||||
using Beefy.utils;
|
using Beefy.utils;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Collections;
|
||||||
|
using Beefy.gfx;
|
||||||
|
using Beefy.geom;
|
||||||
|
using Beefy.theme.dark;
|
||||||
|
using Beefy.widgets;
|
||||||
|
|
||||||
namespace IDE.ui
|
namespace IDE.ui
|
||||||
{
|
{
|
||||||
class DiagnosticsPanel : Panel
|
class DiagnosticsPanel : Panel
|
||||||
{
|
{
|
||||||
|
class DbgAllocListViewItem : IDEListViewItem
|
||||||
|
{
|
||||||
|
public int mTypeId;
|
||||||
|
public int mAllocCount;
|
||||||
|
public int mAllocSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DbgAllocListView : DarkListView
|
||||||
|
{
|
||||||
|
public this()
|
||||||
|
{
|
||||||
|
//mShowLineGrid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override ListViewItem CreateListViewItem()
|
||||||
|
{
|
||||||
|
return new DbgAllocListViewItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DrawAll(Graphics g)
|
||||||
|
{
|
||||||
|
base.DrawAll(g);
|
||||||
|
|
||||||
|
/*using (g.PushColor(0x40FF0000))
|
||||||
|
g.FillRect(8, 8, mWidth - 16, mHeight - 16);*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Sample
|
||||||
|
{
|
||||||
|
public double mValue;
|
||||||
|
public double mTime;
|
||||||
|
|
||||||
|
public this(double value, double time)
|
||||||
|
{
|
||||||
|
mValue = value;
|
||||||
|
mTime = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Sample operator+(Sample lhs, Sample rhs)
|
||||||
|
{
|
||||||
|
return .(lhs.mValue + rhs.mValue, lhs.mTime + rhs.mTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Sample operator-(Sample lhs, Sample rhs)
|
||||||
|
{
|
||||||
|
return .(lhs.mValue - rhs.mValue, lhs.mTime - rhs.mTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Sample operator*(Sample lhs, float rhs)
|
||||||
|
{
|
||||||
|
return .(lhs.mValue * rhs, lhs.mTime * rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Data
|
||||||
|
{
|
||||||
|
public const int cMaxSamples = 1000;
|
||||||
|
public static float[cMaxSamples + 1] sSampleMixTable;
|
||||||
|
|
||||||
|
static this()
|
||||||
|
{
|
||||||
|
for (int i < cMaxSamples + 1)
|
||||||
|
{
|
||||||
|
float pct = (i + 0.1f) / (float)(cMaxSamples - 3);
|
||||||
|
pct = Math.Pow(pct, 1.5f);
|
||||||
|
sSampleMixTable[i] = pct;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<double> mSamples = new .() ~ delete _;
|
||||||
|
double mPrevSample;
|
||||||
|
double mNextSample;
|
||||||
|
|
||||||
|
public double mMaxValue;
|
||||||
|
List<double> mPrevValues = new List<double>() ~ delete _;
|
||||||
|
|
||||||
|
double mSampleAcc;
|
||||||
|
int32 mSampleCount;
|
||||||
|
int32 mSampleCombine;
|
||||||
|
|
||||||
|
public this(int sampleCombine)
|
||||||
|
{
|
||||||
|
mSampleCombine = (.)sampleCombine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddSample(double sample)
|
||||||
|
{
|
||||||
|
double insertSample = sample;
|
||||||
|
|
||||||
|
if (mSampleCombine > 1)
|
||||||
|
{
|
||||||
|
if (mSamples.IsEmpty)
|
||||||
|
{
|
||||||
|
mPrevSample = sample;
|
||||||
|
mNextSample = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSampleAcc += sample;
|
||||||
|
mSampleCount++;
|
||||||
|
|
||||||
|
insertSample = Math.Lerp(mPrevSample, mNextSample, mSampleCount / (float)mSampleCombine);
|
||||||
|
|
||||||
|
if (mSampleCount == mSampleCombine)
|
||||||
|
{
|
||||||
|
mPrevSample = mNextSample;
|
||||||
|
mNextSample = mSampleAcc / mSampleCombine;
|
||||||
|
mSampleCount = 0;
|
||||||
|
mSampleAcc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mSamples.Add(insertSample);
|
||||||
|
|
||||||
|
mPrevValues.Add(insertSample);
|
||||||
|
|
||||||
|
mMaxValue = Math.Max(mMaxValue, insertSample);
|
||||||
|
|
||||||
|
while (mSamples.Count > cMaxSamples)
|
||||||
|
{
|
||||||
|
for (int sampleIdx < mSamples.Count - 1)
|
||||||
|
{
|
||||||
|
let lhs = mSamples[sampleIdx];
|
||||||
|
let rhs = mSamples[sampleIdx + 1];
|
||||||
|
float pct = sSampleMixTable[sampleIdx];
|
||||||
|
mSamples[sampleIdx] = Math.Lerp(lhs, rhs, pct);
|
||||||
|
}
|
||||||
|
mSamples.PopBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
mMaxValue = 0;
|
||||||
|
mSamples.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Get(float sampleIdx)
|
||||||
|
{
|
||||||
|
let lhs = mSamples[(int)sampleIdx];
|
||||||
|
let rhs = mSamples[(int)Math.Min(sampleIdx + 1, mSamples.Count - 1)];
|
||||||
|
return (.)Math.Lerp(lhs, rhs, sampleIdx - (int)sampleIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DataView : Widget
|
||||||
|
{
|
||||||
|
public DiagnosticsPanel mPanel;
|
||||||
|
public Data mTimes;
|
||||||
|
public Data mData;
|
||||||
|
public double? mOverDataTime;
|
||||||
|
public double? mOverDataValue;
|
||||||
|
public String mLabel = new .() ~ delete _;
|
||||||
|
|
||||||
|
public this(StringView label)
|
||||||
|
{
|
||||||
|
mLabel.Set(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
[LinkName(.C)]
|
||||||
|
public static extern double log10(double val);
|
||||||
|
|
||||||
|
[LinkName(.C)]
|
||||||
|
public static extern double log2(double val);
|
||||||
|
|
||||||
|
void ValToString(double val, String str)
|
||||||
|
{
|
||||||
|
let kSize = 1024;
|
||||||
|
|
||||||
|
let maxValue = mData.mMaxValue;
|
||||||
|
if (maxValue < 1000)
|
||||||
|
{
|
||||||
|
str.AppendF("{:0.00}", val);
|
||||||
|
}
|
||||||
|
else if (maxValue < 10000)
|
||||||
|
{
|
||||||
|
str.AppendF("{:0.0}", val);
|
||||||
|
}
|
||||||
|
else if (maxValue < 1'000'000)
|
||||||
|
{
|
||||||
|
str.AppendF("{}", (int)val);
|
||||||
|
}
|
||||||
|
else if (maxValue < 1000 * kSize)
|
||||||
|
{
|
||||||
|
str.AppendF("{:0.000}K", val / kSize);
|
||||||
|
}
|
||||||
|
else if (maxValue < 1000 * (kSize * kSize))
|
||||||
|
{
|
||||||
|
str.AppendF("{:0.000}M", val / (kSize * kSize));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str.AppendF("{:0.000}G", val / (kSize * kSize * kSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawData(Graphics g, Data data, Data timeData, float xOfs, float yOfs, float width, float height)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/*for (double maxValue = 0.001; maxValue < 2; maxValue += 0.001)
|
||||||
|
{
|
||||||
|
double segLog10 = log10(maxValue);
|
||||||
|
if (segLog10 > 0)
|
||||||
|
segLog10 = (int)(segLog10);
|
||||||
|
double segSize = Math.Pow(10, segLog10);
|
||||||
|
double numSegs = maxValue / segSize;
|
||||||
|
if (numSegs < 2)
|
||||||
|
segSize /= 4;
|
||||||
|
else if (numSegs < 4)
|
||||||
|
segSize /= 2;
|
||||||
|
numSegs = maxValue / segSize;
|
||||||
|
|
||||||
|
Debug.WriteLine("{} {:.00} {:.00}", maxValue, segSize, numSegs);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*while (true)
|
||||||
|
{
|
||||||
|
double numSegs = maxValue / segSize;
|
||||||
|
if (numSegs >= 3)
|
||||||
|
break;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
using (g.PushTranslate(xOfs, yOfs))
|
||||||
|
{
|
||||||
|
using (g.PushColor(0xA0000000))
|
||||||
|
{
|
||||||
|
g.FillRect(0, 0, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (g.PushColor(0x40FFFFFF))
|
||||||
|
{
|
||||||
|
g.OutlineRect(-1, -1, width + 2, height + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.mSamples.IsEmpty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (data.mMaxValue > 0)
|
||||||
|
{
|
||||||
|
using (g.PushClip(0, 0, width, height))
|
||||||
|
{
|
||||||
|
using (g.PushColor(0xFF00FF00))
|
||||||
|
{
|
||||||
|
float prevY = 0;
|
||||||
|
|
||||||
|
for (int x < (int)width)
|
||||||
|
{
|
||||||
|
float sampleIdx = x * (data.mSamples.Count - 1) / width;
|
||||||
|
float value = data.Get(sampleIdx);
|
||||||
|
|
||||||
|
float y = (.)(height * (1.0 - (value / data.mMaxValue)) + 0.5);
|
||||||
|
|
||||||
|
if (x == 0)
|
||||||
|
g.FillRect(x, y, 1, 1);
|
||||||
|
else if (y > prevY)
|
||||||
|
g.FillRect(x, prevY, 1, y - prevY + 1);
|
||||||
|
else
|
||||||
|
g.FillRect(x, y, 1, prevY - y + 1);
|
||||||
|
|
||||||
|
prevY = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float labelX = 0;
|
||||||
|
float labelWidth = 0;
|
||||||
|
|
||||||
|
g.SetFont(DarkTheme.sDarkTheme.mSmallFont);
|
||||||
|
int[?] times = .(5, 15, 60, 5*60, 15*60);
|
||||||
|
int findIdx = 0;
|
||||||
|
int findTime = times[0];
|
||||||
|
double prevTime = mPanel.mCurTimeSecs;
|
||||||
|
|
||||||
|
bool wantOverTime = mOverDataTime != null;
|
||||||
|
|
||||||
|
bool drawLabels = width > GS!(240);
|
||||||
|
for (int idx = data.mSamples.Count - 1; idx >= 0; idx--)
|
||||||
|
{
|
||||||
|
double checkTime = timeData.mSamples[idx];
|
||||||
|
|
||||||
|
if ((wantOverTime) && (checkTime <= mOverDataTime))
|
||||||
|
{
|
||||||
|
wantOverTime = false;
|
||||||
|
|
||||||
|
//float x = idx + (float)((findTime - checkTime) / (prevTime - checkTime));
|
||||||
|
|
||||||
|
float overIdx = idx; // + (float)((mOverDataTime - checkTime) / (prevTime - checkTime));
|
||||||
|
|
||||||
|
float x = (int)((overIdx / (float)(data.mSamples.Count - 1)) * width);
|
||||||
|
|
||||||
|
double value = mOverDataValue.Value;
|
||||||
|
g.SetFont(DarkTheme.sDarkTheme.mSmallBoldFont);
|
||||||
|
|
||||||
|
int deltaSecs = (int)(mPanel.mCurTimeSecs - mOverDataTime.Value);
|
||||||
|
|
||||||
|
String drawStr = scope .();
|
||||||
|
ValToString(value, drawStr);
|
||||||
|
drawStr.AppendF(" at {}:{:00}", deltaSecs / 60, deltaSecs % 60);
|
||||||
|
|
||||||
|
labelWidth = g.mFont.GetWidth(drawStr);
|
||||||
|
|
||||||
|
labelX = Math.Clamp(x, labelWidth / 2, width - labelWidth / 2);
|
||||||
|
|
||||||
|
g.DrawString(drawStr, labelX, -GS!(19), .Centered);
|
||||||
|
|
||||||
|
using (g.PushColor(0x70FFFFFF))
|
||||||
|
g.FillRect(x, 0, 1, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
double timeDif = mPanel.mCurTimeSecs - checkTime;
|
||||||
|
if (timeDif >= findTime)
|
||||||
|
{
|
||||||
|
double prevTimeDif = mPanel.mCurTimeSecs - prevTime;
|
||||||
|
float addIdx = idx + (float)((timeDif - findTime) / (timeDif - prevTimeDif));
|
||||||
|
|
||||||
|
float x = (int)((addIdx / (data.mSamples.Count - 1)) * width);
|
||||||
|
|
||||||
|
using (g.PushColor(0xA0FFFFFF))
|
||||||
|
g.FillRect(x, 0, 1, height);
|
||||||
|
|
||||||
|
if (drawLabels)
|
||||||
|
{
|
||||||
|
uint32 color = 0xFFFFFFFF;
|
||||||
|
if (Math.Abs(x - labelX) < labelWidth / 2 + GS!(20))
|
||||||
|
color = 0x60FFFFFF;
|
||||||
|
using (g.PushColor(color))
|
||||||
|
g.DrawString(scope String()..AppendF("{}:{:00}", findTime / 60, findTime % 60), x + GS!(2), -GS!(20), .Centered);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (++findIdx >= times.Count)
|
||||||
|
break;
|
||||||
|
findTime = times[findIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
prevTime = checkTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw segments
|
||||||
|
|
||||||
|
double maxValue = mData.mMaxValue;
|
||||||
|
double segLog10 = log10(maxValue);
|
||||||
|
if (segLog10 > 0)
|
||||||
|
segLog10 = (int)(segLog10);
|
||||||
|
double segSize = Math.Pow(10, segLog10);
|
||||||
|
|
||||||
|
if (maxValue >= 1'000'000)
|
||||||
|
{
|
||||||
|
double segLog2 = log2(maxValue);
|
||||||
|
segLog2 = (int)(segLog2);
|
||||||
|
segSize = Math.Pow(2, segLog2);
|
||||||
|
}
|
||||||
|
|
||||||
|
double numSegs = maxValue / segSize;
|
||||||
|
|
||||||
|
|
||||||
|
if (numSegs < 2)
|
||||||
|
segSize /= 4;
|
||||||
|
else if (numSegs < 4)
|
||||||
|
segSize /= 2;
|
||||||
|
|
||||||
|
/*int kSize = 1024;
|
||||||
|
if (segSize >= kSize * kSize * kSize)
|
||||||
|
segSize = (int)(segSize / (kSize * kSize * kSize)) * (kSize * kSize * kSize);
|
||||||
|
else if (segSize >= kSize * kSize)
|
||||||
|
segSize = (int)(segSize / (kSize * kSize)) * (kSize * kSize);
|
||||||
|
else if (segSize >= kSize)
|
||||||
|
segSize = (int)(segSize / (kSize)) * (kSize);*/
|
||||||
|
|
||||||
|
numSegs = (int)(maxValue / segSize + 0.95f);
|
||||||
|
|
||||||
|
g.SetFont(DarkTheme.sDarkTheme.mSmallFont);
|
||||||
|
for (int segIdx = 1; segIdx < (int)numSegs; segIdx++)
|
||||||
|
{
|
||||||
|
bool drawLabels = width > GS!(120);
|
||||||
|
double segValue = segIdx * segSize;
|
||||||
|
|
||||||
|
float drawY = (int)((1 - segValue / maxValue) * (height - 1));
|
||||||
|
using (g.PushColor(0x40FFFFFF))
|
||||||
|
g.FillRect(0, drawY, width, 1);
|
||||||
|
if (drawLabels)
|
||||||
|
{
|
||||||
|
var labelStr = scope String();
|
||||||
|
ValToString(segValue, labelStr);
|
||||||
|
g.DrawString(labelStr, -xOfs, drawY - GS!(10), .Right, xOfs - GS!(4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect GetDataRect()
|
||||||
|
{
|
||||||
|
return .(GS!(80), GS!(20), mWidth - GS!(80) - 2, mHeight - GS!(20) - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void MouseLeave()
|
||||||
|
{
|
||||||
|
base.MouseLeave();
|
||||||
|
mOverDataTime = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void MouseMove(float x, float y)
|
||||||
|
{
|
||||||
|
base.MouseMove(x, y);
|
||||||
|
|
||||||
|
let dataRect = GetDataRect();
|
||||||
|
if ((x >= dataRect.mX) && (x < dataRect.Right) && (!mData.mSamples.IsEmpty))
|
||||||
|
{
|
||||||
|
float overDataIdx = (x - dataRect.mX) / (float)dataRect.mWidth * mData.mSamples.Count;
|
||||||
|
mOverDataTime = mTimes.Get(overDataIdx);
|
||||||
|
mOverDataValue = mData.Get(overDataIdx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mOverDataTime = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Draw(Graphics g)
|
||||||
|
{
|
||||||
|
base.Draw(g);
|
||||||
|
|
||||||
|
let dataRect = GetDataRect();
|
||||||
|
|
||||||
|
using (g.PushColor(0x20FFFFFF))
|
||||||
|
g.FillRect(0, 0, mWidth, mHeight);
|
||||||
|
|
||||||
|
DrawData(g, mData, mTimes, dataRect.mX, dataRect.mY, dataRect.mWidth, dataRect.mHeight);
|
||||||
|
|
||||||
|
g.SetFont(DarkTheme.sDarkTheme.mSmallBoldFont);
|
||||||
|
g.DrawString(mLabel, -GS!(0), -GS!(0), .Centered, dataRect.mX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region fields
|
||||||
|
ScrollableWidget mScrollableWidget;
|
||||||
|
Widget mContentWidget;
|
||||||
|
|
||||||
Stopwatch mSampleStopwatch = new .() ~ delete _;
|
Stopwatch mSampleStopwatch = new .() ~ delete _;
|
||||||
int mSampleKernelTime;
|
int mSampleCPUTime;
|
||||||
int mSampleUserTime;
|
double mCurTimeSecs;
|
||||||
|
|
||||||
|
const int cMaxSamples = 1024;
|
||||||
|
Data mRunningTime = new .(0) ~ delete _;
|
||||||
|
Data mUserTime = new .(6) ~ delete _;
|
||||||
|
Data mWorkingMem = new .(0) ~ delete _;
|
||||||
|
Data mVirtualMem = new .(0) ~ delete _;
|
||||||
|
Data mDbgAllocMem = new .(0) ~ delete _;
|
||||||
|
|
||||||
|
List<DataView> mDataViews = new List<DataView>() ~ delete _;
|
||||||
|
DbgAllocListView mDbgAllocListView;
|
||||||
|
DarkButton mRefreshButton;
|
||||||
|
|
||||||
public this()
|
public this()
|
||||||
{
|
{
|
||||||
mSampleStopwatch.Start();
|
mSampleStopwatch.Start();
|
||||||
|
/*for (int i < 10)
|
||||||
|
AddSample(mUserTime, .(i, i));*/
|
||||||
|
|
||||||
|
mScrollableWidget = new ScrollableWidget();
|
||||||
|
mScrollableWidget.InitScrollbars(false, true);
|
||||||
|
AddWidget(mScrollableWidget);
|
||||||
|
|
||||||
|
mContentWidget = new Widget();
|
||||||
|
mScrollableWidget.mScrollContentContainer.AddWidget(mContentWidget);
|
||||||
|
mScrollableWidget.mScrollContent = mContentWidget;
|
||||||
|
|
||||||
|
DataView dataView = new DataView("CPU");
|
||||||
|
dataView.mPanel = this;
|
||||||
|
dataView.mTimes = mRunningTime;
|
||||||
|
dataView.mData = mUserTime;
|
||||||
|
mContentWidget.AddWidget(dataView);
|
||||||
|
mDataViews.Add(dataView);
|
||||||
|
|
||||||
|
dataView = new DataView("VMem");
|
||||||
|
dataView.mPanel = this;
|
||||||
|
dataView.mTimes = mRunningTime;
|
||||||
|
dataView.mData = mVirtualMem;
|
||||||
|
mContentWidget.AddWidget(dataView);
|
||||||
|
mDataViews.Add(dataView);
|
||||||
|
|
||||||
|
dataView = new DataView("WkMem");
|
||||||
|
dataView.mPanel = this;
|
||||||
|
dataView.mTimes = mRunningTime;
|
||||||
|
dataView.mData = mWorkingMem;
|
||||||
|
mContentWidget.AddWidget(dataView);
|
||||||
|
mDataViews.Add(dataView);
|
||||||
|
|
||||||
|
dataView = new DataView("DbgAlloc");
|
||||||
|
dataView.mPanel = this;
|
||||||
|
dataView.mTimes = mRunningTime;
|
||||||
|
dataView.mData = mDbgAllocMem;
|
||||||
|
mContentWidget.AddWidget(dataView);
|
||||||
|
mDataViews.Add(dataView);
|
||||||
|
|
||||||
|
mRefreshButton = new DarkButton();
|
||||||
|
mRefreshButton.Label = "Get Debug Alloc Information";
|
||||||
|
mRefreshButton.mOnMouseClick.Add(new (mouseArgs) =>
|
||||||
|
{
|
||||||
|
if (gApp.mDebugger.mIsRunning)
|
||||||
|
{
|
||||||
|
var info = scope String();
|
||||||
|
//let sampler = Profiler.StartSampling().GetValueOrDefault();
|
||||||
|
gApp.mDebugger.GetDbgAllocInfo(info);
|
||||||
|
/*if (sampler != default)
|
||||||
|
sampler.Dispose();*/
|
||||||
|
|
||||||
|
PopulateDbgAllocInfo(info);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mContentWidget.AddWidget(mRefreshButton);
|
||||||
|
|
||||||
|
mDbgAllocListView = new DbgAllocListView();
|
||||||
|
|
||||||
|
ListViewColumn column = mDbgAllocListView.AddColumn(300, "Type");
|
||||||
|
column.mMinWidth = 100;
|
||||||
|
|
||||||
|
column = mDbgAllocListView.AddColumn(80, "Count");
|
||||||
|
column.mMinWidth = 60;
|
||||||
|
column = mDbgAllocListView.AddColumn(80, "Size");
|
||||||
|
column.mMinWidth = 60;
|
||||||
|
|
||||||
|
mDbgAllocListView.mOnItemMouseDown.Add(new => ListViewItemMouseDown);
|
||||||
|
mDbgAllocListView.mOnItemMouseClicked.Add(new => ListViewItemMouseClicked);
|
||||||
|
mDbgAllocListView.mOnKeyDown.Add(new => ListViewKeyDown_ShowMenu);
|
||||||
|
|
||||||
|
mContentWidget.AddWidget(mDbgAllocListView);
|
||||||
|
|
||||||
|
ResizeComponents();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update()
|
void Clear()
|
||||||
{
|
{
|
||||||
|
mSampleCPUTime = 0;
|
||||||
|
mCurTimeSecs = 0;
|
||||||
|
mUserTime.Clear();
|
||||||
|
mRunningTime.Clear();
|
||||||
|
mVirtualMem.Clear();
|
||||||
|
mWorkingMem.Clear();
|
||||||
|
mDbgAllocMem.Clear();
|
||||||
|
mDbgAllocListView.GetRoot().Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResizeComponents()
|
||||||
|
{
|
||||||
|
mScrollableWidget.Resize(0, 0, mWidth, mHeight);
|
||||||
|
|
||||||
|
float width = Math.Max(mScrollableWidget.mWidth - GS!(20), 0);
|
||||||
|
|
||||||
|
float dataViewWidth = Math.Max((width - GS!(24)) / 2, 100);
|
||||||
|
float dataViewHeight = (int)(dataViewWidth * 0.5f);
|
||||||
|
|
||||||
|
for (let dataView in mDataViews)
|
||||||
|
{
|
||||||
|
int col = @dataView.Index % 2;
|
||||||
|
int row = @dataView.Index / 2;
|
||||||
|
|
||||||
|
|
||||||
|
dataView.Resize(col * (dataViewWidth + GS!(8)) + GS!(8), row * (dataViewHeight + GS!(8)) + GS!(8), dataViewWidth, dataViewHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
float curY = dataViewHeight * 2 + GS!(24);
|
||||||
|
|
||||||
|
mRefreshButton.Resize(GS!(8), curY, GS!(240), GS!(20));
|
||||||
|
mDbgAllocListView.Resize(GS!(0), curY + GS!(20), Math.Max(width - GS!(0), 120), mDbgAllocListView.mScrollContent.mHeight + GS!(28));
|
||||||
|
|
||||||
|
mContentWidget.Resize(0, 0, width, curY + mDbgAllocListView.mScrollContent.mHeight + GS!(48));
|
||||||
|
mScrollableWidget.UpdateScrollbars();
|
||||||
|
mScrollableWidget.UpdateContentPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopulateDbgAllocInfo(String info)
|
||||||
|
{
|
||||||
|
//Debug.WriteLine(info);
|
||||||
|
|
||||||
|
mDbgAllocListView.GetRoot().Clear();
|
||||||
|
|
||||||
|
String totalLabel = "Total Debug Allocations";
|
||||||
|
|
||||||
|
int totalSize = 0;
|
||||||
|
int totalCount = 0;
|
||||||
|
|
||||||
|
DbgAllocListViewItem AddItem(StringView label, int allocCount, int allocSize)
|
||||||
|
{
|
||||||
|
var newItem = (DbgAllocListViewItem)mDbgAllocListView.GetRoot().CreateChildItem();
|
||||||
|
newItem.mAllocCount = allocCount;
|
||||||
|
newItem.mAllocSize = allocSize;
|
||||||
|
newItem.Label = label;
|
||||||
|
|
||||||
|
var subItem = newItem.GetOrCreateSubItem(1);
|
||||||
|
subItem.Label = scope String()..AppendF("{}", allocCount);
|
||||||
|
|
||||||
|
subItem = newItem.GetOrCreateSubItem(2);
|
||||||
|
subItem.Label = scope String()..AppendF("{}k", (allocSize + 1023)/1024);
|
||||||
|
return newItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let line in info.Split('\n'))
|
||||||
|
{
|
||||||
|
var elemItr = line.Split('\t');
|
||||||
|
switch (elemItr.GetNext().Value)
|
||||||
|
{
|
||||||
|
case "type":
|
||||||
|
int typeId = int.Parse(elemItr.GetNext().Value).Value;
|
||||||
|
StringView name = elemItr.GetNext().Value;
|
||||||
|
int allocCount = int.Parse(elemItr.GetNext().Value).Value;
|
||||||
|
int allocSize = int.Parse(elemItr.GetNext().Value).Value;
|
||||||
|
|
||||||
|
totalCount += allocCount;
|
||||||
|
totalSize += allocSize;
|
||||||
|
|
||||||
|
var newItem = AddItem(name, allocCount, allocSize);
|
||||||
|
newItem.mTypeId = typeId;
|
||||||
|
//newItem.MakeParent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddItem(totalLabel, totalCount, totalSize);
|
||||||
|
|
||||||
|
mDbgAllocListView.GetRoot().mChildItems.Sort(scope (lhs, rhs) =>
|
||||||
|
{
|
||||||
|
return ((DbgAllocListViewItem)rhs).mAllocSize <=> ((DbgAllocListViewItem)lhs).mAllocSize;
|
||||||
|
});
|
||||||
|
mDbgAllocListView.GetRoot().ResizeComponents(0);
|
||||||
|
mDbgAllocListView.mAutoFocus = true;
|
||||||
|
mDbgAllocListView.mOnLostFocus.Add(new (evt) =>
|
||||||
|
{
|
||||||
|
if (!mShowingRightClickMenu)
|
||||||
|
mDbgAllocListView.GetRoot().SelectItemExclusively(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
mDbgAllocListView.UpdateListSize();
|
||||||
|
ResizeComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Draw(Graphics g)
|
||||||
|
{
|
||||||
|
base.Draw(g);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateStats()
|
||||||
|
{
|
||||||
|
/*int addIdx = mUpdateCnt;
|
||||||
|
AddSample(mUserTime, .(addIdx, addIdx));*/
|
||||||
|
|
||||||
|
scope AutoBeefPerf("DiagnosticsPanel.UpdateStats");
|
||||||
|
|
||||||
String procInfo = scope .();
|
String procInfo = scope .();
|
||||||
gApp.mDebugger.GetProcessInfo(procInfo);
|
gApp.mDebugger.GetProcessInfo(procInfo);
|
||||||
|
|
||||||
|
if (gApp.mDebugger.IsPaused())
|
||||||
|
{
|
||||||
|
mSampleStopwatch.Restart();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (procInfo.IsEmpty)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gApp.mUpdateCnt % 5 != 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkDirty();
|
||||||
|
if (mSampleStopwatch.ElapsedMilliseconds < 10)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 5 Hz sample rate
|
||||||
|
/*if (elapsedTime < 100)
|
||||||
|
return;*/
|
||||||
|
mSampleStopwatch.Restart();
|
||||||
|
|
||||||
|
int runningTime = 0;
|
||||||
int virtualMem = 0;
|
int virtualMem = 0;
|
||||||
int workingMem = 0;
|
int workingMem = 0;
|
||||||
int kernelTime = 0;
|
int kernelTime = 0;
|
||||||
|
@ -39,12 +709,40 @@ namespace IDE.ui
|
||||||
{
|
{
|
||||||
case "WorkingMemory": workingMem = value;
|
case "WorkingMemory": workingMem = value;
|
||||||
case "VirtualMemory": virtualMem = value;
|
case "VirtualMemory": virtualMem = value;
|
||||||
|
case "RunningTime": runningTime = value;
|
||||||
case "KernelTime": kernelTime = value;
|
case "KernelTime": kernelTime = value;
|
||||||
case "UserTime": userTime = value;
|
case "UserTime": userTime = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cpuTime = kernelTime + userTime;
|
||||||
|
|
||||||
|
double newTimeSecs = runningTime / (double)(10*1000*1000);
|
||||||
|
double elapsedTime = newTimeSecs - mCurTimeSecs;
|
||||||
|
|
||||||
|
mCurTimeSecs = newTimeSecs;
|
||||||
|
|
||||||
|
mRunningTime.AddSample(mCurTimeSecs);
|
||||||
|
mUserTime.AddSample((cpuTime - mSampleCPUTime) * 100 / elapsedTime / 10000000.0f);
|
||||||
|
mWorkingMem.AddSample(workingMem);
|
||||||
|
mVirtualMem.AddSample(virtualMem);
|
||||||
|
mDbgAllocMem.AddSample(gApp.mDebugger.GetDbgAllocHeapSize());
|
||||||
|
|
||||||
|
mSampleCPUTime = cpuTime;
|
||||||
|
|
||||||
|
/*int addIdx = mUpdateCnt;
|
||||||
|
AddSample(mUserTime, .(addIdx, addIdx));*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Resize(float x, float y, float width, float height)
|
||||||
|
{
|
||||||
|
base.Resize(x, y, width, height);
|
||||||
|
ResizeComponents();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Serialize(StructuredData data)
|
public override void Serialize(StructuredData data)
|
||||||
|
|
|
@ -9874,15 +9874,10 @@ void BfModule::CurrentAddToConstHolder(BfIRValue& irVal)
|
||||||
newVals.push_back(newVal);
|
newVals.push_back(newVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
irVal = mCurTypeInstance->mConstHolder->CreateConstArray(constArray->mType, newVals);
|
irVal = mCurTypeInstance->GetOrCreateConstHolder()->CreateConstArray(constArray->mType, newVals);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (constant->mConstType == BfConstType_GlobalVar)
|
|
||||||
{
|
|
||||||
NOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto origConst = irVal;
|
auto origConst = irVal;
|
||||||
if ((constant->mConstType == BfConstType_BitCast) || (constant->mConstType == BfConstType_BitCastNull))
|
if ((constant->mConstType == BfConstType_BitCast) || (constant->mConstType == BfConstType_BitCastNull))
|
||||||
{
|
{
|
||||||
|
|
|
@ -732,10 +732,19 @@ DbgExprEvaluator::DbgExprEvaluator(WinDebugger* winDebugger, DbgModule* dbgModul
|
||||||
mCapturingChildRef = true;
|
mCapturingChildRef = true;
|
||||||
mPassInstance = passInstance;
|
mPassInstance = passInstance;
|
||||||
mDebugger = winDebugger;
|
mDebugger = winDebugger;
|
||||||
mLanguage = DbgLanguage_NotSet;
|
mLanguage = DbgLanguage_NotSet;
|
||||||
mDebugTarget = dbgModule->mDebugTarget;
|
|
||||||
mOrigDbgModule = dbgModule;
|
mOrigDbgModule = dbgModule;
|
||||||
mDbgModule = dbgModule->GetLinkedModule();
|
if (dbgModule != NULL)
|
||||||
|
{
|
||||||
|
mDebugTarget = dbgModule->mDebugTarget;
|
||||||
|
mDbgModule = dbgModule->GetLinkedModule();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mDebugTarget = NULL;
|
||||||
|
mDbgModule = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
mDbgCompileUnit = NULL;
|
mDbgCompileUnit = NULL;
|
||||||
mExplicitThisExpr = NULL;
|
mExplicitThisExpr = NULL;
|
||||||
mExpectingType = NULL;
|
mExpectingType = NULL;
|
||||||
|
@ -1125,12 +1134,14 @@ DbgTypedValue DbgExprEvaluator::GetBeefTypeById(int typeId)
|
||||||
if (mDebugTarget->mTargetBinary == NULL)
|
if (mDebugTarget->mTargetBinary == NULL)
|
||||||
return DbgTypedValue();
|
return DbgTypedValue();
|
||||||
|
|
||||||
|
mDebugTarget->mTargetBinary->ParseTypeData();
|
||||||
auto typeTypeEntry = mDebugTarget->mTargetBinary->FindType("System.Type", DbgLanguage_Beef);
|
auto typeTypeEntry = mDebugTarget->mTargetBinary->FindType("System.Type", DbgLanguage_Beef);
|
||||||
if ((typeTypeEntry == NULL) || (typeTypeEntry->mValue == NULL))
|
if ((typeTypeEntry == NULL) || (typeTypeEntry->mValue == NULL))
|
||||||
return DbgTypedValue();
|
return DbgTypedValue();
|
||||||
|
|
||||||
auto typeType = typeTypeEntry->mValue;
|
auto typeType = typeTypeEntry->mValue;
|
||||||
mDbgModule->PopulateTypeGlobals(typeType);
|
if (typeType->mNeedsGlobalsPopulated)
|
||||||
|
typeType->mCompileUnit->mDbgModule->PopulateTypeGlobals(typeType);
|
||||||
for (auto member : typeType->mMemberList)
|
for (auto member : typeType->mMemberList)
|
||||||
{
|
{
|
||||||
if ((member->mIsStatic) && (member->mName != NULL) && (strcmp(member->mName, "sTypes") == 0) && (member->mLocationData != NULL))
|
if ((member->mIsStatic) && (member->mName != NULL) && (strcmp(member->mName, "sTypes") == 0) && (member->mLocationData != NULL))
|
||||||
|
@ -1232,6 +1243,12 @@ void DbgExprEvaluator::BeefTypeToString(const DbgTypedValue& val, String& outStr
|
||||||
_TypeCode mElementType;
|
_TypeCode mElementType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _SizedArrayType : _Type
|
||||||
|
{
|
||||||
|
_TypeId mElementType;
|
||||||
|
int32 mElementCount;
|
||||||
|
};
|
||||||
|
|
||||||
struct _String
|
struct _String
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -1267,16 +1284,27 @@ void DbgExprEvaluator::BeefTypeToString(const DbgTypedValue& val, String& outStr
|
||||||
uint8 mInterfaceCount;
|
uint8 mInterfaceCount;
|
||||||
int16 mMethodDataCount;
|
int16 mMethodDataCount;
|
||||||
int16 mPropertyDataCount;
|
int16 mPropertyDataCount;
|
||||||
int16 mFieldDataCount;
|
int16 mFieldDataCount;
|
||||||
int16 mConstructorDataCount;
|
|
||||||
|
|
||||||
void* mInterfaceDataPtr;
|
void* mInterfaceDataPtr;
|
||||||
_MethodData* mMethodDataPtr;
|
_MethodData* mMethodDataPtr;
|
||||||
void* mPropertyDataPtr;
|
void* mPropertyDataPtr;
|
||||||
_FieldData* mFieldDataPtr;
|
_FieldData* mFieldDataPtr;
|
||||||
void* mConstructorDataPtr;
|
|
||||||
void** mCustomAttrDataPtr;
|
void** mCustomAttrDataPtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _SpecializedGenericType : _TypeInstance
|
||||||
|
{
|
||||||
|
_TypeId mUnspecializedType;
|
||||||
|
_TypeId* mResolvedTypeRefs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _ArrayType : _SpecializedGenericType
|
||||||
|
{
|
||||||
|
int32 mElementSize;
|
||||||
|
uint8 mRank;
|
||||||
|
uint8 mElemensDataOffset;
|
||||||
|
};
|
||||||
|
|
||||||
int typeIdSize = sizeof(_TypeId);
|
int typeIdSize = sizeof(_TypeId);
|
||||||
int ptrSize = (int)sizeof(addr_target);
|
int ptrSize = (int)sizeof(addr_target);
|
||||||
|
@ -1284,12 +1312,54 @@ void DbgExprEvaluator::BeefTypeToString(const DbgTypedValue& val, String& outStr
|
||||||
int typeSize = sizeof(_Type);
|
int typeSize = sizeof(_Type);
|
||||||
|
|
||||||
int typeInstanceSize = objectSize + sizeof(_TypeInstance);
|
int typeInstanceSize = objectSize + sizeof(_TypeInstance);
|
||||||
|
|
||||||
auto addr = useVal.mSrcAddress;
|
auto addr = useVal.mSrcAddress;
|
||||||
auto typeAddr = addr + objectSize;
|
auto typeAddr = addr + objectSize;
|
||||||
|
|
||||||
_TypeFlags typeFlags = mDebugger->ReadMemory<_TypeFlags>(typeAddr + offsetof(_Type, mTypeFlags));
|
_TypeFlags typeFlags = mDebugger->ReadMemory<_TypeFlags>(typeAddr + offsetof(_Type, mTypeFlags));
|
||||||
if (((typeFlags & BfTypeFlags_Struct) != 0) || ((typeFlags & BfTypeFlags_TypedPrimitive) != 0) || ((typeFlags & BfTypeFlags_Object) != 0))
|
|
||||||
|
if ((typeFlags & BfTypeFlags_Array) != 0)
|
||||||
|
{
|
||||||
|
_TypeId unspecializedTypeId = mDebugger->ReadMemory<_TypeId>(typeAddr + offsetof(_SpecializedGenericType, mUnspecializedType));
|
||||||
|
addr_target elementsArrayAddr = mDebugger->ReadMemory<addr_target>(typeAddr + offsetof(_SpecializedGenericType, mResolvedTypeRefs));
|
||||||
|
_TypeId elementTypeId = mDebugger->ReadMemory<_TypeId>(elementsArrayAddr);
|
||||||
|
|
||||||
|
auto elementType = GetBeefTypeById(elementTypeId);
|
||||||
|
BeefTypeToString(elementType, outStr);
|
||||||
|
|
||||||
|
outStr += "[";
|
||||||
|
int rank = mDebugger->ReadMemory<uint8>(typeAddr + offsetof(_ArrayType, mRank));
|
||||||
|
for (int commaIdx = 0; commaIdx < rank - 1; commaIdx++)
|
||||||
|
outStr += ",";
|
||||||
|
outStr += "]";
|
||||||
|
}
|
||||||
|
else if ((typeFlags & BfTypeFlags_Pointer) != 0)
|
||||||
|
{
|
||||||
|
_TypeId elementTypeId = mDebugger->ReadMemory<_TypeId>(typeAddr + offsetof(_PointerType, mElementType));
|
||||||
|
auto elementType = GetBeefTypeById(elementTypeId);
|
||||||
|
BeefTypeToString(elementType, outStr);
|
||||||
|
}
|
||||||
|
else if ((typeFlags & BfTypeFlags_Delegate) != 0)
|
||||||
|
{
|
||||||
|
outStr += "delegate";
|
||||||
|
}
|
||||||
|
else if ((typeFlags & BfTypeFlags_Function) != 0)
|
||||||
|
{
|
||||||
|
outStr += "function";
|
||||||
|
}
|
||||||
|
// else if ((typeFlags & BfTypeFlags_Tuple) != 0)
|
||||||
|
// {
|
||||||
|
// outStr += "function";
|
||||||
|
// }
|
||||||
|
else if ((typeFlags & BfTypeFlags_SizedArray) != 0)
|
||||||
|
{
|
||||||
|
_TypeId elementTypeId = mDebugger->ReadMemory<_TypeId>(typeAddr + objectSize + offsetof(_SizedArrayType, mElementType));
|
||||||
|
auto elementType = GetBeefTypeById(elementTypeId);
|
||||||
|
BeefTypeToString(elementType, outStr);
|
||||||
|
int elementCount = mDebugger->ReadMemory<int32>(typeAddr + objectSize + offsetof(_SizedArrayType, mElementCount));
|
||||||
|
outStr += StrFormat("[%d]", elementCount);
|
||||||
|
}
|
||||||
|
else if (((typeFlags & BfTypeFlags_Struct) != 0) || ((typeFlags & BfTypeFlags_TypedPrimitive) != 0) || ((typeFlags & BfTypeFlags_Object) != 0))
|
||||||
{
|
{
|
||||||
addr_target namePtr = mDebugger->ReadMemory<addr_target>(typeAddr + offsetof(_TypeInstance, mName));
|
addr_target namePtr = mDebugger->ReadMemory<addr_target>(typeAddr + offsetof(_TypeInstance, mName));
|
||||||
addr_target namespacePtr = mDebugger->ReadMemory<addr_target>(typeAddr + offsetof(_TypeInstance, mNamespace));
|
addr_target namespacePtr = mDebugger->ReadMemory<addr_target>(typeAddr + offsetof(_TypeInstance, mNamespace));
|
||||||
|
|
|
@ -1535,6 +1535,22 @@ BF_EXPORT void BF_CALLTYPE Debugger_InitiateHotResolve(int flags)
|
||||||
gDebugger->InitiateHotResolve((DbgHotResolveFlags)flags);
|
gDebugger->InitiateHotResolve((DbgHotResolveFlags)flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BF_EXPORT intptr BF_CALLTYPE Debugger_GetDbgAllocHeapSize()
|
||||||
|
{
|
||||||
|
AutoCrit autoCrit(gDebugManager->mCritSect);
|
||||||
|
return gDebugger->GetDbgAllocHeapSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetDbgAllocInfo()
|
||||||
|
{
|
||||||
|
AutoCrit autoCrit(gDebugManager->mCritSect);
|
||||||
|
|
||||||
|
String& outString = *gTLStrReturn.Get();
|
||||||
|
outString = gDebugger->GetDbgAllocInfo();
|
||||||
|
return outString.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
BF_EXPORT const char* BF_CALLTYPE Debugger_GetHotResolveData(uint8* outTypeData, int* outTypeDataSize)
|
BF_EXPORT const char* BF_CALLTYPE Debugger_GetHotResolveData(uint8* outTypeData, int* outTypeDataSize)
|
||||||
{
|
{
|
||||||
AutoCrit autoCrit(gDebugManager->mCritSect);
|
AutoCrit autoCrit(gDebugManager->mCritSect);
|
||||||
|
@ -1554,7 +1570,10 @@ BF_EXPORT const char* BF_CALLTYPE Debugger_GetHotResolveData(uint8* outTypeData,
|
||||||
|
|
||||||
*outTypeDataSize = dataSize;
|
*outTypeDataSize = dataSize;
|
||||||
if (dataSize > 0)
|
if (dataSize > 0)
|
||||||
memcpy(outTypeData, &gDebugger->mHotResolveData->mTypeData[0], dataSize);
|
{
|
||||||
|
for (int i = 0; i < dataSize; i++)
|
||||||
|
outTypeData[i] = (gDebugger->mHotResolveData->mTypeData[i].mCount > 0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
String& outString = *gTLStrReturn.Get();
|
String& outString = *gTLStrReturn.Get();
|
||||||
outString.Clear();
|
outString.Clear();
|
||||||
|
|
|
@ -215,7 +215,20 @@ public:
|
||||||
class DbgHotResolveData
|
class DbgHotResolveData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Array<uint8> mTypeData;
|
struct TypeData
|
||||||
|
{
|
||||||
|
intptr mCount;
|
||||||
|
intptr mSize;
|
||||||
|
|
||||||
|
TypeData()
|
||||||
|
{
|
||||||
|
mCount = 0;
|
||||||
|
mSize = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
Array<TypeData> mTypeData;
|
||||||
Beefy::HashSet<String> mBeefCallStackEntries;
|
Beefy::HashSet<String> mBeefCallStackEntries;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -248,6 +261,8 @@ public:
|
||||||
virtual void Run() = 0;
|
virtual void Run() = 0;
|
||||||
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) = 0;
|
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) = 0;
|
||||||
virtual void InitiateHotResolve(DbgHotResolveFlags flags) = 0;
|
virtual void InitiateHotResolve(DbgHotResolveFlags flags) = 0;
|
||||||
|
virtual intptr GetDbgAllocHeapSize() = 0;
|
||||||
|
virtual String GetDbgAllocInfo() = 0;
|
||||||
virtual void Update() = 0;
|
virtual void Update() = 0;
|
||||||
virtual void ContinueDebugEvent() = 0;
|
virtual void ContinueDebugEvent() = 0;
|
||||||
virtual void ForegroundTarget() = 0;
|
virtual void ForegroundTarget() = 0;
|
||||||
|
|
|
@ -169,11 +169,15 @@ void DbgHotScanner::ScanSpan(TCFake::Span* span, int expectedStartPage, int memK
|
||||||
elementSize = spanSize;
|
elementSize = spanSize;
|
||||||
//BF_LOGASSERT(elementSize >= sizeof(bf::System::Object));
|
//BF_LOGASSERT(elementSize >= sizeof(bf::System::Object));
|
||||||
|
|
||||||
auto _MarkTypeUsed = [&](int typeId)
|
auto _MarkTypeUsed = [&](int typeId, intptr size)
|
||||||
{
|
{
|
||||||
|
if (typeId < 0)
|
||||||
|
return;
|
||||||
while (mDebugger->mHotResolveData->mTypeData.size() <= typeId)
|
while (mDebugger->mHotResolveData->mTypeData.size() <= typeId)
|
||||||
mDebugger->mHotResolveData->mTypeData.Add(0);
|
mDebugger->mHotResolveData->mTypeData.Add(DbgHotResolveData::TypeData());
|
||||||
mDebugger->mHotResolveData->mTypeData[typeId] = 1;
|
auto& typeData = mDebugger->mHotResolveData->mTypeData[typeId];
|
||||||
|
typeData.mSize += size;
|
||||||
|
typeData.mCount++;
|
||||||
};
|
};
|
||||||
|
|
||||||
int objectSize = ((mDbgGCData.mDbgFlags & BfRtFlags_ObjectHasDebugFlags) != 0) ? sizeof(addr_target)*2 : sizeof(addr_target);
|
int objectSize = ((mDbgGCData.mDbgFlags & BfRtFlags_ObjectHasDebugFlags) != 0) ? sizeof(addr_target)*2 : sizeof(addr_target);
|
||||||
|
@ -206,36 +210,68 @@ void DbgHotScanner::ScanSpan(TCFake::Span* span, int expectedStartPage, int memK
|
||||||
if ((mDbgGCData.mDbgFlags & BfRtFlags_ObjectHasDebugFlags) != 0)
|
if ((mDbgGCData.mDbgFlags & BfRtFlags_ObjectHasDebugFlags) != 0)
|
||||||
classVDataAddr = classVDataAddr & ~0xFF;
|
classVDataAddr = classVDataAddr & ~0xFF;
|
||||||
}
|
}
|
||||||
else if (mFoundRawAllocDataAddrs.Add(rawAllocDataAddr))
|
else
|
||||||
{
|
{
|
||||||
Fake_DbgRawAllocData rawAllocData = mDebugger->ReadMemory<Fake_DbgRawAllocData>(rawAllocDataAddr);
|
|
||||||
if ((rawAllocData.mType != NULL) && (mFoundTypeAddrs.Add(rawAllocData.mType)))
|
int* rawTypeIdPtr = NULL;
|
||||||
|
if (mFoundRawAllocDataAddrs.TryAdd(rawAllocDataAddr, NULL, &rawTypeIdPtr))
|
||||||
{
|
{
|
||||||
Fake_Type_Data typeData;
|
*rawTypeIdPtr = -1;
|
||||||
if (mDebugger->ReadMemory(rawAllocData.mType + objectSize, sizeof(typeData), &typeData))
|
Fake_DbgRawAllocData rawAllocData = mDebugger->ReadMemory<Fake_DbgRawAllocData>(rawAllocDataAddr);
|
||||||
_MarkTypeUsed(typeData.mTypeId);
|
if (rawAllocData.mType != NULL)
|
||||||
|
{
|
||||||
|
int* typeAddrIdPtr = NULL;
|
||||||
|
if (mFoundTypeAddrs.TryAdd(rawAllocData.mType, NULL, &typeAddrIdPtr))
|
||||||
|
{
|
||||||
|
*typeAddrIdPtr = -1;
|
||||||
|
Fake_Type_Data typeData;
|
||||||
|
if (mDebugger->ReadMemory(rawAllocData.mType + objectSize, sizeof(typeData), &typeData))
|
||||||
|
{
|
||||||
|
*typeAddrIdPtr = typeData.mTypeId;
|
||||||
|
*rawTypeIdPtr = typeData.mTypeId;
|
||||||
|
_MarkTypeUsed(typeData.mTypeId, elementSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_MarkTypeUsed(*typeAddrIdPtr, elementSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_MarkTypeUsed(*rawTypeIdPtr, elementSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((classVDataAddr != 0) && (mFoundClassVDataAddrs.Add(classVDataAddr)))
|
if (classVDataAddr != 0)
|
||||||
{
|
{
|
||||||
addr_target typeAddr = mDebugger->ReadMemory<addr_target>(classVDataAddr);
|
int* typeIdPtr = NULL;
|
||||||
Fake_Type_Data typeData;
|
if (mFoundClassVDataAddrs.TryAdd(classVDataAddr, NULL, &typeIdPtr))
|
||||||
mDebugger->ReadMemory(typeAddr + objectSize, sizeof(typeData), &typeData);
|
|
||||||
|
|
||||||
_MarkTypeUsed(typeData.mTypeId);
|
|
||||||
if ((typeData.mTypeFlags & BfTypeFlags_Delegate) != 0)
|
|
||||||
{
|
{
|
||||||
Fake_Delegate_Data* dlg = (Fake_Delegate_Data*)((uint8*)spanPtr + objectSize);
|
addr_target typeAddr = mDebugger->ReadMemory<addr_target>(classVDataAddr);
|
||||||
if (mFoundFuncPtrs.Add(dlg->mFuncPtr))
|
Fake_Type_Data typeData;
|
||||||
|
mDebugger->ReadMemory(typeAddr + objectSize, sizeof(typeData), &typeData);
|
||||||
|
|
||||||
|
*typeIdPtr = typeData.mTypeId;
|
||||||
|
_MarkTypeUsed(typeData.mTypeId, elementSize);
|
||||||
|
if ((typeData.mTypeFlags & BfTypeFlags_Delegate) != 0)
|
||||||
{
|
{
|
||||||
auto subProgram = mDebugger->mDebugTarget->FindSubProgram(dlg->mFuncPtr, DbgOnDemandKind_None);
|
Fake_Delegate_Data* dlg = (Fake_Delegate_Data*)((uint8*)spanPtr + objectSize);
|
||||||
if ((subProgram != NULL) && (subProgram->GetLanguage() == DbgLanguage_Beef))
|
if (mFoundFuncPtrs.Add(dlg->mFuncPtr))
|
||||||
AddSubProgram(subProgram, true, "D ");
|
{
|
||||||
|
auto subProgram = mDebugger->mDebugTarget->FindSubProgram(dlg->mFuncPtr, DbgOnDemandKind_None);
|
||||||
|
if ((subProgram != NULL) && (subProgram->GetLanguage() == DbgLanguage_Beef))
|
||||||
|
AddSubProgram(subProgram, true, "D ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_MarkTypeUsed(*typeIdPtr, elementSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spanPtr = (void*)((intptr)spanPtr + elementSize);
|
spanPtr = (void*)((intptr)spanPtr + elementSize);
|
||||||
|
|
|
@ -84,9 +84,9 @@ class DbgHotScanner
|
||||||
public:
|
public:
|
||||||
WinDebugger* mDebugger;
|
WinDebugger* mDebugger;
|
||||||
DbgGCData mDbgGCData;
|
DbgGCData mDbgGCData;
|
||||||
Beefy::HashSet<addr_target> mFoundClassVDataAddrs;
|
Beefy::Dictionary<addr_target, int> mFoundClassVDataAddrs;
|
||||||
Beefy::HashSet<addr_target> mFoundRawAllocDataAddrs;
|
Beefy::Dictionary<addr_target, int> mFoundRawAllocDataAddrs;
|
||||||
Beefy::HashSet<addr_target> mFoundTypeAddrs;
|
Beefy::Dictionary<addr_target, int> mFoundTypeAddrs;
|
||||||
Beefy::HashSet<addr_target> mFoundFuncPtrs;
|
Beefy::HashSet<addr_target> mFoundFuncPtrs;
|
||||||
|
|
||||||
#ifdef BF_DBG_32
|
#ifdef BF_DBG_32
|
||||||
|
|
|
@ -523,6 +523,7 @@ WinDebugger::WinDebugger(DebugManager* debugManager) : mDbgSymSrv(this)
|
||||||
mDbgProcessHandle = 0;
|
mDbgProcessHandle = 0;
|
||||||
mDbgThreadHandle = 0;
|
mDbgThreadHandle = 0;
|
||||||
mDbgProcessId = 0;
|
mDbgProcessId = 0;
|
||||||
|
mDbgHeapData = NULL;
|
||||||
mIsPartialCallStack = true;
|
mIsPartialCallStack = true;
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
|
@ -1174,6 +1175,76 @@ void WinDebugger::InitiateHotResolve(DbgHotResolveFlags flags)
|
||||||
delete hotScanner;
|
delete hotScanner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intptr WinDebugger::GetDbgAllocHeapSize()
|
||||||
|
{
|
||||||
|
if (mDbgHeapData == NULL)
|
||||||
|
{
|
||||||
|
Beefy::String memName = StrFormat("BFGC_stats_%d", mProcessInfo.dwProcessId);
|
||||||
|
|
||||||
|
mDbgHeapData = new WinDbgHeapData();
|
||||||
|
mDbgHeapData->mFileMapping = ::OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, memName.c_str());
|
||||||
|
if (mDbgHeapData->mFileMapping == 0)
|
||||||
|
{
|
||||||
|
delete mDbgHeapData;
|
||||||
|
mDbgHeapData = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDbgHeapData->mStats = (WinDbgHeapData::Stats*)MapViewOfFile(mDbgHeapData->mFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(WinDbgHeapData::Stats));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDbgHeapData->mStats == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return mDbgHeapData->mStats->mHeapSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
String WinDebugger::GetDbgAllocInfo()
|
||||||
|
{
|
||||||
|
AutoCrit autoCrit(mDebugManager->mCritSect);
|
||||||
|
|
||||||
|
for (auto threadInfo : mThreadList)
|
||||||
|
::SuspendThread(threadInfo->mHThread);
|
||||||
|
|
||||||
|
delete mHotResolveData;
|
||||||
|
mHotResolveData = NULL;
|
||||||
|
|
||||||
|
mHotResolveData = new DbgHotResolveData();
|
||||||
|
DbgHotScanner* hotScanner = new DbgHotScanner(this);
|
||||||
|
hotScanner->Scan(DbgHotResolveFlag_Allocations);
|
||||||
|
delete hotScanner;
|
||||||
|
|
||||||
|
String result;
|
||||||
|
|
||||||
|
if (mHotResolveData != NULL)
|
||||||
|
{
|
||||||
|
DbgExprEvaluator exprEvaluator(this, NULL, NULL, -1, -1);
|
||||||
|
exprEvaluator.mDebugTarget = mDebugTarget;
|
||||||
|
|
||||||
|
String typeName;
|
||||||
|
|
||||||
|
result += ":types\n";
|
||||||
|
|
||||||
|
for (int typeId = 0; typeId < mHotResolveData->mTypeData.size(); typeId++)
|
||||||
|
{
|
||||||
|
auto& typeData = mHotResolveData->mTypeData[typeId];
|
||||||
|
if (typeData.mCount > 0)
|
||||||
|
{
|
||||||
|
auto type = exprEvaluator.GetBeefTypeById(typeId);
|
||||||
|
typeName.Clear();
|
||||||
|
exprEvaluator.BeefTypeToString(type, typeName);
|
||||||
|
|
||||||
|
result += StrFormat("type\t%d\t%s\t%lld\t%lld\n", typeId, typeName.c_str(), typeData.mCount, typeData.mSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto threadInfo : mThreadList)
|
||||||
|
::ResumeThread(threadInfo->mHThread);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock)
|
bool WinDebugger::DoOpenFile(const StringImpl& fileName, const StringImpl& args, const StringImpl& workingDir, const Array<uint8>& envBlock)
|
||||||
{
|
{
|
||||||
BP_ZONE("WinDebugger::DoOpenFile");
|
BP_ZONE("WinDebugger::DoOpenFile");
|
||||||
|
@ -1398,6 +1469,8 @@ void WinDebugger::Detach()
|
||||||
|
|
||||||
mDbgAttachFlags = BfDbgAttachFlag_None;
|
mDbgAttachFlags = BfDbgAttachFlag_None;
|
||||||
mDbgProcessId = 0;
|
mDbgProcessId = 0;
|
||||||
|
delete mDbgHeapData;
|
||||||
|
mDbgHeapData = NULL;
|
||||||
mDbgProcessHandle = 0;
|
mDbgProcessHandle = 0;
|
||||||
ClearCallStack();
|
ClearCallStack();
|
||||||
mWantsDebugContinue = false;
|
mWantsDebugContinue = false;
|
||||||
|
@ -10208,21 +10281,27 @@ String WinDebugger::GetProcessInfo()
|
||||||
if ((mActiveThread == NULL) && (!mIsRunning))
|
if ((mActiveThread == NULL) && (!mIsRunning))
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
|
SYSTEM_INFO sysinfo = { 0 };
|
||||||
|
GetSystemInfo(&sysinfo);
|
||||||
|
|
||||||
FILETIME creationTime = { 0 };
|
FILETIME creationTime = { 0 };
|
||||||
FILETIME exitTime = { 0 };
|
FILETIME exitTime = { 0 };
|
||||||
FILETIME kernelTime = { 0 };
|
FILETIME kernelTime = { 0 };
|
||||||
FILETIME userTime = { 0 };
|
FILETIME userTime = { 0 };
|
||||||
GetProcessTimes(mProcessInfo.hProcess, &creationTime, &exitTime, &kernelTime, &userTime);
|
::GetProcessTimes(mProcessInfo.hProcess, &creationTime, &exitTime, &kernelTime, &userTime);
|
||||||
|
|
||||||
String retStr;
|
String retStr;
|
||||||
PROCESS_MEMORY_COUNTERS memInfo = { 0 };
|
PROCESS_MEMORY_COUNTERS memInfo = { 0 };
|
||||||
GetProcessMemoryInfo(mProcessInfo.hProcess, &memInfo, sizeof(PROCESS_MEMORY_COUNTERS));
|
::GetProcessMemoryInfo(mProcessInfo.hProcess, &memInfo, sizeof(PROCESS_MEMORY_COUNTERS));
|
||||||
|
|
||||||
|
FILETIME currentTime = { 0 };
|
||||||
|
::GetSystemTimeAsFileTime(¤tTime);
|
||||||
|
|
||||||
retStr += StrFormat("VirtualMemory\t%d\n", memInfo.PagefileUsage);
|
retStr += StrFormat("VirtualMemory\t%d\n", memInfo.PagefileUsage);
|
||||||
retStr += StrFormat("WorkingMemory\t%d\n", memInfo.WorkingSetSize);
|
retStr += StrFormat("WorkingMemory\t%d\n", memInfo.WorkingSetSize);
|
||||||
retStr += StrFormat("RunningTime\t%lld\n", *(int64*)&creationTime);
|
retStr += StrFormat("RunningTime\t%lld\n", *(int64*)¤tTime - *(int64*)&creationTime);
|
||||||
retStr += StrFormat("KernelTime\t%lld\n", *(int64*)&kernelTime);
|
retStr += StrFormat("KernelTime\t%lld\n", *(int64*)&kernelTime / sysinfo.dwNumberOfProcessors);
|
||||||
retStr += StrFormat("UserTime\t%lld\n", *(int64*)&userTime);
|
retStr += StrFormat("UserTime\t%lld\n", *(int64*)&userTime / sysinfo.dwNumberOfProcessors);
|
||||||
|
|
||||||
return retStr;
|
return retStr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -384,6 +384,31 @@ struct WinHotThreadState
|
||||||
int mThreadId;
|
int mThreadId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WinDbgHeapData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Stats
|
||||||
|
{
|
||||||
|
intptr mHeapSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
HANDLE mFileMapping;
|
||||||
|
Stats* mStats;
|
||||||
|
|
||||||
|
WinDbgHeapData()
|
||||||
|
{
|
||||||
|
mFileMapping = 0;
|
||||||
|
mStats = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
~WinDbgHeapData()
|
||||||
|
{
|
||||||
|
if (mFileMapping != 0)
|
||||||
|
::CloseHandle(mFileMapping);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class WinDebugger : public Debugger
|
class WinDebugger : public Debugger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -407,6 +432,7 @@ public:
|
||||||
CPU* mCPU;
|
CPU* mCPU;
|
||||||
PROCESS_INFORMATION mProcessInfo;
|
PROCESS_INFORMATION mProcessInfo;
|
||||||
BfDbgAttachFlags mDbgAttachFlags;
|
BfDbgAttachFlags mDbgAttachFlags;
|
||||||
|
WinDbgHeapData* mDbgHeapData;
|
||||||
DWORD mDbgProcessId;
|
DWORD mDbgProcessId;
|
||||||
HANDLE mDbgProcessHandle;
|
HANDLE mDbgProcessHandle;
|
||||||
HANDLE mDbgThreadHandle;
|
HANDLE mDbgThreadHandle;
|
||||||
|
@ -593,6 +619,8 @@ public:
|
||||||
virtual void Run() override;
|
virtual void Run() override;
|
||||||
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) override;
|
virtual void HotLoad(const Array<String>& objectFiles, int hotIdx) override;
|
||||||
virtual void InitiateHotResolve(DbgHotResolveFlags flags) override;
|
virtual void InitiateHotResolve(DbgHotResolveFlags flags) override;
|
||||||
|
virtual intptr GetDbgAllocHeapSize() override;
|
||||||
|
virtual String GetDbgAllocInfo() override;
|
||||||
virtual void Update() override;
|
virtual void Update() override;
|
||||||
virtual void ContinueDebugEvent() override;
|
virtual void ContinueDebugEvent() override;
|
||||||
virtual void ForegroundTarget() override;
|
virtual void ForegroundTarget() override;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue