mirror of https://github.com/buggins/dlangide.git
DMD profiler trace.log viewer, part 1 - #344
This commit is contained in:
parent
645090ec31
commit
f620e3e286
|
@ -71,9 +71,9 @@
|
|||
<doXGeneration>1</doXGeneration>
|
||||
<xfilename>$(IntDir)\$(TargetName).json</xfilename>
|
||||
<debuglevel>0</debuglevel>
|
||||
<debugids>KeyInput DCD</debugids>
|
||||
<debugids>DCD</debugids>
|
||||
<versionlevel>0</versionlevel>
|
||||
<versionids>EmbedStandardResources NO_OPENGL USE_FREETYPE</versionids>
|
||||
<versionids>EmbedStandardResources USE_FREETYPE NO_OPENGL</versionids>
|
||||
<dump_source>0</dump_source>
|
||||
<mapverbosity>0</mapverbosity>
|
||||
<createImplib>0</createImplib>
|
||||
|
@ -176,7 +176,7 @@
|
|||
<debuglevel>0</debuglevel>
|
||||
<debugids />
|
||||
<versionlevel>0</versionlevel>
|
||||
<versionids>EmbedStandardResources</versionids>
|
||||
<versionids>EmbedStandardResources NO_OPENGL USE_FREETYPE</versionids>
|
||||
<dump_source>0</dump_source>
|
||||
<mapverbosity>0</mapverbosity>
|
||||
<createImplib>0</createImplib>
|
||||
|
@ -214,7 +214,7 @@
|
|||
<multiobj>0</multiobj>
|
||||
<singleFileCompilation>0</singleFileCompilation>
|
||||
<oneobj>0</oneobj>
|
||||
<mscoff>1</mscoff>
|
||||
<mscoff>0</mscoff>
|
||||
<trace>0</trace>
|
||||
<quiet>0</quiet>
|
||||
<verbose>0</verbose>
|
||||
|
@ -277,9 +277,9 @@
|
|||
<doXGeneration>1</doXGeneration>
|
||||
<xfilename>$(IntDir)\$(TargetName).json</xfilename>
|
||||
<debuglevel>0</debuglevel>
|
||||
<debugids>KeyInput DCD</debugids>
|
||||
<debugids>DCD</debugids>
|
||||
<versionlevel>0</versionlevel>
|
||||
<versionids>EmbedStandardResources NO_OPENGL USE_FREETYPE</versionids>
|
||||
<versionids>EmbedStandardResources USE_FREETYPE NO_OPENGL</versionids>
|
||||
<dump_source>0</dump_source>
|
||||
<mapverbosity>0</mapverbosity>
|
||||
<createImplib>0</createImplib>
|
||||
|
@ -382,7 +382,7 @@
|
|||
<debuglevel>0</debuglevel>
|
||||
<debugids />
|
||||
<versionlevel>0</versionlevel>
|
||||
<versionids>EmbedStandardResources</versionids>
|
||||
<versionids>EmbedStandardResources NO_OPENGL USE_FREETYPE</versionids>
|
||||
<dump_source>0</dump_source>
|
||||
<mapverbosity>0</mapverbosity>
|
||||
<createImplib>0</createImplib>
|
||||
|
@ -618,6 +618,212 @@
|
|||
<postBuildCommand />
|
||||
<filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean>
|
||||
</Config>
|
||||
<Config name="DSFMLDebug" platform="Win32">
|
||||
<obj>0</obj>
|
||||
<link>0</link>
|
||||
<lib>0</lib>
|
||||
<subsystem>2</subsystem>
|
||||
<multiobj>0</multiobj>
|
||||
<singleFileCompilation>0</singleFileCompilation>
|
||||
<oneobj>0</oneobj>
|
||||
<mscoff>0</mscoff>
|
||||
<trace>1</trace>
|
||||
<quiet>0</quiet>
|
||||
<verbose>0</verbose>
|
||||
<vtls>0</vtls>
|
||||
<vgc>0</vgc>
|
||||
<symdebug>1</symdebug>
|
||||
<optimize>0</optimize>
|
||||
<cpu>0</cpu>
|
||||
<isX86_64>0</isX86_64>
|
||||
<isLinux>0</isLinux>
|
||||
<isOSX>0</isOSX>
|
||||
<isWindows>0</isWindows>
|
||||
<isFreeBSD>0</isFreeBSD>
|
||||
<isSolaris>0</isSolaris>
|
||||
<scheduler>0</scheduler>
|
||||
<useDeprecated>1</useDeprecated>
|
||||
<errDeprecated>0</errDeprecated>
|
||||
<useAssert>0</useAssert>
|
||||
<useInvariants>0</useInvariants>
|
||||
<useIn>0</useIn>
|
||||
<useOut>0</useOut>
|
||||
<useArrayBounds>0</useArrayBounds>
|
||||
<noboundscheck>0</noboundscheck>
|
||||
<useSwitchError>0</useSwitchError>
|
||||
<useUnitTests>0</useUnitTests>
|
||||
<useInline>0</useInline>
|
||||
<release>0</release>
|
||||
<preservePaths>0</preservePaths>
|
||||
<warnings>0</warnings>
|
||||
<infowarnings>0</infowarnings>
|
||||
<checkProperty>0</checkProperty>
|
||||
<genStackFrame>0</genStackFrame>
|
||||
<pic>0</pic>
|
||||
<cov>0</cov>
|
||||
<nofloat>0</nofloat>
|
||||
<Dversion>2</Dversion>
|
||||
<ignoreUnsupportedPragmas>0</ignoreUnsupportedPragmas>
|
||||
<allinst>0</allinst>
|
||||
<stackStomp>0</stackStomp>
|
||||
<compiler>0</compiler>
|
||||
<otherDMD>0</otherDMD>
|
||||
<cccmd>$(CC) -c</cccmd>
|
||||
<ccTransOpt>1</ccTransOpt>
|
||||
<addDepImp>0</addDepImp>
|
||||
<program>$(DMDInstallDir)windows\bin\dmd.exe</program>
|
||||
<imppath>$(ProjectDir)/../dlangui/src $(ProjectDir)/../dlangui/3rdparty $(ProjectDir)/../dlangui/deps/DerelictGL3/source $(ProjectDir)/../dlangui/deps/DerelictUtil/source $(ProjectDir)/../dlangui/deps/DerelictFT/source $(ProjectDir)/../dlangui/deps/DerelictSDL2/source $(ProjectDir)/../dlangui/deps/libdparse/src $(ProjectDir)/../DerelictLLDB/source</imppath>
|
||||
<fileImppath>views views/res views/res/i18n views/res/mdpi views/res/hdpi</fileImppath>
|
||||
<outdir>$(ConfigurationName)</outdir>
|
||||
<objdir>$(OutDir)</objdir>
|
||||
<objname />
|
||||
<libname />
|
||||
<doDocComments>0</doDocComments>
|
||||
<docdir />
|
||||
<docname />
|
||||
<modules_ddoc />
|
||||
<ddocfiles />
|
||||
<doHdrGeneration>0</doHdrGeneration>
|
||||
<hdrdir />
|
||||
<hdrname />
|
||||
<doXGeneration>1</doXGeneration>
|
||||
<xfilename>$(IntDir)\$(TargetName).json</xfilename>
|
||||
<debuglevel>0</debuglevel>
|
||||
<debugids>KeyInput DCD</debugids>
|
||||
<versionlevel>0</versionlevel>
|
||||
<versionids>EmbedStandardResources USE_FREETYPE NO_OPENGL</versionids>
|
||||
<dump_source>0</dump_source>
|
||||
<mapverbosity>0</mapverbosity>
|
||||
<createImplib>0</createImplib>
|
||||
<defaultlibname />
|
||||
<debuglibname />
|
||||
<moduleDepsFile />
|
||||
<run>0</run>
|
||||
<runargs />
|
||||
<runCv2pdb>1</runCv2pdb>
|
||||
<pathCv2pdb>$(VisualDInstallDir)cv2pdb\cv2pdb.exe</pathCv2pdb>
|
||||
<cv2pdbPre2043>0</cv2pdbPre2043>
|
||||
<cv2pdbNoDemangle>0</cv2pdbNoDemangle>
|
||||
<cv2pdbEnumType>0</cv2pdbEnumType>
|
||||
<cv2pdbOptions />
|
||||
<objfiles />
|
||||
<linkswitches />
|
||||
<libfiles />
|
||||
<libpaths />
|
||||
<deffile />
|
||||
<resfile />
|
||||
<exefile>$(OutDir)\$(ProjectName).exe</exefile>
|
||||
<useStdLibPath>1</useStdLibPath>
|
||||
<cRuntime>2</cRuntime>
|
||||
<privatePhobos>0</privatePhobos>
|
||||
<additionalOptions />
|
||||
<preBuildCommand />
|
||||
<postBuildCommand />
|
||||
<filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean>
|
||||
</Config>
|
||||
<Config name="DSFMLDebug" platform="x64">
|
||||
<obj>0</obj>
|
||||
<link>0</link>
|
||||
<lib>0</lib>
|
||||
<subsystem>2</subsystem>
|
||||
<multiobj>0</multiobj>
|
||||
<singleFileCompilation>0</singleFileCompilation>
|
||||
<oneobj>0</oneobj>
|
||||
<mscoff>0</mscoff>
|
||||
<trace>1</trace>
|
||||
<quiet>0</quiet>
|
||||
<verbose>0</verbose>
|
||||
<vtls>0</vtls>
|
||||
<vgc>0</vgc>
|
||||
<symdebug>1</symdebug>
|
||||
<optimize>0</optimize>
|
||||
<cpu>0</cpu>
|
||||
<isX86_64>1</isX86_64>
|
||||
<isLinux>0</isLinux>
|
||||
<isOSX>0</isOSX>
|
||||
<isWindows>0</isWindows>
|
||||
<isFreeBSD>0</isFreeBSD>
|
||||
<isSolaris>0</isSolaris>
|
||||
<scheduler>0</scheduler>
|
||||
<useDeprecated>1</useDeprecated>
|
||||
<errDeprecated>0</errDeprecated>
|
||||
<useAssert>0</useAssert>
|
||||
<useInvariants>0</useInvariants>
|
||||
<useIn>0</useIn>
|
||||
<useOut>0</useOut>
|
||||
<useArrayBounds>0</useArrayBounds>
|
||||
<noboundscheck>0</noboundscheck>
|
||||
<useSwitchError>0</useSwitchError>
|
||||
<useUnitTests>0</useUnitTests>
|
||||
<useInline>0</useInline>
|
||||
<release>0</release>
|
||||
<preservePaths>0</preservePaths>
|
||||
<warnings>0</warnings>
|
||||
<infowarnings>0</infowarnings>
|
||||
<checkProperty>0</checkProperty>
|
||||
<genStackFrame>0</genStackFrame>
|
||||
<pic>0</pic>
|
||||
<cov>0</cov>
|
||||
<nofloat>0</nofloat>
|
||||
<Dversion>2</Dversion>
|
||||
<ignoreUnsupportedPragmas>0</ignoreUnsupportedPragmas>
|
||||
<allinst>0</allinst>
|
||||
<stackStomp>0</stackStomp>
|
||||
<compiler>0</compiler>
|
||||
<otherDMD>0</otherDMD>
|
||||
<cccmd>$(CC) -c -v</cccmd>
|
||||
<ccTransOpt>1</ccTransOpt>
|
||||
<addDepImp>0</addDepImp>
|
||||
<program>$(DMDInstallDir)windows\bin\dmd.exe</program>
|
||||
<imppath>$(ProjectDir)/../dlangui/src $(ProjectDir)/../dlangui/3rdparty $(ProjectDir)/../dlangui/deps/DerelictGL3/source $(ProjectDir)/../dlangui/deps/DerelictUtil/source $(ProjectDir)/../dlangui/deps/DerelictFT/source $(ProjectDir)/../dlangui/deps/DerelictSDL2/source $(ProjectDir)/../dlangui/deps/libdparse/src $(ProjectDir)/../DerelictLLDB/source</imppath>
|
||||
<fileImppath>views views/res views/res/i18n views/res/mdpi views/res/hdpi</fileImppath>
|
||||
<outdir>$(ConfigurationName)</outdir>
|
||||
<objdir>$(OutDir)</objdir>
|
||||
<objname />
|
||||
<libname />
|
||||
<doDocComments>0</doDocComments>
|
||||
<docdir />
|
||||
<docname />
|
||||
<modules_ddoc />
|
||||
<ddocfiles />
|
||||
<doHdrGeneration>0</doHdrGeneration>
|
||||
<hdrdir />
|
||||
<hdrname />
|
||||
<doXGeneration>1</doXGeneration>
|
||||
<xfilename>$(IntDir)\$(TargetName).json</xfilename>
|
||||
<debuglevel>0</debuglevel>
|
||||
<debugids>KeyInput DCD</debugids>
|
||||
<versionlevel>0</versionlevel>
|
||||
<versionids>EmbedStandardResources USE_FREETYPE NO_OPENGL</versionids>
|
||||
<dump_source>0</dump_source>
|
||||
<mapverbosity>0</mapverbosity>
|
||||
<createImplib>0</createImplib>
|
||||
<defaultlibname />
|
||||
<debuglibname />
|
||||
<moduleDepsFile />
|
||||
<run>0</run>
|
||||
<runargs />
|
||||
<runCv2pdb>1</runCv2pdb>
|
||||
<pathCv2pdb>$(VisualDInstallDir)cv2pdb\cv2pdb.exe</pathCv2pdb>
|
||||
<cv2pdbPre2043>0</cv2pdbPre2043>
|
||||
<cv2pdbNoDemangle>0</cv2pdbNoDemangle>
|
||||
<cv2pdbEnumType>0</cv2pdbEnumType>
|
||||
<cv2pdbOptions />
|
||||
<objfiles />
|
||||
<linkswitches />
|
||||
<libfiles />
|
||||
<libpaths />
|
||||
<deffile />
|
||||
<resfile />
|
||||
<exefile>$(OutDir)\$(ProjectName).exe</exefile>
|
||||
<useStdLibPath>1</useStdLibPath>
|
||||
<cRuntime>2</cRuntime>
|
||||
<privatePhobos>1</privatePhobos>
|
||||
<additionalOptions />
|
||||
<preBuildCommand />
|
||||
<postBuildCommand />
|
||||
<filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean>
|
||||
</Config>
|
||||
<Folder name="dlangide">
|
||||
<Folder name="3rdparty">
|
||||
<Folder name="containers">
|
||||
|
@ -718,6 +924,7 @@
|
|||
<Folder name="d">
|
||||
<File path="src\dlangide\tools\d\dcdinterface.d" />
|
||||
<File path="src\dlangide\tools\d\deditortool.d" />
|
||||
<File path="src\dlangide\tools\d\dmdtrace.d" />
|
||||
<File path="src\dlangide\tools\d\dparser.d" />
|
||||
<File path="src\dlangide\tools\d\dsyntax.d" />
|
||||
</Folder>
|
||||
|
@ -726,6 +933,7 @@
|
|||
<Folder name="ui">
|
||||
<File path="src\dlangide\ui\commands.d" />
|
||||
<File path="src\dlangide\ui\debuggerui.d" />
|
||||
<File path="src\dlangide\ui\dmdprofilerview.d" />
|
||||
<File path="src\dlangide\ui\dsourceedit.d" />
|
||||
<File path="src\dlangide\ui\frame.d" />
|
||||
<File path="src\dlangide\ui\homescreen.d" />
|
||||
|
|
|
@ -13,6 +13,14 @@ mixin APP_ENTRY_POINT;
|
|||
/// entry point for dlangui based application
|
||||
extern (C) int UIAppMain(string[] args) {
|
||||
|
||||
//debug(TestDMDTraceParser) {
|
||||
// import dlangide.tools.d.dmdtrace;
|
||||
// long start = currentTimeMillis;
|
||||
// DMDTraceLogParser parser = parseDMDTraceLog("trace.log");
|
||||
// if (parser) {
|
||||
// Log.d("trace.log is parsed ok in ", currentTimeMillis - start, " seconds");
|
||||
// }
|
||||
//}
|
||||
debug(TestParser) {
|
||||
import ddc.lexer.parser;
|
||||
runParserTests();
|
||||
|
|
|
@ -0,0 +1,365 @@
|
|||
/// DMD trace.log parser
|
||||
module dlangide.tools.d.dmdtrace;
|
||||
|
||||
/*
|
||||
Based on d-profile-viewer: https://bitbucket.org/andrewtrotman/d-profile-viewer
|
||||
|
||||
Copyright (c) 2015-2016 eBay Software Foundation
|
||||
Written by Andrew Trotman
|
||||
Licensed under the 3-clause BSD license (see here:https://en.wikipedia.org/wiki/BSD_licenses)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
import dlangui.core.logger;
|
||||
//import core.stdc.stdlib;
|
||||
import std.file;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
//import dlangide.tools.d.demangle;
|
||||
import core.runtime;
|
||||
import std.conv;
|
||||
import std.algorithm;
|
||||
import std.exception;
|
||||
//import std.demangle;
|
||||
import dlangide.ui.outputpanel;
|
||||
import dlangide.builders.extprocess;
|
||||
import dlangui.widgets.appframe;
|
||||
import core.thread;
|
||||
|
||||
class DMDTraceLogParser {
|
||||
string filename;
|
||||
string content;
|
||||
string[] lines;
|
||||
bool _cancelRequested;
|
||||
|
||||
FunctionNode[string] nodes;
|
||||
//FunctionEdge[string] caller_graph;
|
||||
//FunctionEdge[string] called_graph;
|
||||
ulong ticks_per_second;
|
||||
|
||||
this(string fname) {
|
||||
filename = fname;
|
||||
}
|
||||
void requestCancel() {
|
||||
_cancelRequested = true;
|
||||
}
|
||||
private void splitLines(void[] buffer) {
|
||||
lines.assumeSafeAppend;
|
||||
content = cast(string)buffer;
|
||||
int lineStart = 0;
|
||||
for (int i = 0; i < content.length; i++) {
|
||||
char ch = content.ptr[i];
|
||||
if (ch == '\r' || ch == '\n') {
|
||||
if (lineStart < i) {
|
||||
lines ~= content[lineStart .. i];
|
||||
}
|
||||
lineStart = i + 1;
|
||||
}
|
||||
}
|
||||
// append last line if any
|
||||
if (lineStart < content.length)
|
||||
lines ~= content[lineStart .. $];
|
||||
}
|
||||
bool load() {
|
||||
void[] file;
|
||||
try
|
||||
{
|
||||
file = read(filename);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.e("Cannot open trace file ", filename);
|
||||
return false;
|
||||
}
|
||||
if (file.length == 0) {
|
||||
Log.e("Trace log ", filename, " is empty");
|
||||
return false;
|
||||
}
|
||||
Log.d("Opened file ", filename, " ", file.length, " bytes");
|
||||
splitLines(file);
|
||||
Log.d("Lines: ", lines.length);
|
||||
return lines.length > 0;
|
||||
}
|
||||
bool parse() {
|
||||
bool caller = true;
|
||||
string function_name;
|
||||
FunctionEdge[string] caller_graph;
|
||||
FunctionEdge[string] called_graph;
|
||||
ulong function_times;
|
||||
ulong function_and_descendant;
|
||||
ulong function_only;
|
||||
foreach(i, line; lines) {
|
||||
if (_cancelRequested)
|
||||
return false;
|
||||
if (line.length == 0) {
|
||||
continue; // Ignore blank lines
|
||||
} else if (line[0] == '=') { // Seperator between call graph and summary data
|
||||
auto number = indexOfAny(line, "1234567890");
|
||||
if (number < 0)
|
||||
{
|
||||
Log.e("Corrupt trace.log (can't compute ticks per second), please re-profile and try again");
|
||||
return false;
|
||||
}
|
||||
auto space = indexOf(line[number .. $], ' ') + number;
|
||||
ticks_per_second = to!ulong(line[number .. space]);
|
||||
break;
|
||||
} else if (line[0] == '-') { //Seperator between each function call graph
|
||||
caller = true;
|
||||
if (function_name.length != 0)
|
||||
nodes[text(function_name)] = new FunctionNode(function_name,
|
||||
function_times, function_and_descendant, function_only,
|
||||
caller_graph, called_graph);
|
||||
caller_graph = null;
|
||||
called_graph = null;
|
||||
} else if (line[0] == '\t')
|
||||
{
|
||||
// A function either calling or called by this function
|
||||
/*
|
||||
We can't assume a name starts with an '_' because it might be an extern "C" which hasn't been mangled.
|
||||
We also can't assume the character encodin of what ever language that is so we look for the last tab
|
||||
and asusme the identifier starts on the next character.
|
||||
*/
|
||||
// auto pos = indexOfAny(line, "_");
|
||||
auto pos = lastIndexOf(line, '\t') + 1;
|
||||
auto start_pos = indexOfAny(line, "1234567890");
|
||||
if (start_pos < 0 || pos < 0 || pos < start_pos)
|
||||
{
|
||||
Log.e("Corrupt trace.log (call count is non-numeric), please re-profile and try again");
|
||||
return false;
|
||||
}
|
||||
immutable times = to!ulong(line[start_pos .. pos - 1]);
|
||||
auto name = line[pos .. $];
|
||||
if (caller)
|
||||
{
|
||||
caller_graph[text(name)] = new FunctionEdge(name, times);
|
||||
}
|
||||
else
|
||||
{
|
||||
called_graph[text(name)] = new FunctionEdge(name, times);
|
||||
}
|
||||
}
|
||||
/*
|
||||
In the case of a call to a non-D function, the identifier might not start with an '_' (e.g. extern "C"). But, we can't know
|
||||
how those identifiers are stored so we can't assume an encoding - and hence we must assume that what ever we have is correct.
|
||||
*/
|
||||
// else if (indexOf("_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", line[0]) >= 0) //The name of the function were're currently examining the call graph for (seperates callers from called)
|
||||
else //The name of the function were're currently examining the call graph for (seperates callers from called)
|
||||
{
|
||||
auto start_tab = indexOf(line, '\t');
|
||||
auto middle_tab = indexOf(line[start_tab + 1 .. $], '\t') + start_tab + 1;
|
||||
auto last_tab = indexOf(line[middle_tab + 1 .. $], '\t') + middle_tab + 1;
|
||||
function_name = line[0 .. start_tab];
|
||||
//if (function_name.length > 1024)
|
||||
// Log.d("long function name: ", function_name);
|
||||
function_times = to!ulong(line[start_tab + 1 .. middle_tab]);
|
||||
function_and_descendant = to!ulong(line[middle_tab + 1 .. last_tab]);
|
||||
function_only = to!ulong(line[last_tab + 1 .. $]);
|
||||
caller = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private __gshared static char[] demangleBuffer;
|
||||
|
||||
private string demangle(string mangled_name) {
|
||||
import core.demangle : demangle;
|
||||
//const (char) [] demangled_name;
|
||||
string demangled_name; // = dlangide.tools.d.demangle.demangle(mangled_name);
|
||||
//if (demangled_name[0] == '_') { // in the unlikely event that we fail to demangle, fall back to the phobos demangler
|
||||
try {
|
||||
if (demangleBuffer.length < mangled_name.length + 16384)
|
||||
demangleBuffer.length = mangled_name.length * 2 + 16384;
|
||||
demangled_name = cast(string)core.demangle.demangle(mangled_name, demangleBuffer[]);
|
||||
} catch (Exception e) {
|
||||
demangled_name = mangled_name;
|
||||
}
|
||||
//}
|
||||
if (demangled_name.length > 1024)
|
||||
return demangled_name[0..1024] ~ "...";
|
||||
return demangled_name.dup;
|
||||
}
|
||||
|
||||
/*
|
||||
CLASS FUNCTION_EDGE
|
||||
-------------------
|
||||
There's one of these objects for each function in program being profiled.
|
||||
*/
|
||||
class FunctionEdge
|
||||
{
|
||||
public:
|
||||
string name; // the demangled name of the function
|
||||
string mangled_name; // the mangled name
|
||||
ulong calls; // number of times the function is called
|
||||
|
||||
public:
|
||||
/*
|
||||
THIS()
|
||||
------
|
||||
Constructor
|
||||
*/
|
||||
this(string mangled_name, ulong calls)
|
||||
{
|
||||
this.mangled_name = mangled_name;
|
||||
|
||||
this.name = demangle(mangled_name);
|
||||
|
||||
this.calls = calls;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
CLASS FUNCTION_NODE
|
||||
-------------------
|
||||
|
||||
*/
|
||||
class FunctionNode
|
||||
{
|
||||
public:
|
||||
FunctionEdge[string] called_by;
|
||||
FunctionEdge[string] calls_to;
|
||||
string name;
|
||||
string mangled_name;
|
||||
ulong number_of_calls;
|
||||
ulong function_and_descendant_time; // in cycles
|
||||
ulong function_time; // in cycles
|
||||
|
||||
private:
|
||||
/*
|
||||
PERCENT()
|
||||
---------
|
||||
Compute top/bottom to 2 decimal places
|
||||
*/
|
||||
double percent(double top, double bottom)
|
||||
{
|
||||
return cast(double)(cast(size_t)((top / bottom * 100_00.0))) / 100.0;
|
||||
}
|
||||
|
||||
/*
|
||||
TO_US()
|
||||
-------
|
||||
Convert from ticks to micro-seconds
|
||||
*/
|
||||
size_t to_us(double ticks, double ticks_per_second)
|
||||
{
|
||||
return cast(size_t)(ticks / ticks_per_second * 1000 * 1000);
|
||||
}
|
||||
|
||||
public:
|
||||
/*
|
||||
THIS()
|
||||
------
|
||||
*/
|
||||
this(string mangled_name, ulong calls, ulong function_and_descendant_time,
|
||||
ulong function_time, FunctionEdge[string] called_by, FunctionEdge[string] calls_to)
|
||||
{
|
||||
this.mangled_name = mangled_name;
|
||||
|
||||
this.name = demangle(mangled_name);
|
||||
|
||||
this.number_of_calls = calls;
|
||||
this.function_and_descendant_time = function_and_descendant_time;
|
||||
this.function_time = function_time;
|
||||
this.called_by = called_by;
|
||||
this.calls_to = calls_to;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DMDTraceLogParser parseDMDTraceLog(string filename) {
|
||||
scope(exit) demangleBuffer = null;
|
||||
DMDTraceLogParser parser = new DMDTraceLogParser(filename);
|
||||
if (!parser.load())
|
||||
return null;
|
||||
if (!parser.parse())
|
||||
return null;
|
||||
return parser;
|
||||
}
|
||||
|
||||
class DMDProfilerLogParserThread : Thread {
|
||||
private DMDTraceLogParser _parser;
|
||||
private bool _finished;
|
||||
private bool _success;
|
||||
|
||||
this(string filename) {
|
||||
super(&run);
|
||||
_parser = new DMDTraceLogParser(filename);
|
||||
}
|
||||
|
||||
@property bool finished() { return _finished; }
|
||||
@property DMDTraceLogParser parser() { return _success ? _parser : null; }
|
||||
|
||||
void requestCancel() {
|
||||
_parser.requestCancel();
|
||||
}
|
||||
void run() {
|
||||
scope(exit) demangleBuffer = null;
|
||||
if (!_parser.load()) {
|
||||
_finished = true;
|
||||
return;
|
||||
}
|
||||
if (!_parser.parse()) {
|
||||
_finished = true;
|
||||
return;
|
||||
}
|
||||
_success = true;
|
||||
_finished = true;
|
||||
// Done
|
||||
}
|
||||
}
|
||||
|
||||
alias DMDProfilerLogParserListener = void delegate(DMDTraceLogParser parser);
|
||||
|
||||
class DMDProfilerLogParserOperation : BackgroundOperationWatcher {
|
||||
|
||||
string _filename;
|
||||
DMDProfilerLogParserListener _listener;
|
||||
dstring _description;
|
||||
DMDProfilerLogParserThread _thread;
|
||||
DMDTraceLogParser _result;
|
||||
|
||||
this(AppFrame frame, string filename, OutputPanel log, DMDProfilerLogParserListener listener) {
|
||||
super(frame);
|
||||
_filename = filename;
|
||||
_listener = listener;
|
||||
_description = "Parsing DMD trace log file"d;
|
||||
_thread = new DMDProfilerLogParserThread(filename);
|
||||
_thread.start();
|
||||
}
|
||||
|
||||
/// returns description of background operation to show in status line
|
||||
override @property dstring description() { return _description; }
|
||||
/// returns icon of background operation to show in status line
|
||||
override @property string icon() { return "folder"; }
|
||||
/// update background operation status
|
||||
override void update() {
|
||||
if (_finished) {
|
||||
return;
|
||||
}
|
||||
if (_thread.finished) {
|
||||
_thread.join();
|
||||
_result = _thread.parser;
|
||||
//_extprocess.kill();
|
||||
//_extprocess.wait();
|
||||
_finished = true;
|
||||
return;
|
||||
}
|
||||
if (_cancelRequested) {
|
||||
_thread.requestCancel();
|
||||
_thread.join();
|
||||
_result = _thread.parser;
|
||||
//_extprocess.kill();
|
||||
//_extprocess.wait();
|
||||
_finished = true;
|
||||
return;
|
||||
}
|
||||
super.update();
|
||||
}
|
||||
override void removing() {
|
||||
super.removing();
|
||||
//if (_exitCode != int.min && _listener)
|
||||
_listener(_result);
|
||||
}
|
||||
}
|
|
@ -80,6 +80,8 @@ enum IDEActions : int {
|
|||
ViewToggleTabPositionMarks,
|
||||
ViewToggleToolbar,
|
||||
ViewToggleStatusbar,
|
||||
|
||||
ToolsOpenDMDTraceLog,
|
||||
}
|
||||
|
||||
__gshared static this() {
|
||||
|
@ -175,6 +177,8 @@ const Action ACTION_GET_PAREN_COMPLETION = (new Action(IDEActions.GetParenComple
|
|||
const Action ACTION_GO_TO_LINE = (new Action(IDEActions.GotoLine, "GO_TO_LINE"c, ""c, KeyCode.KEY_L, KeyFlag.Control|KeyFlag.Option)).disableByDefault();;
|
||||
|
||||
const Action ACTION_FIND_TEXT = (new Action(IDEActions.FindInFiles, "FIND_IN_FILES"c, "edit-find"c, KeyCode.KEY_F, KeyFlag.Control | KeyFlag.Shift)).disableByDefault();
|
||||
const Action ACTION_TOOLS_OPEN_DMD_TRACE_LOG = (new Action(IDEActions.ToolsOpenDMDTraceLog, "OPEN_DMD_TRACE_LOG"c));
|
||||
|
||||
|
||||
const Action[] STD_IDE_ACTIONS = [
|
||||
ACTION_EDIT_COPY, ACTION_EDIT_PASTE, ACTION_EDIT_CUT,
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
module dlangide.ui.dmdprofilerview;
|
||||
|
||||
import dlangui.widgets.layouts;
|
||||
import dlangui.widgets.widget;
|
||||
import dlangui.widgets.scroll;
|
||||
import dlangui.widgets.controls;
|
||||
import dlangide.ui.frame;
|
||||
import dlangide.ui.commands;
|
||||
import dlangui.core.i18n;
|
||||
import dlangide.tools.d.dmdtrace;
|
||||
|
||||
class DMDProfilerView : ScrollWidget {
|
||||
protected IDEFrame _frame;
|
||||
protected DMDTraceLogParser _data;
|
||||
this(string ID, IDEFrame frame, DMDTraceLogParser data) {
|
||||
super(ID);
|
||||
_frame = frame;
|
||||
_data = data;
|
||||
contentWidget = new TextWidget(null, "DMD profiler view"d);
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ import ddebug.common.execution;
|
|||
import ddebug.common.nodebug;
|
||||
import ddebug.common.debugger;
|
||||
import ddebug.gdb.gdbinterface;
|
||||
import dlangide.tools.d.dmdtrace;
|
||||
|
||||
import std.conv;
|
||||
import std.utf;
|
||||
|
@ -805,6 +806,9 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
|
|||
);
|
||||
|
||||
|
||||
MenuItem toolsItem = new MenuItem(new Action(33, "MENU_TOOLS"c));
|
||||
toolsItem.add(ACTION_TOOLS_OPEN_DMD_TRACE_LOG);
|
||||
|
||||
MenuItem windowItem = new MenuItem(new Action(3, "MENU_WINDOW"c));
|
||||
//windowItem.add(new Action(30, "MENU_WINDOW_PREFERENCES"));
|
||||
windowItem.add(ACTION_WINDOW_CLOSE_DOCUMENT, ACTION_WINDOW_CLOSE_ALL_DOCUMENTS);
|
||||
|
@ -818,6 +822,7 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
|
|||
mainMenuItems.add(navItem);
|
||||
mainMenuItems.add(buildItem);
|
||||
mainMenuItems.add(debugItem);
|
||||
mainMenuItems.add(toolsItem);
|
||||
//mainMenuItems.add(viewItem);
|
||||
mainMenuItems.add(windowItem);
|
||||
mainMenuItems.add(helpItem);
|
||||
|
@ -1002,6 +1007,50 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
|
|||
}
|
||||
}
|
||||
|
||||
static immutable TRACE_LOG_ID = "TRACE_LOG";
|
||||
void showDMDTraceLog(DMDTraceLogParser data) {
|
||||
import dlangide.ui.dmdprofilerview;
|
||||
int index = _tabs.tabIndex(TRACE_LOG_ID);
|
||||
if (index >= 0) {
|
||||
_tabs.removeTab(TRACE_LOG_ID);
|
||||
}
|
||||
DMDProfilerView home = new DMDProfilerView(TRACE_LOG_ID, this, data);
|
||||
_tabs.addTab(home, UIString.fromId("PROFILER_WINDOW"c), null, true);
|
||||
_tabs.selectTab(TRACE_LOG_ID, true);
|
||||
}
|
||||
|
||||
//void showDMDTraceLog()
|
||||
void openDMDTraceLog(string filename) {
|
||||
DMDProfilerLogParserOperation op = new DMDProfilerLogParserOperation(this, filename, _logPanel,
|
||||
delegate(DMDTraceLogParser parser) {
|
||||
if (parser) {
|
||||
Log.d("Trace log is ready");
|
||||
showDMDTraceLog(parser);
|
||||
} else {
|
||||
Log.e("Trace log is failed");
|
||||
window.showMessageBox(UIString.fromId("ERROR"c), UIString.fromId("ERROR_FAILED_TO_PARSE_FILE"c));
|
||||
}
|
||||
}
|
||||
);
|
||||
setBackgroundOperation(op);
|
||||
}
|
||||
|
||||
void openDMDTraceLog() {
|
||||
UIString caption;
|
||||
caption = UIString.fromId("HEADER_OPEN_DMD_PROFILER_LOG"c);
|
||||
FileDialog dlg = createFileDialog(caption);
|
||||
dlg.addFilter(FileFilterEntry(UIString.fromId("PROFILER_LOG_FILES"c), "*.log"));
|
||||
dlg.path = _settings.getRecentPath("FILE_OPEN_PATH");
|
||||
dlg.dialogResult = delegate(Dialog d, const Action result) {
|
||||
if (result.id == ACTION_OPEN.id) {
|
||||
string filename = result.stringParam;
|
||||
_settings.setRecentPath(dlg.path, "FILE_OPEN_PATH");
|
||||
openDMDTraceLog(filename);
|
||||
}
|
||||
};
|
||||
dlg.show();
|
||||
}
|
||||
|
||||
FileDialog createFileDialog(UIString caption, int fileDialogFlags = DialogFlag.Modal | DialogFlag.Resizable | FileDialogFlag.FileMustExist) {
|
||||
FileDialog dlg = new FileDialog(caption, window, null, fileDialogFlags);
|
||||
dlg.filetypeIcons[".d"] = "text-d";
|
||||
|
@ -1026,6 +1075,9 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
|
|||
case IDEActions.HelpDonate:
|
||||
Platform.instance.openURL(HELP_DONATION_URL);
|
||||
return true;
|
||||
case IDEActions.ToolsOpenDMDTraceLog:
|
||||
openDMDTraceLog();
|
||||
return true;
|
||||
case IDEActions.HelpAbout:
|
||||
//debug {
|
||||
// testDCDFailAfterThreadCreation();
|
||||
|
|
|
@ -19,10 +19,13 @@ DLANG_IDE_DONATE=Support DlangIDE
|
|||
DLANG_IDE_DONATE_PAYPAL=Donate via PayPal
|
||||
EXIT=Exit
|
||||
|
||||
PROFILER_WINDOW=Profiler
|
||||
|
||||
ALL_FILES=All files
|
||||
SOURCE_FILES=Source files
|
||||
WORKSPACE_AND_PROJECT_FILES=Workspace and project files
|
||||
IDE_FILES=DlangIDE files
|
||||
PROFILER_LOG_FILES=DMD Profiler Logs
|
||||
|
||||
EDITOR_CONTENT=Editors content
|
||||
LOCATION=Location
|
||||
|
@ -127,6 +130,9 @@ MENU_VIEW_THEME=&Theme
|
|||
MENU_VIEW_THEME_DEFAULT=&Default
|
||||
MENU_VIEW_THEME_CUSTOM1=&Custom 1
|
||||
|
||||
MENU_TOOLS=Tools
|
||||
OPEN_DMD_TRACE_LOG=Open DMD profiler log
|
||||
|
||||
TAB_LONG_LIST=Long list
|
||||
TAB_BUTTONS=Buttons
|
||||
TAB_ANIMATION=Animation
|
||||
|
@ -145,6 +151,7 @@ MENU_PROJECT_FOLDER_COLLAPSE_ALL=Collapse all
|
|||
HEADER_SETTINGS=DlangIDE settings
|
||||
HEADER_OPEN_WORKSPACE_OR_PROJECT=Open Workspace or Project
|
||||
HEADER_OPEN_TEXT_FILE=Open Text File
|
||||
HEADER_OPEN_DMD_PROFILER_LOG=Open DMD Profiler Log File
|
||||
HEADER_CLOSE_FILE=Close file
|
||||
HEADER_CLOSE_TAB=Close tab
|
||||
HEADER_PROJECT_SETTINGS=project settings
|
||||
|
@ -235,6 +242,7 @@ ERROR_OPEN_WORKSPACE=Cannot open workspace
|
|||
ERROR_OPENING_FILE=Failed to open file
|
||||
ERROR_OPENING_PROJECT=Error occured while opening project
|
||||
ERROR_OPENING_WORKSPACE=Error occured while opening workspace
|
||||
ERROR_FAILED_TO_PARSE_TRACE_LOG_FILE=Failed to parse trace log file
|
||||
|
||||
MSG_FILE_CONTENT_CHANGED=Content of this file has been changed.
|
||||
MSG_TAB_CONTENT_CHANGED=Content of tab has been changed
|
||||
|
|
|
@ -19,10 +19,13 @@ DLANG_IDE_DONATE=Поддержать DlangIDE
|
|||
DLANG_IDE_DONATE_PAYPAL=PayPal
|
||||
EXIT=Выход
|
||||
|
||||
PROFILER_WINDOW=Профилировщик
|
||||
|
||||
ALL_FILES=Все файлы
|
||||
SOURCE_FILES=Исходники
|
||||
WORKSPACE_AND_PROJECT_FILES=Файлы проектов и раб. прост.
|
||||
IDE_FILES=Файлы DlangIDE
|
||||
PROFILER_LOG_FILES=Файды DMD Profiler
|
||||
|
||||
EDITOR_CONTENT=Содержимое редактора
|
||||
LOCATION=Место
|
||||
|
@ -126,6 +129,9 @@ MENU_VIEW_THEME=&Тема
|
|||
MENU_VIEW_THEME_DEFAULT=Стандартная
|
||||
MENU_VIEW_THEME_CUSTOM1=Пример 1
|
||||
|
||||
MENU_TOOLS=Инструменты
|
||||
OPEN_DMD_TRACE_LOG=Открыть лог DMD profiler
|
||||
|
||||
TAB_LONG_LIST=Длинный список
|
||||
TAB_BUTTONS=Кнопки
|
||||
TAB_ANIMATION=Анимация
|
||||
|
@ -144,6 +150,7 @@ MENU_PROJECT_FOLDER_COLLAPSE_ALL=Свернуть все
|
|||
HEADER_SETTINGS=DlangIDE настройки
|
||||
HEADER_OPEN_WORKSPACE_OR_PROJECT=Открыть рабочее пространство или проект
|
||||
HEADER_OPEN_TEXT_FILE=Открыть текстовый файл
|
||||
HEADER_OPEN_DMD_PROFILER_LOG=Открыть файл DMD Profiler Log
|
||||
HEADER_CLOSE_FILE=Закрыть файл
|
||||
HEADER_CLOSE_TAB=Закрыть вкладку
|
||||
HEADER_PROJECT_SETTINGS=настройки проекта
|
||||
|
@ -233,6 +240,7 @@ ERROR_OPEN_WORKSPACE=Невозможно открыть рабочее прос
|
|||
ERROR_OPENING_FILE=Ошибка открытия файла
|
||||
ERROR_OPENING_PROJECT=Ошибка в ходе открытия проекта
|
||||
ERROR_OPENING_WORKSPACE=Ошибка в ходе открытия рабочего пространства
|
||||
ERROR_FAILED_TO_PARSE_TRACE_LOG_FILE=Не удалось обработать файл DMD trace log
|
||||
|
||||
MSG_FILE_CONTENT_CHANGED=Содержимое этого файла изменено.
|
||||
MSG_TAB_CONTENT_CHANGED=Содержимое вкладки изменено
|
||||
|
|
Loading…
Reference in New Issue