summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimur Mustafin/Platform Lab /SRR/Engineer/Samsung Electronics <t.mustafin@partner.samsung.com>2022-09-06 19:44:24 +0300
committerGitHub Enterprise <noreply-CODE@samsung.com>2022-09-06 19:44:24 +0300
commit698b8764a2fbd9d0168e4791f3cc8468984f1973 (patch)
treec1f66f0d4cfdfb608719c061cb21aada85973ee1
parent83b98332edef313709a8ec8d87ff4966b6c54929 (diff)
downloadheaptrack-698b8764a2fbd9d0168e4791f3cc8468984f1973.tar.gz
heaptrack-698b8764a2fbd9d0168e4791f3cc8468984f1973.tar.bz2
heaptrack-698b8764a2fbd9d0168e4791f3cc8468984f1973.zip
Fix Aarch64 work (#100)
* interpret: class name resolve warn only Unresolved nodes ejection corrupts tree structure, it leads to problems on reading the tree in buildObjectTree. * Fix Linux build Changes to make heaptrack build on linux Define USE_KCHART to build all GUI tabs Add Linux instruction * gui: Refactoing and comments * profiler: fix pointer storage in int type * Use OnFunctionLeave as OnTailCall callback Fixes flamegraph picture on architectures with TailCall optimization
-rw-r--r--CMakeLists.txt3
-rw-r--r--LINUX_GUI_BUILD.md39
-rw-r--r--profiler/profiler/src/profiler.cpp13
-rw-r--r--profiler/profiler/src/stackentry.h4
-rw-r--r--src/analyze/accumulatedtracedata.h6
-rw-r--r--src/analyze/gui/CMakeLists.txt4
-rw-r--r--src/analyze/gui/parser.cpp22
-rw-r--r--src/interpret/heaptrack_interpret.cpp1
8 files changed, 70 insertions, 22 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c57c2f2..850259a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -50,6 +50,9 @@ if(HEAPTRACK_BUILD_GUI)
find_package(KF5 COMPONENTS CoreAddons I18n ItemModels ThreadWeaver ConfigWidgets KIO)
find_package(KChart "2.6.0")
set_package_properties(KChart PROPERTIES TYPE RECOMMENDED PURPOSE "Required for the heaptrack_gui executable. Get it from the kdiagram module.")
+ if(KChart_FOUND)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_CHART=1")
+ endif()
endif()
endif()
diff --git a/LINUX_GUI_BUILD.md b/LINUX_GUI_BUILD.md
new file mode 100644
index 0000000..0fe813b
--- /dev/null
+++ b/LINUX_GUI_BUILD.md
@@ -0,0 +1,39 @@
+# Building Heaptrack GUI on Linux
+
+## Prerequisites
+
+Operating system: Ubuntu 18.04 can be used to build Heaptrack GUI.
+
+The following packages are needed:
+
+```bash
+apt-get update && apt-get -y install cmake libsparsehash-dev \
+ build-essential libunwind8-dev libunwind8 libboost-dev \
+ libboost-iostreams-dev libboost-program-options-dev \
+ zlib1g zlib1g-dev libdwarf-dev qt5-default extra-cmake-modules \
+ libkf5coreaddons-dev libkf5i18n-dev libkf5itemmodels-dev \
+ libkf5threadweaver-dev libkf5configwidgets-dev libkf5kiocore5 \
+ libkf5kiowidgets5 kio-dev cpio rpm2cpio clang libkchart2 \
+ libkchart-dev gettext
+```
+
+## Building the GUI application
+
+### How to build
+
+After installing all libraries required it’s possible to build the GUI application itself. It can be done using *cmake* utility from project root directory:
+
+```bash
+cd <heaptrack sources>
+mkdir build-x64; cd build-x64
+cmake ../
+make
+```
+
+### Open collected and interpreted heaptrack file in builded Heaptrack GUI
+
+Heaptrack GUI file is placed in ./bin/ directory after build:
+
+```bash
+./bin/heaptrack_gui --managed <path to heaptrack.interpreted file heaptrack.interpreted.gz file>
+```
diff --git a/profiler/profiler/src/profiler.cpp b/profiler/profiler/src/profiler.cpp
index 29607cc..774e2db 100644
--- a/profiler/profiler/src/profiler.cpp
+++ b/profiler/profiler/src/profiler.cpp
@@ -1,3 +1,4 @@
+#include <cinttypes>
#include "profiler.h"
#include "pal_excerpts.h"
#include "classfactory.h"
@@ -103,7 +104,7 @@ static WCHAR *wszModuleNames = nullptr;
extern __thread StackEntry* g_shadowStack;
__thread StackEntry* g_freeStackEntryListItems = nullptr;
-StackEntry::StackEntry(unsigned int funcId,
+StackEntry::StackEntry(uintptr_t funcId,
const char* className,
const char* methodName,
bool isType,
@@ -342,7 +343,7 @@ HRESULT STDMETHODCALLTYPE Profiler::Initialize(IUnknown *pICorProfilerInfoUnk) {
COR_PRF_ENABLE_FUNCTION_RETVAL | COR_PRF_ENABLE_FRAME_INFO |
COR_PRF_ENABLE_STACK_SNAPSHOT | COR_PRF_MONITOR_CLASS_LOADS |
COR_PRF_ENABLE_OBJECT_ALLOCATED | COR_PRF_MONITOR_OBJECT_ALLOCATED | COR_PRF_MONITOR_GC);
- info->SetEnterLeaveFunctionHooks3WithInfo(OnFunctionEnter, OnFunctionLeave, NULL);
+ info->SetEnterLeaveFunctionHooks3WithInfo(OnFunctionEnter, OnFunctionLeave, OnFunctionLeave);
info->Release();
info = NULL;
}
@@ -427,7 +428,7 @@ HRESULT STDMETHODCALLTYPE
Profiler::ClassLoadFinished(ClassID classId, HRESULT hrStatus) {
if (hrStatus != S_OK) {
- fprintf(stderr, "[W] Failed to load class %x, HRESULT=%x\n", classId, hrStatus);
+ fprintf(stderr, "[W] Failed to load class %" PRIxPTR ", HRESULT=%x\n", classId, hrStatus);
return S_OK;
}
@@ -442,7 +443,7 @@ HRESULT STDMETHODCALLTYPE
hr = GetClassNameFromClassId(info, classId, wszClassName);
if (hr != S_OK) {
- fprintf(stderr, "[W] Failed to retrieve class name for class %x, HRESULT=%x\n", classId, hr);
+ fprintf(stderr, "[W] Failed to retrieve class name for class %" PRIxPTR ", HRESULT=%x\n", classId, hr);
goto Cleanup;
}
@@ -651,7 +652,7 @@ HRESULT STDMETHODCALLTYPE
// We still want the best estimate, even though something went wrong.
if (hr != S_OK) {
- fprintf(stderr, "[W] Unknown type for object %x, HRESULT=%x\n", objectRefIds[i], hr);
+ fprintf(stderr, "[W] Unknown type for object %" PRIxPTR ", HRESULT=%x\n", objectRefIds[i], hr);
continue;
}
@@ -686,7 +687,7 @@ HRESULT STDMETHODCALLTYPE
// We still want the best estimate, even though something went wrong.
if (hr != S_OK) {
- fprintf(stderr, "[W] Unknown type for object %x, HRESULT=%x\n", rootRefIds[i], hr);
+ fprintf(stderr, "[W] Unknown type for object %" PRIxPTR ", HRESULT=%x\n", rootRefIds[i], hr);
continue;
}
diff --git a/profiler/profiler/src/stackentry.h b/profiler/profiler/src/stackentry.h
index 53cf27f..77813c0 100644
--- a/profiler/profiler/src/stackentry.h
+++ b/profiler/profiler/src/stackentry.h
@@ -6,9 +6,9 @@ static constexpr size_t MAX_NAME_LENGTH = 512;
class StackEntry {
public:
- StackEntry(unsigned int funcId, const char* className, const char* methodName, bool isType, StackEntry *next);
+ StackEntry(uintptr_t funcId, const char* className, const char* methodName, bool isType, StackEntry *next);
- unsigned int m_funcId;
+ uintptr_t m_funcId;
char m_className[MAX_NAME_LENGTH + 1];
char m_methodName[MAX_NAME_LENGTH + 1];
bool m_isType;
diff --git a/src/analyze/accumulatedtracedata.h b/src/analyze/accumulatedtracedata.h
index 4002d95..cd5597e 100644
--- a/src/analyze/accumulatedtracedata.h
+++ b/src/analyze/accumulatedtracedata.h
@@ -91,7 +91,7 @@ struct ObjectTreeNode
{
uint64_t gcNum;
uint64_t numChildren;
- uint64_t objectPtr;
+ uint64_t objectPtr; // Object pointer as it was on target
ClassIndex classIndex;
AllocationIndex allocIndex;
};
@@ -364,6 +364,10 @@ struct AccumulatedTraceData
std::vector<IpIndex> opNewIpIndices;
std::vector<AllocationInfo> allocationInfos;
std::vector<ClassIndex> classIndices;
+
+ /* objectTreeNodes is in fact a flat collection of ObjectTreeNodes. The graph structure
+ is provided by ObjectTreeNode::numChildren which indicates how many childrens has current node.
+ Childrens of current node follow in a row with intervals for thier own descendants. */
std::vector<ObjectTreeNode> objectTreeNodes;
AddressRangesMap addressRangeInfos;
diff --git a/src/analyze/gui/CMakeLists.txt b/src/analyze/gui/CMakeLists.txt
index e734554..bf59fbe 100644
--- a/src/analyze/gui/CMakeLists.txt
+++ b/src/analyze/gui/CMakeLists.txt
@@ -2,6 +2,7 @@ set(CMAKE_AUTOMOC 1)
ki18n_wrap_ui(UIFILES
mainwindow.ui
+ aboutdialog.ui
)
unset(BIN_INSTALL_DIR)
@@ -31,6 +32,8 @@ set(SRCFILES
topproxy.cpp
callercalleemodel.cpp
util.cpp
+ aboutdata.cpp
+ aboutdialog.cpp
)
set(LIBRARIES
@@ -60,7 +63,6 @@ endif()
add_definitions(-Wall
-DQT_NO_URL_CAST_FROM_STRING
- -DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII
-DQT_NO_CAST_FROM_BYTEARRAY
-DQT_USE_QSTRINGBUILDER
)
diff --git a/src/analyze/gui/parser.cpp b/src/analyze/gui/parser.cpp
index 940ba9a..a495d62 100644
--- a/src/analyze/gui/parser.cpp
+++ b/src/analyze/gui/parser.cpp
@@ -358,13 +358,13 @@ struct ObjectNode {
}
std::vector<ObjectNode*> m_children;
- size_t index;
+ size_t index; // Index to access vector data.objectTreeNodes
bool visited;
static std::unordered_map<uint64_t, std::unique_ptr<ObjectNode>> nodes;
};
-std::unordered_map<uint64_t, std::unique_ptr<ObjectNode>> ObjectNode::nodes;
+std::unordered_map<uint64_t, std::unique_ptr<ObjectNode>> ObjectNode::nodes; // Key is ObjectTreeNode.objectPtr, object pointer as it was on target
struct TypeTree {
TypeTree()
@@ -397,7 +397,7 @@ struct TypeTree {
auto TT = std::unique_ptr<TypeTree>(new TypeTree());
TT->m_classIndex = data.objectTreeNodes[node->index].classIndex;
TT->m_gcNum = data.objectTreeNodes[node->index].gcNum;
- TT->m_uniqueObjects[node->index] = 1;
+ TT->m_uniqueObjects.insert(node->index);
return TT;
}
@@ -438,7 +438,7 @@ struct TypeTree {
for (auto &grandparent: other->m_parents)
m_parents.push_back(std::move(grandparent));
for (auto& uo: other->m_uniqueObjects) {
- m_uniqueObjects[uo.first]++;
+ m_uniqueObjects.insert(uo);
}
}
@@ -499,15 +499,14 @@ struct TypeTree {
size_t addRefSize(ParserData& data, size_t objectIndex, size_t leafSize) {
int result = 0;
for (auto& uo: m_uniqueObjects) {
- size_t uoIndex = uo.first;
- auto& uoChildren = ObjectNode::nodes[data.objectTreeNodes[uoIndex].objectPtr]->m_children;
+ auto& uoChildren = ObjectNode::nodes[data.objectTreeNodes[uo].objectPtr]->m_children;
for (auto &uoChild: uoChildren) {
if (uoChild->index == objectIndex) {
if (m_parents.size() == 0) {
result += 1;
}
for (auto& parent: m_parents)
- result += parent->addRefSize(data, uoIndex, leafSize);
+ result += parent->addRefSize(data, uo, leafSize);
}
}
}
@@ -517,7 +516,7 @@ struct TypeTree {
ClassIndex m_classIndex;
std::vector<std::unique_ptr<TypeTree>> m_parents;
- std::unordered_map<size_t, uint64_t> m_uniqueObjects;
+ std::unordered_set<size_t> m_uniqueObjects; // Indexes in data.objectTreeNodes
uint64_t m_referencedSize;
int m_gcNum;
};
@@ -783,7 +782,7 @@ ObjectRowData objectRowDataFromTypeTree(ParserData& data, TypeTree* tree) {
rowData.allocations = tree->m_uniqueObjects.size();
rowData.referenced = tree->m_referencedSize;
for (auto &uo: tree->m_uniqueObjects) {
- rowData.allocated += data.allocationInfos[data.objectTreeNodes[uo.first].allocIndex.index].size;
+ rowData.allocated += data.allocationInfos[data.objectTreeNodes[uo].allocIndex.index].size;
}
for (auto& parent: tree->m_parents)
rowData.children.push_back(objectRowDataFromTypeTree(data, parent.get()));
@@ -824,6 +823,7 @@ ObjectTreeData buildObjectTree(ParserData& data)
auto nodePtr = node.get();
ObjectNode::nodes.insert(std::pair<uint64_t, std::unique_ptr<ObjectNode>>(
0, std::move(node)));
+ Q_ASSERT(data.objectTreeNodes[nodePtr->index].objectPtr == 0 && "Incorrect root node");
TypeTree root;
root.m_gcNum = data.objectTreeNodes[nodePtr->index].gcNum;
root.m_parents = std::move(TypeTree::createBottomUp(data, nodePtr));
@@ -832,8 +832,8 @@ ObjectTreeData buildObjectTree(ParserData& data)
for (auto& parent: root.m_parents) {
for (auto &uo: parent->m_uniqueObjects) {
for (auto &grandparent: parent->m_parents) {
- size_t leafSize = data.allocationInfos[data.objectTreeNodes[uo.first].allocIndex.index].size;
- size_t chains = grandparent->addRefSize(data, uo.first, leafSize);
+ size_t leafSize = data.allocationInfos[data.objectTreeNodes[uo].allocIndex.index].size;
+ size_t chains = grandparent->addRefSize(data, uo, leafSize);
parent->m_referencedSize += chains * leafSize;
}
}
diff --git a/src/interpret/heaptrack_interpret.cpp b/src/interpret/heaptrack_interpret.cpp
index 9b69853..5a9b539 100644
--- a/src/interpret/heaptrack_interpret.cpp
+++ b/src/interpret/heaptrack_interpret.cpp
@@ -813,7 +813,6 @@ int main(int /*argc*/, char** /*argv*/)
const auto classId = data.addClass(classPointer);
if (classId == 0 && classPointer != 0) {
cerr << "[W] Unknown class id (" << classPointer << ") here: " << reader.line() << endl;
- continue;
}
const auto objectId = ptrToIndex.peekPointer(objectPointer);