Skip to content

Commit b414666

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

File tree

8 files changed

+135
-119
lines changed

8 files changed

+135
-119
lines changed

src/agent.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,20 +221,20 @@ JNIEXPORT jobjectArray JNICALL Java_com_intellij_memory_agent_IdeaNativeAgentPro
221221
}
222222

223223
extern "C"
224-
JNIEXPORT jobjectArray JNICALL Java_com_intellij_memory_agent_IdeaNativeAgentProxy_getShallowAndRetainedSizeByObjects(
224+
JNIEXPORT jobjectArray JNICALL Java_com_intellij_memory_agent_IdeaNativeAgentProxy_getShallowAndRetainedSizesByObjects(
225225
JNIEnv *env,
226226
jobject thisObject,
227227
jobjectArray objects) {
228-
return RetainedSizeViaDominatorTreeAction(env, gdata->jvmti, thisObject).run(objects);
228+
return RetainedSizesViaDominatorTreeAction(env, gdata->jvmti, thisObject).run(objects);
229229
}
230230

231231
extern "C"
232-
JNIEXPORT jobjectArray JNICALL Java_com_intellij_memory_agent_IdeaNativeAgentProxy_getShallowAndRetainedSizeByClass(
232+
JNIEXPORT jobjectArray JNICALL Java_com_intellij_memory_agent_IdeaNativeAgentProxy_getSortedShallowAndRetainedSizesByClass(
233233
JNIEnv *env,
234234
jobject thisObject,
235235
jobject classRef,
236236
jlong objectsLimit) {
237-
return RetainedSizeByClassViaDominatorTreeAction(env, gdata->jvmti, thisObject).run(classRef, objectsLimit);
237+
return RetainedSizesByClassViaDominatorTreeAction(env, gdata->jvmti, thisObject).run(classRef, objectsLimit);
238238
}
239239

240240
extern "C"

src/sizes/dominator_tree.cpp

Lines changed: 26 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
#include "dominator_tree.h"
55

66
namespace {
7-
void link(long v, long w, std::vector<long> &ancestor) {
7+
using jlongs = std::vector<jlong>;
8+
using graph_t = std::vector<jlongs>;
9+
10+
void link(jlong v, jlong w, jlongs &ancestor) {
811
ancestor[w] = v;
912
}
1013

11-
void compress(long v, std::vector<long> &ancestor, std::vector<long> &label, std::vector<long> &semi) {
14+
void compress(jlong v, jlongs &ancestor, jlongs &label, jlongs &semi) {
1215
if (ancestor[ancestor[v]] != -1) {
1316
compress(ancestor[v], ancestor, label, semi);
1417
if (semi[label[ancestor[v]]] < semi[label[v]]) {
@@ -18,7 +21,7 @@ namespace {
1821
}
1922
}
2023

21-
long eval(long v, std::vector<long> &ancestor, std::vector<long> &label, std::vector<long> &semi) {
24+
jlong eval(jlong v, jlongs &ancestor, jlongs &label, jlongs &semi) {
2225
if (ancestor[v] == -1) {
2326
return v;
2427
}
@@ -27,14 +30,8 @@ namespace {
2730
return label[v];
2831
}
2932

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-
) {
33+
void dfs(jlong v, jlong &n, const graph_t &graph, jlongs &semi,
34+
jlongs &parent, jlongs &vertex, graph_t &pred) {
3835
semi[v] = n;
3936
vertex[n] = v;
4037
n++;
@@ -48,33 +45,25 @@ namespace {
4845
}
4946
}
5047

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];
48+
jlongs calculateRetainedSizesViaDominatorTree(const graph_t &graph, const jlongs &sizes) {
49+
auto n = static_cast<jlong>(graph.size());
50+
jlongs semi(n);
51+
jlongs parent(n);
52+
jlongs vertex(n);
53+
jlongs ancestor(n);
54+
jlongs label(n);
55+
jlongs dom(n);
56+
jlongs retainedSizes(n);
57+
graph_t pred(n);
58+
graph_t bucket(n);
59+
60+
for (jlong i = 0; i < n; i++) {
61+
retainedSizes[i] = sizes[i];
6862
label[i] = i;
69-
link_size[i] = 1;
7063
ancestor[i] = -1;
7164
}
7265

73-
link_size[0] = 0;
74-
label[0] = 0;
75-
semi[0] = 0;
76-
77-
jlong n = 0;
66+
n = 0;
7867
dfs(0, n, graph, semi, parent, vertex, pred);
7968

8069
for (jlong i = n - 1; i > 0; i--) {
@@ -100,7 +89,7 @@ std::vector<jlong> calculateRetainedSizes(const std::vector<std::vector<jlong>>
10089
}
10190

10291
dom[0] = -1;
103-
std::vector<jlong> childCount(numOfVertices);
92+
jlongs childCount(n);
10493
for (jlong i = 1; i < n; i++) {
10594
jlong w = vertex[i];
10695
if (dom[w] != vertex[semi[w]]) {
@@ -124,12 +113,12 @@ std::vector<jlong> calculateRetainedSizes(const std::vector<std::vector<jlong>>
124113
leaves.pop();
125114
jlong d = dom[leaf];
126115
if (d >= 0) {
127-
retained_sizes[d] += retained_sizes[leaf];
116+
retainedSizes[d] += retainedSizes[leaf];
128117
if (--childCount[d] == 0) {
129118
leaves.push(d);
130119
}
131120
}
132121
}
133122

134-
return retained_sizes;
123+
return retainedSizes;
135124
}

src/sizes/dominator_tree.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <vector>
77
#include <jni.h>
88

9-
std::vector<jlong> calculateRetainedSizes(const std::vector<std::vector<jlong>> &graph, const std::vector<jlong> &sizes);
9+
std::vector<jlong> calculateRetainedSizesViaDominatorTree(const std::vector<std::vector<jlong>> &graph,
10+
const std::vector<jlong> &sizes);
1011

1112
#endif //MEMORY_AGENT_DOMINATOR_TREE_H

src/sizes/retained_size_via_dominator_tree.cpp

Lines changed: 75 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -128,110 +128,113 @@ namespace {
128128

129129
return JVMTI_VISIT_OBJECTS;
130130
}
131+
132+
jobjectArray getObjectArrayOfSize(JNIEnv *env, size_t size) {
133+
return env->NewObjectArray(static_cast<jsize>(size), env->FindClass("java/lang/Object"), nullptr);
134+
}
131135
}
132136

133-
jobjectArray RetainedSizeViaDominatorTreeAction::executeOperation(jobjectArray objects) {
134-
SizesViaDominatorTreeHeapDumpInfo info;
135-
jvmtiError err = info.initAndSetTagsForObjects(env, jvmti, objects);
136-
if (err != JVMTI_ERROR_NONE) return nullptr;
137+
template<typename RESULT_TYPE, typename... ARGS_TYPES>
138+
jvmtiError RetainedSizesAction<RESULT_TYPE, ARGS_TYPES...>::calculateRetainedSizes(jobjectArray objects,
139+
std::vector<jlong> &retainedSizes,
140+
SizesViaDominatorTreeHeapDumpInfo &info) {
141+
jvmtiError err = info.initAndSetTagsForObjects(this->env, this->jvmti, objects);
142+
if (!isOk(err)) return err;
137143

138144
// We set a tag for the input array to ignore it during traversal
139-
err = jvmti->SetTag(objects, MOCK_REFERRER_TAG);
140-
if (err != JVMTI_ERROR_NONE) return nullptr;
145+
err = this->jvmti->SetTag(objects, MOCK_REFERRER_TAG);
146+
if (!isOk(err)) return err;
141147

142-
progressManager.updateProgress(10, "Traversing heap for the first time...");
148+
this->progressManager.updateProgress(10, "Traversing heap for the first time...");
143149
logger::resetTimer();
144-
err = FollowReferences(0, nullptr, nullptr, firstTraversal, &info, "first traversal");
150+
err = this->FollowReferences(0, nullptr, nullptr, firstTraversal, &info);
145151
logger::logPassedTime();
146-
if (err != JVMTI_ERROR_NONE || shouldStopExecution()) return nullptr;
152+
if (!isOk(err) || this->shouldStopExecution()) return err;
147153

148154
logger::resetTimer();
149-
progressManager.updateProgress(60, "Traversing heap for the second time...");
150-
err = FollowReferences(0, nullptr, objects, secondTraversal, &info, "second traversal");
155+
this->progressManager.updateProgress(60, "Traversing heap for the second time...");
156+
err = this->FollowReferences(0, nullptr, objects, secondTraversal, &info);
151157
logger::logPassedTime();
152-
if (err != JVMTI_ERROR_NONE || shouldStopExecution()) return nullptr;
158+
if (!isOk(err) || this->shouldStopExecution()) return err;
153159

154-
progressManager.updateProgress(80, "Calculating retained size...");
160+
this->progressManager.updateProgress(80, "Calculating retained size...");
155161
info.setUpNeighboursForMasterNode();
156-
std::vector<jlong> retained_sizes = calculateRetainedSizes(info.graph, info.sizes);
162+
retainedSizes = calculateRetainedSizesViaDominatorTree(info.graph, info.sizes);
163+
164+
return err;
165+
}
166+
167+
template<typename RESULT_TYPE, typename... ARGS_TYPES>
168+
RetainedSizesAction<RESULT_TYPE, ARGS_TYPES...>::RetainedSizesAction(JNIEnv *env, jvmtiEnv *jvmti, jobject object) :
169+
MemoryAgentAction<RESULT_TYPE, ARGS_TYPES...>(env, jvmti, object) {
170+
171+
}
172+
173+
jobjectArray RetainedSizesViaDominatorTreeAction::executeOperation(jobjectArray objects) {
174+
SizesViaDominatorTreeHeapDumpInfo info;
175+
std::vector<jlong> retainedSizes;
176+
jvmtiError err = calculateRetainedSizes(objects, retainedSizes, info);
177+
if (!isOk(err) || shouldStopExecution()) return nullptr;
157178

158179
progressManager.updateProgress(95, "Extracting answer...");
180+
return constructResultObject(objects, retainedSizes, info);
181+
}
182+
183+
jobjectArray RetainedSizesViaDominatorTreeAction::constructResultObject(jobjectArray objects,
184+
const std::vector<jlong> &retainedSizes,
185+
const SizesViaDominatorTreeHeapDumpInfo &info) {
159186
jsize size = env->GetArrayLength(objects);
160187
std::vector<jlong> shallowSizes;
161-
std::vector<jlong> retainedSizes;
162-
retainedSizes.reserve(size);
188+
std::vector<jlong> resultingRetainedSizes;
189+
resultingRetainedSizes.reserve(size);
163190
shallowSizes.reserve(size);
164191
for (jsize i = 0; i < size; i++) {
165192
jobject object = env->GetObjectArrayElement(objects, i);
166193
jlong tag;
167194
jvmti->GetTag(object, &tag);
168-
retainedSizes.push_back(retained_sizes[tag]);
195+
resultingRetainedSizes.push_back(retainedSizes[tag]);
169196
shallowSizes.push_back(info.sizes[tag]);
170197
}
171-
172-
jclass langObject = env->FindClass("java/lang/Object");
173-
jobjectArray result = env->NewObjectArray(2, langObject, nullptr);
198+
jobjectArray result = getObjectArrayOfSize(env, 2);
174199
env->SetObjectArrayElement(result, 0, toJavaArray(env, shallowSizes));
175-
env->SetObjectArrayElement(result, 1, toJavaArray(env, retainedSizes));
176-
if (!isOk(err)) {
177-
handleError(jvmti, err, "Could not estimate retained size by classes");
178-
return nullptr;
179-
}
200+
env->SetObjectArrayElement(result, 1, toJavaArray(env, resultingRetainedSizes));
201+
180202
return result;
181203
}
182204

183-
jvmtiError RetainedSizeViaDominatorTreeAction::cleanHeap() {
205+
jvmtiError RetainedSizesViaDominatorTreeAction::cleanHeap() {
184206
return removeAllTagsFromHeap(jvmti, nullptr);
185207
}
186208

187-
RetainedSizeViaDominatorTreeAction::RetainedSizeViaDominatorTreeAction(JNIEnv *env, jvmtiEnv *jvmti, jobject object) :
188-
MemoryAgentAction(env, jvmti, object) {
209+
RetainedSizesViaDominatorTreeAction::RetainedSizesViaDominatorTreeAction(JNIEnv *env, jvmtiEnv *jvmti, jobject object) :
210+
RetainedSizesAction(env, jvmti, object) {
189211
}
190212

191-
jobjectArray RetainedSizeByClassViaDominatorTreeAction::executeOperation(jobject classRef, jlong objectsLimit) {
213+
jobjectArray RetainedSizesByClassViaDominatorTreeAction::executeOperation(jobject classRef, jlong objectsLimit) {
192214
jvmtiError err = jvmti->SetTag(classRef, CLASS_TAG);
193-
if (err != JVMTI_ERROR_NONE) return nullptr;
215+
if (!isOk(err)) return nullptr;
194216

195-
err = FollowReferences(0, nullptr, nullptr, collectObjects, nullptr, "collect objects of class");
196-
if (err != JVMTI_ERROR_NONE || shouldStopExecution()) return nullptr;
217+
progressManager.updateProgress(5, "Collecting objects of class");
218+
err = FollowReferences(0, nullptr, nullptr, collectObjects, nullptr);
219+
if (!isOk(err) || shouldStopExecution()) return nullptr;
197220

198221
std::vector<jobject> objectsOfClass;
199222
err = getObjectsByTags(jvmti, std::vector<jlong>{OBJECT_OF_CLASS_TAG}, objectsOfClass);
200-
if (err != JVMTI_ERROR_NONE || shouldStopExecution()) return nullptr;
223+
if (!isOk(err) || shouldStopExecution()) return nullptr;
201224

202225
// Constructing the master node
203-
jclass langObject = env->FindClass("java/lang/Object");
204-
jobjectArray objects = env->NewObjectArray(objectsOfClass.size(), langObject, nullptr);
226+
jobjectArray objects = getObjectArrayOfSize(env, objectsOfClass.size());
205227
for (int i = 0; i < objectsOfClass.size(); i++) {
206228
env->SetObjectArrayElement(objects, i, objectsOfClass[i]);
207229
}
208230

209231
err = jvmti->SetTag(classRef, 0);
210-
if (err != JVMTI_ERROR_NONE) return nullptr;
232+
if (!isOk(err)) return nullptr;
211233

212234
SizesViaDominatorTreeHeapDumpInfo info;
213-
err = info.initAndSetTagsForObjects(env, jvmti, objects);
214-
if (err != JVMTI_ERROR_NONE) return nullptr;
215-
216-
// We set a tag for the input array to ignore it during traversal
217-
err = jvmti->SetTag(objects, MOCK_REFERRER_TAG);
218-
if (err != JVMTI_ERROR_NONE) return nullptr;
219-
220-
progressManager.updateProgress(10, "Traversing heap for the first time...");
221-
logger::resetTimer();
222-
err = FollowReferences(0, nullptr, nullptr, firstTraversal, &info, "first traversal");
223-
logger::logPassedTime();
224-
if (err != JVMTI_ERROR_NONE || shouldStopExecution()) return nullptr;
225-
226-
logger::resetTimer();
227-
progressManager.updateProgress(60, "Traversing heap for the second time...");
228-
err = FollowReferences(0, nullptr, objects, secondTraversal, &info, "second traversal");
229-
logger::logPassedTime();
230-
if (err != JVMTI_ERROR_NONE || shouldStopExecution()) return nullptr;
231-
232-
progressManager.updateProgress(80, "Calculating retained size...");
233-
info.setUpNeighboursForMasterNode();
234-
std::vector<jlong> retainedSizes = calculateRetainedSizes(info.graph, info.sizes);
235+
std::vector<jlong> retainedSizes;
236+
err = calculateRetainedSizes(objects, retainedSizes, info);
237+
if (!isOk(err) || shouldStopExecution()) return nullptr;
235238

236239
// Sort objects by their retained size
237240
std::sort(objectsOfClass.begin(), objectsOfClass.end(), [&](jobject a, jobject b) {
@@ -243,7 +246,14 @@ jobjectArray RetainedSizeByClassViaDominatorTreeAction::executeOperation(jobject
243246
});
244247

245248
progressManager.updateProgress(95, "Extracting answer...");
246-
size_t size = std::min((size_t)objectsLimit, objectsOfClass.size());
249+
return constructResultObject(objectsOfClass, retainedSizes, info, objectsLimit);
250+
}
251+
252+
jobjectArray RetainedSizesByClassViaDominatorTreeAction::constructResultObject(const std::vector<jobject> &objectsOfClass,
253+
const std::vector<jlong> &retainedSizes,
254+
const SizesViaDominatorTreeHeapDumpInfo &info,
255+
jlong objectsLimit) {
256+
size_t size = std::min(static_cast<size_t>(objectsLimit), objectsOfClass.size());
247257
std::vector<jlong> shallowSizes;
248258
std::vector<jlong> sortedRetainedSizes;
249259
sortedRetainedSizes.reserve(size);
@@ -256,25 +266,22 @@ jobjectArray RetainedSizeByClassViaDominatorTreeAction::executeOperation(jobject
256266
shallowSizes.push_back(info.sizes[tag]);
257267
}
258268

259-
jobjectArray result = env->NewObjectArray(3, langObject, nullptr);
260-
objects = env->NewObjectArray(size, langObject, nullptr);
269+
jobjectArray result = getObjectArrayOfSize(env, 3);
270+
jobjectArray objects = getObjectArrayOfSize(env, size);
261271
for (int i = 0; i < size; i++) {
262272
env->SetObjectArrayElement(objects, i, objectsOfClass[i]);
263273
}
264274
env->SetObjectArrayElement(result, 0, objects);
265275
env->SetObjectArrayElement(result, 1, toJavaArray(env, shallowSizes));
266276
env->SetObjectArrayElement(result, 2, toJavaArray(env, sortedRetainedSizes));
267-
if (!isOk(err)) {
268-
handleError(jvmti, err, "Could not estimate retained size by classes");
269-
return nullptr;
270-
}
277+
271278
return result;
272279
}
273280

274-
jvmtiError RetainedSizeByClassViaDominatorTreeAction::cleanHeap() {
281+
jvmtiError RetainedSizesByClassViaDominatorTreeAction::cleanHeap() {
275282
return removeAllTagsFromHeap(jvmti, nullptr);
276283
}
277284

278-
RetainedSizeByClassViaDominatorTreeAction::RetainedSizeByClassViaDominatorTreeAction(JNIEnv *env, jvmtiEnv *jvmti, jobject object) :
279-
MemoryAgentAction(env, jvmti, object) {
285+
RetainedSizesByClassViaDominatorTreeAction::RetainedSizesByClassViaDominatorTreeAction(JNIEnv *env, jvmtiEnv *jvmti, jobject object) :
286+
RetainedSizesAction(env, jvmti, object) {
280287
}

0 commit comments

Comments
 (0)