Commit a0587185 by Mārtiņš Možeiko

Importing all files.

parent 3afd869f
Build
*.zip
project(CxxProfiler)
cmake_minimum_required(VERSION 3.2)
if(WIN32)
# link automatically to qtmain.lib on Windows
cmake_policy(SET CMP0020 NEW)
endif()
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Concurrent REQUIRED)
set_property(GLOBAL PROPERTY USE_FOLDERS OFF)
add_definitions("-D_UNICODE -DUNICODE -D_SCL_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_DEPRECATE")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /GF /Gy /GS- /GR- /GL")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} /GF /Gy /GS- /GR- /GL")
set(CMAKE_EXE_LINKER_FLAGS "/INCREMENTAL:NO")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/LTCG /OPT:ICF /OPT:REF")
macro(use_pch TARGET HEADER SOURCE)
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS "/Yu${HEADER} /FI${HEADER}")
set_source_files_properties(${SOURCE} PROPERTIES COMPILE_FLAGS "/Yc${HEADER}")
endmacro(use_pch)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CxxProfiler_BINARY_DIR}/Build")
add_subdirectory(CxxProfiler)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /WX")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(UI
MainWindow.ui
NewDialog.ui
RunningDialog.ui
SymbolWidget.ui
)
set(MOC
Profiler.h
SyntaxHighlighter.h
MainWindow.h
NewDialog.h
RunningDialog.h
SymbolWidget.h
SourceWidget.h
SourceLoader.h
)
set(SOURCE
Resources.rc
Precompiled.h
Precompiled.cpp
Utils.h
Utils.cpp
Main.cpp
Profiler.cpp
SyntaxHighlighter.cpp
MainWindow.cpp
NewDialog.cpp
RunningDialog.cpp
SymbolWidget.cpp
SourceWidget.cpp
SourceLoader.cpp
Symbols.cpp
Symbols.h
Version.h
)
set(QRC Resources.qrc)
qt5_wrap_ui(UI_OUT ${UI})
qt5_wrap_cpp(MOC_OUT ${MOC})
qt5_add_resources(QRC_OUT ${QRC} OPTIONS "-no-compress")
source_group("" FILES ${SOURCE} ${MOC} ${UI} ${QRC})
source_group("Generated" FILES ${MOC_OUT} ${UI_OUT} ${MOC_OUT} ${QRC_OUT})
add_executable(CxxProfiler WIN32 ${SOURCE} ${MOC} ${MOC_OUT} ${UI_OUT} ${MOC_OUT} ${QRC_OUT})
qt5_use_modules(CxxProfiler Widgets Concurrent)
use_pch(CxxProfiler Precompiled.h Precompiled.cpp)
#include "MainWindow.h"
#include "Version.h"
namespace
{
void EnableDebugPrivileges()
{
HANDLE token;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
{
LUID luid;
if (LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &luid))
{
TOKEN_PRIVILEGES state;
state.PrivilegeCount = 1;
state.Privileges[0].Luid = luid;
state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(token, FALSE, &state, sizeof(state), nullptr, nullptr);
}
CloseHandle(token);
}
}
}
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
app.setApplicationName("C/C++ Profiler");
app.setWindowIcon(QIcon(":/CxxProfiler/Icon.png"));
EnableDebugPrivileges();
MainWindow window;
window.show();
return app.exec();
}
#pragma once
#include "Precompiled.h"
#include "ui_MainWindow.h"
class SymbolWidget;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
~MainWindow();
private slots:
void toggleShowWithEmptyFiles(bool show);
void popupAction(QAction* action);
bool saveData();
private:
Ui::MainWindow ui;
QTabWidget* mTabs;
SymbolWidget* mCallGraph;
SymbolWidget* mFlatProfile;
QAction* actGoto;
QAction* actCopyName;
QAction* actCopyModule;
QAction* actCopyFilename;
QAction* actHide;
QAction* actHideAll;
QAction* actRestore;
QAction* actExpand;
QAction* actCollapse;
QAction* actExploreTo;
QAction* actOpenSymbolFile;
QAction* actOpenSymbolVS;
bool mShowWithEmptyFiles = false;
QByteArray mData;
bool mDataSaved = true;
uint32_t mDataPointerSize;
void loadData(uint32_t pointerSize, const QByteArray& data);
void closeEvent(QCloseEvent* ev) override;
};
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>C/C++ Profiler</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout"/>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFILE">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="actFileNew"/>
<addaction name="separator"/>
<addaction name="actFileOpen"/>
<addaction name="actFileSave"/>
<addaction name="separator"/>
<addaction name="actFileQuit"/>
</widget>
<widget class="QMenu" name="menu_Help">
<property name="title">
<string>&amp;Help</string>
</property>
<addaction name="actHelpAbout"/>
<addaction name="actHelpAboutQt"/>
</widget>
<addaction name="menuFILE"/>
<addaction name="menu_Help"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actHelpAbout">
<property name="text">
<string>&amp;About</string>
</property>
<property name="menuRole">
<enum>QAction::AboutRole</enum>
</property>
</action>
<action name="actHelpAboutQt">
<property name="text">
<string>About &amp;Qt</string>
</property>
<property name="menuRole">
<enum>QAction::AboutQtRole</enum>
</property>
</action>
<action name="actFileNew">
<property name="text">
<string>&amp;New...</string>
</property>
<property name="shortcut">
<string>Ctrl+N</string>
</property>
</action>
<action name="actFileSave">
<property name="text">
<string>&amp;Save...</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="actFileOpen">
<property name="text">
<string>&amp;Open...</string>
</property>
<property name="shortcut">
<string>Ctrl+O</string>
</property>
</action>
<action name="actFileQuit">
<property name="text">
<string>Quit</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
<property name="menuRole">
<enum>QAction::QuitRole</enum>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>
#pragma once
#include "Precompiled.h"
#include "Utils.h"
#include "Profiler.h"
#include "ui_NewDialog.h"
class NewDialog : public QDialog
{
Q_OBJECT
public:
enum
{
RunNewApplication = -1,
AttachToProcess = -2,
};
explicit NewDialog(QWidget* parent);
~NewDialog();
QString getApplication() const;
QString getFolder() const;
QString getArguments() const;
DWORD getProcessId() const;
ProfilerOptions getOptions() const;
private slots:
void updateProcessList();
private:
Ui::NewDialog ui;
QTimer mTimer;
CpuUsage mCpuUsage;
QSet<DWORD> mProcessIds;
void saveSettings() const;
};
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewDialog</class>
<widget class="QDialog" name="NewDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>576</width>
<height>575</height>
</rect>
</property>
<property name="windowTitle">
<string>New</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
<item>
<widget class="QLabel" name="lblIcon">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblInfo">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="grpRunNew">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Run new application</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lblRunNewApplication">
<property name="text">
<string>Application:</string>
</property>
<property name="buddy">
<cstring>lineRunNewApplication</cstring>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="lblRunNewFolder">
<property name="text">
<string>Folder:</string>
</property>
<property name="buddy">
<cstring>lineRunNewFolder</cstring>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="lblRunNewArguments">
<property name="text">
<string>Arguments:</string>
</property>
<property name="buddy">
<cstring>lineRunNewArguments</cstring>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="lineRunNewArguments"/>
</item>
<item row="1" column="3">
<widget class="QToolButton" name="btnRunNewFolder">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="lineRunNewApplication"/>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="lineRunNewFolder"/>
</item>
<item row="0" column="3">
<widget class="QToolButton" name="btnRunNewApplication">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="3" column="2" colspan="2" alignment="Qt::AlignRight">
<widget class="QPushButton" name="btnRunNew">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Run</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="grpAttach">
<property name="title">
<string>Attach to running process</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeWidget" name="treeAttach">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="columnCount">
<number>3</number>
</property>
<attribute name="headerStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>PID</string>
</property>
</column>
<column>
<property name="text">
<string>CPU usage %</string>
</property>
</column>
<column>
<property name="text">
<string>Process</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="btnAttach"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="grpOptions">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Options</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0,1">
<item row="0" column="0">
<widget class="QLabel" name="lblOptionsCapture">
<property name="text">
<string>Capture OutputDebugString:</string>
</property>
<property name="buddy">
<cstring>chkOptionsCapture</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="chkDownloadSymbols">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="chkOptionsCapture">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblDownloadSymbols">
<property name="text">
<string>Download Microsoft symbols:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblOptionsSamplingFreq">
<property name="text">
<string>Sampling frequency (ms):</string>
</property>
<property name="buddy">
<cstring>spnOptionsSamplingFreq</cstring>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="lblDownloadInfo">
<property name="text">
<string>&lt;a href=&quot;?&quot;&gt;(?)&lt;/a&gt;</string>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QSpinBox" name="spnOptionsSamplingFreq">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="btnCancel">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>lineRunNewApplication</tabstop>
<tabstop>btnRunNewApplication</tabstop>
<tabstop>lineRunNewFolder</tabstop>
<tabstop>btnRunNewFolder</tabstop>
<tabstop>lineRunNewArguments</tabstop>
<tabstop>btnRunNew</tabstop>
<tabstop>treeAttach</tabstop>
<tabstop>chkOptionsCapture</tabstop>
<tabstop>spnOptionsSamplingFreq</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>btnCancel</sender>
<signal>accepted()</signal>
<receiver>NewDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>btnCancel</sender>
<signal>rejected()</signal>
<receiver>NewDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
#include "Precompiled.h"
#pragma comment (lib, "winmm.lib")
#pragma comment (lib, "dbghelp.lib")
#pragma once
#include <stdint.h>
#pragma warning (push, 0)
#define DBGHELP_TRANSLATE_TCHAR
#define NOMINMAX
#include <windows.h>
#include <atlbase.h>
#include <mmsystem.h>
#include <tlhelp32.h>
#include <psapi.h>
#include <dbghelp.h>
#include <QtCore>
#include <QtConcurrent>
#include <QtWidgets>
#include <QtGui>
#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("8.0") lcid("0") raw_interfaces_only named_guids
#pragma warning (pop)
#pragma once
#include "Precompiled.h"
#include "Symbols.h"
struct ProfilerOptions
{
uint32_t samplingFreqInMs;
bool captureDebugOutputString;
bool downloadSymbols;
};
struct Module
{
HANDLE handle;
QString name;
uint64_t address;
uint32_t size;
};
struct CallStackEntry
{
SymbolPtr symbol;
uint32_t line = 0;
uint32_t offset = 0;
};
typedef QVector<CallStackEntry> ThreadCallStack;
typedef QVector<ThreadCallStack> CallStack;
class Profiler : public QThread
{
Q_OBJECT
public:
Profiler(const ProfilerOptions& options);
~Profiler();
void attach(DWORD pid);
void execute(const QString& command, const QString& folder, const QString& arguments);
bool isAttached() const;
uint32_t getSizeOfPointer() const;
uint32_t getThreadCount() const;
uint64_t getCollectedSamples() const;
QByteArray serializeCallStacks() const;
public slots:
void stop();
signals:
void attached(HANDLE process);
void message(const QString& message);
void finished();
private:
void process();
void sample();
void createProcess(DWORD processId, DWORD threadId, const CREATE_PROCESS_DEBUG_INFO* info);
void exitProcess