Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI improvement, User can specify more options at memory dump analysis scene & changing setting is cancelable after open the settings pannel. #242

Merged
merged 5 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,9 @@ protected HeapDumpAnalyzer buildAnalyzer(Path target, Map<String, String> option

@Override
protected void cachedAnalyzerRemoved(HeapDumpAnalyzer heapDumpAnalyzer) {
heapDumpAnalyzer.dispose();
if (heapDumpAnalyzer != null) {
heapDumpAnalyzer.dispose();
}
}

private File indexFile(Path target) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,11 +333,11 @@ public Progress progressOfAnalysis(@ApiParameterMeta(targetPath = true) Path tar
}

public void release(@ApiParameterMeta(targetPath = true) Path target) {
cachedAnalyzer.invalidate(target);
cleanAndDisposeAnalyzerCache(target);
}

public void clean(@ApiParameterMeta(targetPath = true) Path target) {
cachedAnalyzer.invalidate(target);
cleanAndDisposeAnalyzerCache(target);
File errorLog = errorLogFile(target);
if (errorLog.exists()) {
if (!errorLog.delete()) {
Expand All @@ -364,4 +364,13 @@ protected final boolean isActive(Path target) {
protected int getCacheDuration() {
return 8;
}

private void cleanAndDisposeAnalyzerCache(Path target) {
// Dispose snapshot synchronized to prevent from some problem caused by data inconsistency.
Analyzer analyzer = cachedAnalyzer.getIfPresent(target);
cachedAnalyzer.invalidate(target);
if (analyzer != null) {
cachedAnalyzerRemoved(analyzer);
}
}
}
29 changes: 22 additions & 7 deletions frontend/src/components/Analysis.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ const progressStatus = computed(() => {
function analyze(options?) {
let parameters;
if (options) {
options = { ...options };
let additionalOptions = options.additional_options;
delete options.additional_options;
if (additionalOptions && additionalOptions.trim()) {
const pairs = additionalOptions.match(/(\w+)=('(?:\\.|[^'\\])*'|\S+)/g);

for (let pair of pairs) {
const index = pair.indexOf('=');
const key = pair.slice(0, index);
const value = pair.slice(index + 1);
// delete qouta on value if exists.
const cleanedValue = value.replace(/^'(.*)'$/, '$1');
options[key] = cleanedValue
}
}
parameters = { options };
}
request('analyze', parameters)
Expand Down Expand Up @@ -163,6 +178,13 @@ onUnmounted(() => {
<template>
<transition mode="out-in">
<div class="ej-common-view-div" v-if="analysis.phase == Phase.INIT" v-loading="true"></div>
<div
class="ej-common-view-div"
style="display: flex; flex-direction: column; justify-content: center; align-items: center"
v-else-if="analysis.phase === Phase.SETUP || analysis.showSetupPage === true"
>
<component :is="setupComponent" @confirmAnalysisOptions="analyze"></component>
</div>
<div
class="ej-common-view-div"
style="display: flex; flex-direction: column; justify-content: start"
Expand All @@ -188,13 +210,6 @@ onUnmounted(() => {
<p v-if="log" style="white-space: pre-line">{{ log }}</p>
</div>
</div>
<div
class="ej-common-view-div"
style="display: flex; flex-direction: column; justify-content: center; align-items: center"
v-else-if="analysis.phase === Phase.SETUP"
>
<component :is="setupComponent" @confirmAnalysisOptions="analyze"></component>
</div>
<component :is="analysisComponent" v-else-if="analysis.phase == Phase.SUCCESS"></component>
</transition>
</template>
Expand Down
121 changes: 118 additions & 3 deletions frontend/src/components/heapdump/Setup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,40 @@
-->
<script setup lang="ts">
import { hdt } from '@/components/heapdump/utils';
import { Phase, useAnalysisStore } from '@/stores/analysis';
import { InfoFilled } from '@element-plus/icons-vue';
import { t } from '@/i18n/i18n';

import { useAnalysisApiRequester } from '@/composables/analysis-api-requester';

const { request } = useAnalysisApiRequester();
const analysis = useAnalysisStore();

const emit = defineEmits(['confirmAnalysisOptions']);

const options = reactive({
keep_unreachable_objects: true,
strictness: 'stop'
strictness: 'stop',
discard_objects: false,
discard_pattern: '',
discard_ratio: 0,
additional_options: ''
});

function onConfirm() {
emit('confirmAnalysisOptions', options);
request('clean').then(() => {
analysis.leaveGuard = false;
analysis.setPhase(Phase.INIT)
analysis.setShowSetupPage(false);
emit('confirmAnalysisOptions', options);
});
}

function onCancel() {
analysis.setShowSetupPage(false);
}

const enableDiscard = computed(() => options.discard_objects);
</script>
<template>
<el-form
Expand Down Expand Up @@ -95,9 +116,103 @@ function onConfirm() {
</el-popover>
</el-form-item>

<!-- Discard Objects -->
<el-form-item :label="hdt('option.labelOfDiscardObjects')">
<el-switch v-model="options.discard_objects"></el-switch>
<el-popover
placement="top"
:width="600"
trigger="hover"
:show-arrow="false"
:popper-style="{ padding: 0 }"
>
<template #reference>
<el-icon class="ej-icon" style="margin-left: 8px" size="18">
<InfoFilled />
</el-icon>
</template>
<template #default>
<el-alert
type="info"
style="word-break: keep-all"
:closable="false"
:title="hdt('option.descOfDiscardObjects')"
>
<div slot="default">
<p>{{ hdt('option.descOfDiscardObjectsDetail') }}</p>
<p>discard_pattern: {{ hdt('option.descOfDiscardObjectsPattern') }}</p>
<p>discard_ratio: {{ hdt('option.descOfDiscardObjectsRatio') }}</p>
</div>
</el-alert>
</template>
</el-popover>
</el-form-item>
<el-form-item :label="hdt('option.labelOfDiscardObjectsPattern')" v-if="enableDiscard">
<el-input
v-model="options.discard_pattern"
placeholder="eg:byte\[\]|java\.lang\.String||java\.lang\.String\[\]"
clearable
class="discard-pattern-form-input"
@keydown.enter="(e) => e.preventDefault()"
> </el-input>
</el-form-item>
<el-form-item :label="hdt('option.labelOfDiscardObjectsRatio')" v-if="enableDiscard">
<el-input
v-model="options.discard_ratio"
placeholder="0~100"
class="discard-ratio-form-input"
@keydown.enter="(e) => e.preventDefault()"
> </el-input>
</el-form-item>
<!-- Discard Objects end -->
<el-form-item :label="hdt('option.labelAdditionalAnalyseOptions')">
<el-input
v-model="options.additional_options"
placeholder="options for eclipse memory analyser, eg: k1=v1 k2=v2 k3='v3 with blank characters'"
class="additional-options-form-input"
clearable
@keydown.enter="(e) => e.preventDefault()"
> </el-input>
<el-popover
placement="top"
:width="600"
trigger="hover"
:show-arrow="false"
:popper-style="{ padding: 0 }"
>
<template #reference>
<el-icon class="ej-icon" style="margin-left: 8px" size="18">
<InfoFilled />
</el-icon>
</template>
<template #default>
<el-alert
type="info"
style="word-break: keep-all"
:closable="false"
:description="hdt('option.descAdditionalAnalyseOptions')"
>
</el-alert>
</template>
</el-popover>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onConfirm">{{ t('common.confirm') }}</el-button>
<el-button @click="onCancel" v-if="analysis.phase !== Phase.INIT && analysis.phase !== Phase.SETUP">
{{ t('common.cancel') }}
</el-button>
</el-form-item>
</el-form>
</template>
<style scoped></style>
<style scoped>
.discard-ratio-form-input {
width: 120px;
}
.discard-pattern-form-input {
width: 420px;
}

.additional-options-form-input {
width: 350px;
}
</style>
11 changes: 5 additions & 6 deletions frontend/src/components/heapdump/Toolbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ import { Phase, useAnalysisStore } from '@/stores/analysis';
const { request } = useAnalysisApiRequester();

const analysis = useAnalysisStore();
function clean() {
request('clean').then(() => {
useAnalysisStore().leaveGuard = false;
location.reload();
});

function showSetup() {
analysis.setShowSetupPage(true)
}

</script>
<template>
<el-divider direction="vertical" />
Expand All @@ -34,7 +33,7 @@ function clean() {
<template v-if="analysis.phase === Phase.SUCCESS || analysis.phase === Phase.FAILURE">
<el-divider direction="vertical" />

<el-button link class="ej-header-button" :icon="SetUp" @click="clean">
<el-button link class="ej-header-button" :icon="SetUp" @click="showSetup">
{{ t('analysis.setting') }}
</el-button>
</template>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default {
jifa: {
common: {
confirm: 'Confirm',
cancel: 'Cancel',
submit: 'Submit',
back: 'Back',
operations: 'Operations',
Expand Down
11 changes: 10 additions & 1 deletion frontend/src/i18n/heapdump/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,16 @@ export default {
descOfStrictness: "'Strictness' indicates the follow-up action when an error occurred",
descOfStopStrictness: 'Throw an error and stop analyzing the dump',
descOfWarnStrictness: 'Raise a warning and continue',
descOfPermissiveStrictness: 'Raise a warning and try to "fix" it'
descOfPermissiveStrictness: 'Raise a warning and try to "fix" it',
labelOfDiscardObjects: 'Discard objects',
descOfDiscardObjects: 'Discard some objects to reduce memory consume while analyse',
descOfDiscardObjectsDetail: 'Sometimes a heap dump is generated with more objects than Memory Analyzer can handle, either from lack of heap to run Memory Analyzer itself, or because the number exceeds the Memory Analyzer limit of 2,147,483,639 objects. This option controls some experimental settings to help analyze such huge dumps, by purposely discarding objects in the original heap dump.',
labelOfDiscardObjectsRatio: "Discard ratio",
descOfDiscardObjectsRatio: 'A number between 0 and 100, treated as a percentage. Approximately this percentage of ordinary objects matching the discard pattern will be discarded by the HPROF or DTFJ parsers.',
labelOfDiscardObjectsPattern: 'Discard pattern',
descOfDiscardObjectsPattern: 'Only objects with a class name matching this regular expression will be discarded. It is best to chose objects of a type which does not link to other objects, such as primitive arrays, or objects which just link to other such objects. This avoids breaking the object graph too much, and gives a hope that the leak analysis will find the problem.',
labelAdditionalAnalyseOptions: 'Additional options',
descAdditionalAnalyseOptions: 'Analyse options of Eclipse Memory Analyser, see: https://help.eclipse.org/latest/index.jsp?topic=%2Forg.eclipse.mat.ui.help%2Ftasks%2Fconfigure_mat.html'
},

tab: {
Expand Down
11 changes: 10 additions & 1 deletion frontend/src/i18n/heapdump/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,16 @@ export default {
descOfStrictness: "'分析失败时的策略' 表示当分析过程中遇到错误时的后续动作",
descOfStopStrictness: '终止分析',
descOfWarnStrictness: '报告警告信息并继续分析',
descOfPermissiveStrictness: '报告警告信息,尝试修复错误并继续分析'
descOfPermissiveStrictness: '报告警告信息,尝试修复错误并继续分析',
labelOfDiscardObjects: '丢弃部分对象',
descOfDiscardObjects: '分析的时候丢弃部分对象,以减少 jifa 的堆内存占用,防止 OOM',
descOfDiscardObjectsDetail: '如果堆内存特别巨大的话,其中某一类 objects 的数量可能会超过 2,147,483,639 这个限制,从而导致 1. analyze 无法为其创建索引数组而解析失败, 2. jifa 本身OOM 而解析失败. 这个选项可以通过指定丢弃类和丢弃比例的方式来丢弃一部分 objects,从而避免这些问题(如果堆内存特别巨大,建议开启此选项)',
labelOfDiscardObjectsRatio: "丢弃比例",
descOfDiscardObjectsRatio: '丢弃的百分比,数值范围:0 ~ 100. 匹配了 discard pattern 的类将会被根据这个比例进行随机丢弃.',
labelOfDiscardObjectsPattern: '丢弃规则',
descOfDiscardObjectsPattern: '丢弃类的正则匹配表达式,最好选择一些不会引用其他 object 的类,例如: byte\\[\\],java\\.lang\\.String\ 或者 java\\.lang\\.String\\[\\] (记得对关键字进行转义).',
labelAdditionalAnalyseOptions: '其他选项',
descAdditionalAnalyseOptions: 'Eclipse Memory Analyser 支持的其他选项, 详情: https://help.eclipse.org/latest/index.jsp?topic=%2Forg.eclipse.mat.ui.help%2Ftasks%2Fconfigure_mat.html'
},

tab: {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/i18n/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default {
jifa: {
common: {
confirm: '确定',
cancel: '取消',
submit: '提交',
back: '返回',
operations: '操作',
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/stores/analysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ export const useAnalysisStore = defineStore('analysis', {

phase: null as Phase | null,

leaveGuard: true
leaveGuard: true,

showSetupPage: false
}),

actions: {
Expand All @@ -47,6 +49,10 @@ export const useAnalysisStore = defineStore('analysis', {

setPhase(phase: Phase | null) {
this.phase = phase;
},

setShowSetupPage(showSetupPage: boolean) {
this.showSetupPage = showSetupPage
}
}
});
3 changes: 3 additions & 0 deletions frontend/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,7 @@ export default defineConfig({
}
}
},
build: {
chunkSizeWarningLimit: 10240
}
})