Skip to content

Commit 1eedc28

Browse files
Nikita Nazarovnikita-nazarov
authored andcommitted
Add retained and shallow sizes by class and by objects actions
1 parent aa13202 commit 1eedc28

27 files changed

+910
-351
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ venv/**
2323

2424
# CMake
2525
cmake-build-*/
26+
CMakeFiles/**
2627

2728
# Windows build directories
2829
build32/**

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ add_library(memory_agent SHARED
3939
src/allocation_sampling.cpp
4040
src/progress_manager.cpp
4141
src/sizes/retained_size_via_dominator_tree.cpp
42+
src/sizes/dominator_tree.cpp
4243
)
4344

4445
if ((UNIX OR MINGW) AND NOT APPLE)

src/agent.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "sizes/retained_size_via_dominator_tree.h"
1515
#include "sizes/retained_size_by_classes.h"
1616
#include "allocation_sampling.h"
17+
#include "sizes/retained_size_by_objects.h"
1718

1819
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
1920

@@ -23,8 +24,6 @@
2324
static GlobalAgentData *gdata = nullptr;
2425
static bool canSampleAllocations = false;
2526

26-
extern void handleOptions(const char *);
27-
2827
static void setRequiredCapabilities(jvmtiEnv *jvmti, jvmtiCapabilities &effective) {
2928
jvmtiCapabilities potential;
3029
std::memset(&potential, 0, sizeof(jvmtiCapabilities));
@@ -107,7 +106,7 @@ extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
107106
}
108107

109108
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) {
110-
debug("on agent unload");
109+
logger::debug("on agent unload");
111110
delete gdata;
112111
}
113112

@@ -158,7 +157,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_intellij_memory_agent_IdeaNativeAgentPro
158157
JNIEnv *env,
159158
jobject thisObject,
160159
jobjectArray objects) {
161-
return RetainedSizeViaDominatorTreeAction(env, gdata->jvmti, thisObject).run(objects);
160+
return RetainedSizeByObjectsAction(env, gdata->jvmti, thisObject).run(objects);
162161
}
163162

164163
extern "C"
@@ -221,6 +220,23 @@ JNIEXPORT jobjectArray JNICALL Java_com_intellij_memory_agent_IdeaNativeAgentPro
221220
return GetAllReachableObjectsOfClassAction(env, gdata->jvmti, thisObject).run(startObject, suspectClass);
222221
}
223222

223+
extern "C"
224+
JNIEXPORT jobjectArray JNICALL Java_com_intellij_memory_agent_IdeaNativeAgentProxy_getShallowAndRetainedSizeByObjects(
225+
JNIEnv *env,
226+
jobject thisObject,
227+
jobjectArray objects) {
228+
return RetainedSizeViaDominatorTreeAction(env, gdata->jvmti, thisObject).run(objects);
229+
}
230+
231+
extern "C"
232+
JNIEXPORT jobjectArray JNICALL Java_com_intellij_memory_agent_IdeaNativeAgentProxy_getShallowAndRetainedSizeByClass(
233+
JNIEnv *env,
234+
jobject thisObject,
235+
jobject classRef,
236+
jlong objectsLimit) {
237+
return RetainedSizeByClassViaDominatorTreeAction(env, gdata->jvmti, thisObject).run(classRef, objectsLimit);
238+
}
239+
224240
extern "C"
225241
JNIEXPORT jboolean JNICALL Java_com_intellij_memory_agent_IdeaNativeAgentProxy_setHeapSamplingInterval(
226242
JNIEnv *env,

src/sizes/dominator_tree.cpp

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2+
3+
#include <queue>
4+
#include "dominator_tree.h"
5+
6+
namespace {
7+
void link(long v, long w, std::vector<long> &ancestor) {
8+
ancestor[w] = v;
9+
}
10+
11+
void compress(long v, std::vector<long> &ancestor, std::vector<long> &label, std::vector<long> &semi) {
12+
if (ancestor[ancestor[v]] != -1) {
13+
compress(ancestor[v], ancestor, label, semi);
14+
if (semi[label[ancestor[v]]] < semi[label[v]]) {
15+
label[v] = label[ancestor[v]];
16+
}
17+
ancestor[v] = ancestor[ancestor[v]];
18+
}
19+
}
20+
21+
long eval(long v, std::vector<long> &ancestor, std::vector<long> &label, std::vector<long> &semi) {
22+
if (ancestor[v] == -1) {
23+
return v;
24+
}
25+
compress(v, ancestor, label, semi);
26+
27+
return label[v];
28+
}
29+
30+
void dfs(
31+
jlong v, jlong &n,
32+
const std::vector<std::vector<jlong>> &graph,
33+
std::vector <jlong> &semi,
34+
std::vector <jlong> &parent,
35+
std::vector <jlong> &vertex,
36+
std::vector<std::vector<jlong>> &pred
37+
) {
38+
semi[v] = n;
39+
vertex[n] = v;
40+
n++;
41+
for (jlong w : graph[v]) {
42+
if (w != 0 && semi[w] == 0) {
43+
parent[w] = v;
44+
dfs(w, n, graph, semi, parent, vertex, pred);
45+
}
46+
pred[w].push_back(v);
47+
}
48+
}
49+
}
50+
51+
std::vector<jlong> calculateRetainedSizes(const std::vector<std::vector<jlong>> &graph, const std::vector<jlong> &sizes) {
52+
size_t numOfVertices = graph.size();
53+
54+
std::vector<jlong> semi(numOfVertices);
55+
std::vector<jlong> parent(numOfVertices);
56+
std::vector<jlong> vertex(numOfVertices);
57+
std::vector<std::vector<jlong>> pred(numOfVertices);
58+
std::vector<std::vector<jlong>> bucket(numOfVertices);
59+
std::vector<jlong> ancestor(numOfVertices);
60+
std::vector<jlong> label(numOfVertices);
61+
std::vector<jlong> dom(numOfVertices);
62+
std::vector<jlong> retained_sizes(numOfVertices);
63+
std::vector<jlong> child(numOfVertices);
64+
std::vector<jlong> link_size(numOfVertices);
65+
66+
for (jlong i = 0; i < numOfVertices; i++) {
67+
retained_sizes[i] = sizes[i];
68+
label[i] = i;
69+
link_size[i] = 1;
70+
ancestor[i] = -1;
71+
}
72+
73+
link_size[0] = 0;
74+
label[0] = 0;
75+
semi[0] = 0;
76+
77+
jlong n = 0;
78+
dfs(0, n, graph, semi, parent, vertex, pred);
79+
80+
for (jlong i = n - 1; i > 0; i--) {
81+
jlong w = vertex[i];
82+
for (jlong v : pred[w]) {
83+
jlong u = eval(v, ancestor, label, semi);
84+
if (semi[u] < semi[w]) {
85+
semi[w] = semi[u];
86+
}
87+
}
88+
bucket[vertex[semi[w]]].push_back(w);
89+
link(parent[w], w, ancestor);
90+
91+
for (jlong v : bucket[parent[w]]) {
92+
jlong u = eval(v, ancestor, label, semi);
93+
if (semi[u] < semi[v]) {
94+
dom[v] = u;
95+
} else {
96+
dom[v] = parent[w];
97+
}
98+
}
99+
bucket[parent[w]].clear();
100+
}
101+
102+
dom[0] = -1;
103+
std::vector<jlong> childCount(numOfVertices);
104+
for (jlong i = 1; i < n; i++) {
105+
jlong w = vertex[i];
106+
if (dom[w] != vertex[semi[w]]) {
107+
dom[w] = dom[dom[w]];
108+
}
109+
110+
if (dom[w] >= 0) {
111+
childCount[dom[w]]++;
112+
}
113+
}
114+
115+
std::queue<jlong> leaves;
116+
for (jlong i = 1; i < n; i++) {
117+
if (childCount[i] == 0) {
118+
leaves.push(i);
119+
}
120+
}
121+
122+
while (!leaves.empty()) {
123+
jlong leaf = leaves.front();
124+
leaves.pop();
125+
jlong d = dom[leaf];
126+
if (d >= 0) {
127+
retained_sizes[d] += retained_sizes[leaf];
128+
if (--childCount[d] == 0) {
129+
leaves.push(d);
130+
}
131+
}
132+
}
133+
134+
return retained_sizes;
135+
}

src/sizes/dominator_tree.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2+
3+
#ifndef MEMORY_AGENT_DOMINATOR_TREE_H
4+
#define MEMORY_AGENT_DOMINATOR_TREE_H
5+
6+
#include <vector>
7+
#include <jni.h>
8+
9+
std::vector<jlong> calculateRetainedSizes(const std::vector<std::vector<jlong>> &graph, const std::vector<jlong> &sizes);
10+
11+
#endif //MEMORY_AGENT_DOMINATOR_TREE_H

0 commit comments

Comments
 (0)