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>
<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" />

View File

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

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,
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,

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.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();

View File

@ -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

View File

@ -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=Содержимое вкладки изменено