DMD profiler trace.log viewer, part 1 - #344

This commit is contained in:
Vadim Lopatin 2017-10-06 16:40:22 +03:00
parent 645090ec31
commit f620e3e286
8 changed files with 681 additions and 7 deletions

View File

@ -71,9 +71,9 @@
<doXGeneration>1</doXGeneration> <doXGeneration>1</doXGeneration>
<xfilename>$(IntDir)\$(TargetName).json</xfilename> <xfilename>$(IntDir)\$(TargetName).json</xfilename>
<debuglevel>0</debuglevel> <debuglevel>0</debuglevel>
<debugids>KeyInput DCD</debugids> <debugids>DCD</debugids>
<versionlevel>0</versionlevel> <versionlevel>0</versionlevel>
<versionids>EmbedStandardResources NO_OPENGL USE_FREETYPE</versionids> <versionids>EmbedStandardResources USE_FREETYPE NO_OPENGL</versionids>
<dump_source>0</dump_source> <dump_source>0</dump_source>
<mapverbosity>0</mapverbosity> <mapverbosity>0</mapverbosity>
<createImplib>0</createImplib> <createImplib>0</createImplib>
@ -176,7 +176,7 @@
<debuglevel>0</debuglevel> <debuglevel>0</debuglevel>
<debugids /> <debugids />
<versionlevel>0</versionlevel> <versionlevel>0</versionlevel>
<versionids>EmbedStandardResources</versionids> <versionids>EmbedStandardResources NO_OPENGL USE_FREETYPE</versionids>
<dump_source>0</dump_source> <dump_source>0</dump_source>
<mapverbosity>0</mapverbosity> <mapverbosity>0</mapverbosity>
<createImplib>0</createImplib> <createImplib>0</createImplib>
@ -214,7 +214,7 @@
<multiobj>0</multiobj> <multiobj>0</multiobj>
<singleFileCompilation>0</singleFileCompilation> <singleFileCompilation>0</singleFileCompilation>
<oneobj>0</oneobj> <oneobj>0</oneobj>
<mscoff>1</mscoff> <mscoff>0</mscoff>
<trace>0</trace> <trace>0</trace>
<quiet>0</quiet> <quiet>0</quiet>
<verbose>0</verbose> <verbose>0</verbose>
@ -277,9 +277,9 @@
<doXGeneration>1</doXGeneration> <doXGeneration>1</doXGeneration>
<xfilename>$(IntDir)\$(TargetName).json</xfilename> <xfilename>$(IntDir)\$(TargetName).json</xfilename>
<debuglevel>0</debuglevel> <debuglevel>0</debuglevel>
<debugids>KeyInput DCD</debugids> <debugids>DCD</debugids>
<versionlevel>0</versionlevel> <versionlevel>0</versionlevel>
<versionids>EmbedStandardResources NO_OPENGL USE_FREETYPE</versionids> <versionids>EmbedStandardResources USE_FREETYPE NO_OPENGL</versionids>
<dump_source>0</dump_source> <dump_source>0</dump_source>
<mapverbosity>0</mapverbosity> <mapverbosity>0</mapverbosity>
<createImplib>0</createImplib> <createImplib>0</createImplib>
@ -382,7 +382,7 @@
<debuglevel>0</debuglevel> <debuglevel>0</debuglevel>
<debugids /> <debugids />
<versionlevel>0</versionlevel> <versionlevel>0</versionlevel>
<versionids>EmbedStandardResources</versionids> <versionids>EmbedStandardResources NO_OPENGL USE_FREETYPE</versionids>
<dump_source>0</dump_source> <dump_source>0</dump_source>
<mapverbosity>0</mapverbosity> <mapverbosity>0</mapverbosity>
<createImplib>0</createImplib> <createImplib>0</createImplib>
@ -618,6 +618,212 @@
<postBuildCommand /> <postBuildCommand />
<filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean> <filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean>
</Config> </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="dlangide">
<Folder name="3rdparty"> <Folder name="3rdparty">
<Folder name="containers"> <Folder name="containers">
@ -718,6 +924,7 @@
<Folder name="d"> <Folder name="d">
<File path="src\dlangide\tools\d\dcdinterface.d" /> <File path="src\dlangide\tools\d\dcdinterface.d" />
<File path="src\dlangide\tools\d\deditortool.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\dparser.d" />
<File path="src\dlangide\tools\d\dsyntax.d" /> <File path="src\dlangide\tools\d\dsyntax.d" />
</Folder> </Folder>
@ -726,6 +933,7 @@
<Folder name="ui"> <Folder name="ui">
<File path="src\dlangide\ui\commands.d" /> <File path="src\dlangide\ui\commands.d" />
<File path="src\dlangide\ui\debuggerui.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\dsourceedit.d" />
<File path="src\dlangide\ui\frame.d" /> <File path="src\dlangide\ui\frame.d" />
<File path="src\dlangide\ui\homescreen.d" /> <File path="src\dlangide\ui\homescreen.d" />

View File

@ -13,6 +13,14 @@ mixin APP_ENTRY_POINT;
/// entry point for dlangui based application /// entry point for dlangui based application
extern (C) int UIAppMain(string[] args) { 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) { debug(TestParser) {
import ddc.lexer.parser; import ddc.lexer.parser;
runParserTests(); runParserTests();

View File

@ -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);
}
}

View File

@ -80,6 +80,8 @@ enum IDEActions : int {
ViewToggleTabPositionMarks, ViewToggleTabPositionMarks,
ViewToggleToolbar, ViewToggleToolbar,
ViewToggleStatusbar, ViewToggleStatusbar,
ToolsOpenDMDTraceLog,
} }
__gshared static this() { __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_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_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 = [ const Action[] STD_IDE_ACTIONS = [
ACTION_EDIT_COPY, ACTION_EDIT_PASTE, ACTION_EDIT_CUT, ACTION_EDIT_COPY, ACTION_EDIT_PASTE, ACTION_EDIT_CUT,

View File

@ -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);
}
}

View File

@ -36,6 +36,7 @@ import ddebug.common.execution;
import ddebug.common.nodebug; import ddebug.common.nodebug;
import ddebug.common.debugger; import ddebug.common.debugger;
import ddebug.gdb.gdbinterface; import ddebug.gdb.gdbinterface;
import dlangide.tools.d.dmdtrace;
import std.conv; import std.conv;
import std.utf; 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)); MenuItem windowItem = new MenuItem(new Action(3, "MENU_WINDOW"c));
//windowItem.add(new Action(30, "MENU_WINDOW_PREFERENCES")); //windowItem.add(new Action(30, "MENU_WINDOW_PREFERENCES"));
windowItem.add(ACTION_WINDOW_CLOSE_DOCUMENT, ACTION_WINDOW_CLOSE_ALL_DOCUMENTS); 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(navItem);
mainMenuItems.add(buildItem); mainMenuItems.add(buildItem);
mainMenuItems.add(debugItem); mainMenuItems.add(debugItem);
mainMenuItems.add(toolsItem);
//mainMenuItems.add(viewItem); //mainMenuItems.add(viewItem);
mainMenuItems.add(windowItem); mainMenuItems.add(windowItem);
mainMenuItems.add(helpItem); 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 createFileDialog(UIString caption, int fileDialogFlags = DialogFlag.Modal | DialogFlag.Resizable | FileDialogFlag.FileMustExist) {
FileDialog dlg = new FileDialog(caption, window, null, fileDialogFlags); FileDialog dlg = new FileDialog(caption, window, null, fileDialogFlags);
dlg.filetypeIcons[".d"] = "text-d"; dlg.filetypeIcons[".d"] = "text-d";
@ -1026,6 +1075,9 @@ class IDEFrame : AppFrame, ProgramExecutionStatusListener, BreakpointListChangeL
case IDEActions.HelpDonate: case IDEActions.HelpDonate:
Platform.instance.openURL(HELP_DONATION_URL); Platform.instance.openURL(HELP_DONATION_URL);
return true; return true;
case IDEActions.ToolsOpenDMDTraceLog:
openDMDTraceLog();
return true;
case IDEActions.HelpAbout: case IDEActions.HelpAbout:
//debug { //debug {
// testDCDFailAfterThreadCreation(); // testDCDFailAfterThreadCreation();

View File

@ -19,10 +19,13 @@ DLANG_IDE_DONATE=Support DlangIDE
DLANG_IDE_DONATE_PAYPAL=Donate via PayPal DLANG_IDE_DONATE_PAYPAL=Donate via PayPal
EXIT=Exit EXIT=Exit
PROFILER_WINDOW=Profiler
ALL_FILES=All files ALL_FILES=All files
SOURCE_FILES=Source files SOURCE_FILES=Source files
WORKSPACE_AND_PROJECT_FILES=Workspace and project files WORKSPACE_AND_PROJECT_FILES=Workspace and project files
IDE_FILES=DlangIDE files IDE_FILES=DlangIDE files
PROFILER_LOG_FILES=DMD Profiler Logs
EDITOR_CONTENT=Editors content EDITOR_CONTENT=Editors content
LOCATION=Location LOCATION=Location
@ -127,6 +130,9 @@ MENU_VIEW_THEME=&Theme
MENU_VIEW_THEME_DEFAULT=&Default MENU_VIEW_THEME_DEFAULT=&Default
MENU_VIEW_THEME_CUSTOM1=&Custom 1 MENU_VIEW_THEME_CUSTOM1=&Custom 1
MENU_TOOLS=Tools
OPEN_DMD_TRACE_LOG=Open DMD profiler log
TAB_LONG_LIST=Long list TAB_LONG_LIST=Long list
TAB_BUTTONS=Buttons TAB_BUTTONS=Buttons
TAB_ANIMATION=Animation TAB_ANIMATION=Animation
@ -145,6 +151,7 @@ MENU_PROJECT_FOLDER_COLLAPSE_ALL=Collapse all
HEADER_SETTINGS=DlangIDE settings HEADER_SETTINGS=DlangIDE settings
HEADER_OPEN_WORKSPACE_OR_PROJECT=Open Workspace or Project HEADER_OPEN_WORKSPACE_OR_PROJECT=Open Workspace or Project
HEADER_OPEN_TEXT_FILE=Open Text File HEADER_OPEN_TEXT_FILE=Open Text File
HEADER_OPEN_DMD_PROFILER_LOG=Open DMD Profiler Log File
HEADER_CLOSE_FILE=Close file HEADER_CLOSE_FILE=Close file
HEADER_CLOSE_TAB=Close tab HEADER_CLOSE_TAB=Close tab
HEADER_PROJECT_SETTINGS=project settings HEADER_PROJECT_SETTINGS=project settings
@ -235,6 +242,7 @@ ERROR_OPEN_WORKSPACE=Cannot open workspace
ERROR_OPENING_FILE=Failed to open file ERROR_OPENING_FILE=Failed to open file
ERROR_OPENING_PROJECT=Error occured while opening project ERROR_OPENING_PROJECT=Error occured while opening project
ERROR_OPENING_WORKSPACE=Error occured while opening workspace 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_FILE_CONTENT_CHANGED=Content of this file has been changed.
MSG_TAB_CONTENT_CHANGED=Content of tab has been changed MSG_TAB_CONTENT_CHANGED=Content of tab has been changed

View File

@ -19,10 +19,13 @@ DLANG_IDE_DONATE=Поддержать DlangIDE
DLANG_IDE_DONATE_PAYPAL=PayPal DLANG_IDE_DONATE_PAYPAL=PayPal
EXIT=Выход EXIT=Выход
PROFILER_WINDOW=Профилировщик
ALL_FILES=Все файлы ALL_FILES=Все файлы
SOURCE_FILES=Исходники SOURCE_FILES=Исходники
WORKSPACE_AND_PROJECT_FILES=Файлы проектов и раб. прост. WORKSPACE_AND_PROJECT_FILES=Файлы проектов и раб. прост.
IDE_FILES=Файлы DlangIDE IDE_FILES=Файлы DlangIDE
PROFILER_LOG_FILES=Файды DMD Profiler
EDITOR_CONTENT=Содержимое редактора EDITOR_CONTENT=Содержимое редактора
LOCATION=Место LOCATION=Место
@ -126,6 +129,9 @@ MENU_VIEW_THEME=&Тема
MENU_VIEW_THEME_DEFAULT=Стандартная MENU_VIEW_THEME_DEFAULT=Стандартная
MENU_VIEW_THEME_CUSTOM1=Пример 1 MENU_VIEW_THEME_CUSTOM1=Пример 1
MENU_TOOLS=Инструменты
OPEN_DMD_TRACE_LOG=Открыть лог DMD profiler
TAB_LONG_LIST=Длинный список TAB_LONG_LIST=Длинный список
TAB_BUTTONS=Кнопки TAB_BUTTONS=Кнопки
TAB_ANIMATION=Анимация TAB_ANIMATION=Анимация
@ -144,6 +150,7 @@ MENU_PROJECT_FOLDER_COLLAPSE_ALL=Свернуть все
HEADER_SETTINGS=DlangIDE настройки HEADER_SETTINGS=DlangIDE настройки
HEADER_OPEN_WORKSPACE_OR_PROJECT=Открыть рабочее пространство или проект HEADER_OPEN_WORKSPACE_OR_PROJECT=Открыть рабочее пространство или проект
HEADER_OPEN_TEXT_FILE=Открыть текстовый файл HEADER_OPEN_TEXT_FILE=Открыть текстовый файл
HEADER_OPEN_DMD_PROFILER_LOG=Открыть файл DMD Profiler Log
HEADER_CLOSE_FILE=Закрыть файл HEADER_CLOSE_FILE=Закрыть файл
HEADER_CLOSE_TAB=Закрыть вкладку HEADER_CLOSE_TAB=Закрыть вкладку
HEADER_PROJECT_SETTINGS=настройки проекта HEADER_PROJECT_SETTINGS=настройки проекта
@ -233,6 +240,7 @@ ERROR_OPEN_WORKSPACE=Невозможно открыть рабочее прос
ERROR_OPENING_FILE=Ошибка открытия файла ERROR_OPENING_FILE=Ошибка открытия файла
ERROR_OPENING_PROJECT=Ошибка в ходе открытия проекта ERROR_OPENING_PROJECT=Ошибка в ходе открытия проекта
ERROR_OPENING_WORKSPACE=Ошибка в ходе открытия рабочего пространства ERROR_OPENING_WORKSPACE=Ошибка в ходе открытия рабочего пространства
ERROR_FAILED_TO_PARSE_TRACE_LOG_FILE=Не удалось обработать файл DMD trace log
MSG_FILE_CONTENT_CHANGED=Содержимое этого файла изменено. MSG_FILE_CONTENT_CHANGED=Содержимое этого файла изменено.
MSG_TAB_CONTENT_CHANGED=Содержимое вкладки изменено MSG_TAB_CONTENT_CHANGED=Содержимое вкладки изменено