Feat: Polish Async profiling widget (#437)

This commit is contained in:
Fine0830 2024-12-03 12:41:51 +08:00 committed by GitHub
parent 8771ce4a19
commit ea0f5e5f62
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 37 additions and 31 deletions

View File

@ -35,6 +35,7 @@ interface AsyncProfilingState {
instances: Instance[]; instances: Instance[];
analyzeTrees: AsyncProfilerStackElement[]; analyzeTrees: AsyncProfilerStackElement[];
loadingTree: boolean; loadingTree: boolean;
loadingTasks: boolean;
} }
export const asyncProfilingStore = defineStore({ export const asyncProfilingStore = defineStore({
@ -46,6 +47,7 @@ export const asyncProfilingStore = defineStore({
instances: [], instances: [],
analyzeTrees: [], analyzeTrees: [],
loadingTree: false, loadingTree: false,
loadingTasks: false,
}), }),
actions: { actions: {
setSelectedTask(task: Recordable<AsyncProfilingTask>) { setSelectedTask(task: Recordable<AsyncProfilingTask>) {
@ -55,15 +57,15 @@ export const asyncProfilingStore = defineStore({
this.analyzeTrees = tree; this.analyzeTrees = tree;
}, },
async getTaskList() { async getTaskList() {
const { duration } = useAppStoreWithOut();
const selectorStore = useSelectorStore(); const selectorStore = useSelectorStore();
this.loadingTasks = true;
const res: AxiosResponse = await graphql.query("getAsyncTaskList").params({ const res: AxiosResponse = await graphql.query("getAsyncTaskList").params({
request: { request: {
startTime: duration.start.getTime(),
endTime: duration.end.getTime(),
serviceId: selectorStore.currentService.id, serviceId: selectorStore.currentService.id,
limit: 10000,
}, },
}); });
this.loadingTasks = false;
if (res.data.errors) { if (res.data.errors) {
return res.data; return res.data;
} }

View File

@ -35,7 +35,13 @@ limitations under the License. -->
<div> <div>
<div class="label">{{ t("profilingEvents") }}</div> <div class="label">{{ t("profilingEvents") }}</div>
<el-checkbox-group v-model="asyncEvents" class="profile-input mb-5"> <el-checkbox-group v-model="asyncEvents" class="profile-input mb-5">
<el-checkbox v-for="event in ProfilingEvents" :label="event.label" :value="event.value" :key="event.value" /> <el-checkbox
v-for="event in ProfilingEvents"
:label="event"
:value="event"
:key="event"
:disabled="disableEvents(event)"
/>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
<div> <div>
@ -103,10 +109,11 @@ limitations under the License. -->
const selectorStore = useSelectorStore(); const selectorStore = useSelectorStore();
const { t } = useI18n(); const { t } = useI18n();
const serviceInstanceIds = ref<string[]>([]); const serviceInstanceIds = ref<string[]>([]);
const asyncEvents = ref<string[]>([ProfilingEvents[0].value]); const asyncEvents = ref<string[]>([]);
const duration = ref<string>(DurationOptions[0].value); const duration = ref<string>(DurationOptions[0].value);
const execArgs = ref<string>(""); const execArgs = ref<string>("");
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
const PartofEvents = [ProfilingEvents[3], ProfilingEvents[4], ProfilingEvents[5]];
function changeDuration(val: string) { function changeDuration(val: string) {
duration.value = val; duration.value = val;
@ -116,11 +123,26 @@ limitations under the License. -->
serviceInstanceIds.value = options.map((d: Option) => d.value); serviceInstanceIds.value = options.map((d: Option) => d.value);
} }
function disableEvents(item: string) {
if (asyncEvents.value.includes(ProfilingEvents[0]) && PartofEvents.includes(item)) {
return true;
}
if (item === ProfilingEvents[0]) {
for (const event of PartofEvents) {
if (asyncEvents.value.includes(event)) {
return true;
}
}
}
return false;
}
async function createTask() { async function createTask() {
const params = { const params = {
serviceId: selectorStore.currentService.id, serviceId: selectorStore.currentService.id,
serviceInstanceIds: serviceInstanceIds.value, serviceInstanceIds: serviceInstanceIds.value,
duration: Number(duration.value), duration: Number(duration.value) * 60,
events: asyncEvents.value, events: asyncEvents.value,
execArgs: execArgs.value, execArgs: execArgs.value,
}; };

View File

@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. --> limitations under the License. -->
<template> <template>
<div class="profile-task-list flex-v" v-loading="loading"> <div class="profile-task-list flex-v" v-loading="asyncProfilingStore.loadingTasks">
<div class="profile-t-tool flex-h">{{ t("taskList") }}</div> <div class="profile-t-tool flex-h">{{ t("taskList") }}</div>
<div class="profile-t-wrapper"> <div class="profile-t-wrapper">
<div class="no-data" v-show="!asyncProfilingStore.taskList.length"> <div class="no-data" v-show="!asyncProfilingStore.taskList.length">
@ -67,7 +67,7 @@ limitations under the License. -->
</div> </div>
<div class="mb-10 clear item"> <div class="mb-10 clear item">
<span class="g-sm-4 grey">{{ t("duration") }}:</span> <span class="g-sm-4 grey">{{ t("duration") }}:</span>
<span class="g-sm-8 wba">{{ asyncProfilingStore.selectedTask.duration }}</span> <span class="g-sm-8 wba">{{ asyncProfilingStore.selectedTask.duration / 60 }}min</span>
</div> </div>
<div class="mb-10 clear item"> <div class="mb-10 clear item">
<span class="g-sm-4 grey">{{ t("events") }}:</span> <span class="g-sm-4 grey">{{ t("events") }}:</span>
@ -124,7 +124,7 @@ limitations under the License. -->
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, watch } from "vue"; import { ref, onMounted } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useSelectorStore } from "@/store/modules/selectors"; import { useSelectorStore } from "@/store/modules/selectors";
import { useAsyncProfilingStore } from "@/store/modules/async-profiling"; import { useAsyncProfilingStore } from "@/store/modules/async-profiling";
@ -141,16 +141,13 @@ limitations under the License. -->
const instanceLogs = ref<TaskLog | any>({}); const instanceLogs = ref<TaskLog | any>({});
const errorInstances = ref<Instance[]>([]); const errorInstances = ref<Instance[]>([]);
const successInstances = ref<Instance[]>([]); const successInstances = ref<Instance[]>([]);
const loading = ref<boolean>(false);
onMounted(() => { onMounted(() => {
fetchTasks(); fetchTasks();
}); });
async function fetchTasks() { async function fetchTasks() {
loading.value = true;
const res = await asyncProfilingStore.getTaskList(); const res = await asyncProfilingStore.getTaskList();
loading.value = false;
if (res.errors) { if (res.errors) {
return ElMessage.error(res.errors); return ElMessage.error(res.errors);
} }
@ -192,13 +189,6 @@ limitations under the License. -->
} }
} }
} }
watch(
() => selectorStore.currentService,
() => {
fetchTasks();
},
);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.profile-task-list { .profile-task-list {

View File

@ -21,28 +21,20 @@ export const DurationOptions = [
{ value: "15", label: "15 min" }, { value: "15", label: "15 min" },
]; ];
export const ProfilingEvents = [ export const ProfilingEvents = ["CPU", "ALLOC", "LOCK", "WALL", "CTIMER", "ITIMER"];
{ value: "CPU", label: "CPU" },
{ value: "ALLOC", label: "ALLOC" },
{ value: "WALL", label: "WALL" },
{ value: "LOCK", label: "LOCK" },
{ value: "CTIMER", label: "CTIMER" },
{ value: "ITIMER", label: "ITIMER" },
];
export enum EventsMap { export enum EventsMap {
CPU = "EXECUTION_SAMPLE", CPU = "EXECUTION_SAMPLE",
WALL = "EXECUTION_SAMPLE", WALL = "EXECUTION_SAMPLE",
CTIMER = "EXECUTION_SAMPLE", CTIMER = "EXECUTION_SAMPLE",
ITIMER = "EXECUTION_SAMPLE", ITIMER = "EXECUTION_SAMPLE",
LOCK = "JAVA_MONITOR_ENTER", LOCK = "LOCK",
ALLOC = "OBJECT_ALLOCATION_OUTSIDE_TLAB", ALLOC = "OBJECT_ALLOCATION_OUTSIDE_TLAB",
} }
export enum JFREventType { export enum JFREventType {
EXECUTION_SAMPLE = "EXECUTION_SAMPLE", EXECUTION_SAMPLE = "EXECUTION_SAMPLE",
JAVA_MONITOR_ENTER = "JAVA_MONITOR_ENTER", LOCK = "LOCK",
THREAD_PARK = "THREAD_PARK",
OBJECT_ALLOCATION_IN_NEW_TLAB = "OBJECT_ALLOCATION_IN_NEW_TLAB", OBJECT_ALLOCATION_IN_NEW_TLAB = "OBJECT_ALLOCATION_IN_NEW_TLAB",
OBJECT_ALLOCATION_OUTSIDE_TLAB = "OBJECT_ALLOCATION_OUTSIDE_TLAB", OBJECT_ALLOCATION_OUTSIDE_TLAB = "OBJECT_ALLOCATION_OUTSIDE_TLAB",
PROFILER_LIVE_OBJECT = "PROFILER_LIVE_OBJECT", PROFILER_LIVE_OBJECT = "PROFILER_LIVE_OBJECT",

View File

@ -128,7 +128,7 @@ limitations under the License. -->
return; return;
} }
const { type } = ebpfStore.analyzeTrees[0]; const { type } = ebpfStore.analyzeTrees[0];
if ([JFREventType.JAVA_MONITOR_ENTER, JFREventType.THREAD_PARK].includes(type)) { if ([JFREventType.LOCK].includes(type)) {
return `<div class="mb-5">Duration: ${item.dumpCount} ms</div>`; return `<div class="mb-5">Duration: ${item.dumpCount} ms</div>`;
} }
if (type === JFREventType.EXECUTION_SAMPLE) { if (type === JFREventType.EXECUTION_SAMPLE) {