diff --git a/src/assets/icons/async_profiling.svg b/src/assets/icons/async_profiling.svg new file mode 100644 index 00000000..40cbf0b1 --- /dev/null +++ b/src/assets/icons/async_profiling.svg @@ -0,0 +1,18 @@ + + + + + diff --git a/src/graphql/fragments/async-profile.ts b/src/graphql/fragments/async-profile.ts new file mode 100644 index 00000000..7021f193 --- /dev/null +++ b/src/graphql/fragments/async-profile.ts @@ -0,0 +1,80 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const GetAsyncTaskList = { + variable: "$request: AsyncProfilerTaskListRequest!", + query: ` + asyncTaskList: queryAsyncProfilerTaskList(request: $request) { + errorReason + tasks { + id + serviceId + serviceInstanceIds + createTime + events + duration + execArgs + } + } + `, +}; + +export const GetAsyncProfileTaskProcess = { + variable: "$taskId: String!", + query: ` + taskProgress: queryAsyncProfilerTaskProgress(taskId: $taskId) { + logs { + id + instanceId + instanceName + operationType + operationTime + } + errorInstanceIds + successInstanceIds + } + `, +}; + +export const CreateAsyncProfileTask = { + variable: "$asyncProfilerTaskCreationRequest: AsyncProfilerTaskCreationRequest!", + query: ` + task: createAsyncProfilerTask(asyncProfilerTaskCreationRequest: $asyncProfilerTaskCreationRequest) { + id + errorReason + code + } + `, +}; + +export const GetAsyncProfileAnalyze = { + variable: "$request: AsyncProfilerAnalyzationRequest!", + query: ` + analysisResult: queryAsyncProfilerAnalyze(request: $request) { + tree { + type + elements { + id + parentId + symbol: codeSignature + dumpCount: total + self + } + } + } + `, +}; diff --git a/src/graphql/index.ts b/src/graphql/index.ts index 77968202..84c0b89c 100644 --- a/src/graphql/index.ts +++ b/src/graphql/index.ts @@ -28,6 +28,7 @@ import * as alarm from "./query/alarm"; import * as event from "./query/event"; import * as ebpf from "./query/ebpf"; import * as demandLog from "./query/demand-log"; +import * as asyncProfile from "./query/async-profile"; const query: { [key: string]: string } = { ...app, @@ -41,6 +42,7 @@ const query: { [key: string]: string } = { ...event, ...ebpf, ...demandLog, + ...asyncProfile, }; class Graphql { private queryData = ""; diff --git a/src/graphql/query/async-profile.ts b/src/graphql/query/async-profile.ts new file mode 100644 index 00000000..b8ab4617 --- /dev/null +++ b/src/graphql/query/async-profile.ts @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + GetAsyncTaskList, + GetAsyncProfileTaskProcess, + CreateAsyncProfileTask, + GetAsyncProfileAnalyze, +} from "../fragments/async-profile"; + +export const getAsyncTaskList = `query getAsyncTaskList(${GetAsyncTaskList.variable}) {${GetAsyncTaskList.query}}`; + +export const getAsyncProfileTaskProcess = `query getAsyncProfileTaskProcess(${GetAsyncProfileTaskProcess.variable}) {${GetAsyncProfileTaskProcess.query}}`; + +export const saveAsyncProfileTask = `mutation createAsyncProfileTask(${CreateAsyncProfileTask.variable}) {${CreateAsyncProfileTask.query}}`; + +export const getAsyncProfileAnalyze = `query getAsyncProfileAnalyze(${GetAsyncProfileAnalyze.variable}) {${GetAsyncProfileAnalyze.query}}`; diff --git a/src/locales/lang/en.ts b/src/locales/lang/en.ts index 65722791..5640a21d 100644 --- a/src/locales/lang/en.ts +++ b/src/locales/lang/en.ts @@ -390,5 +390,10 @@ const msg = { mappingTip: "Notice: The mapping key is a Regex string, e.g. ^([0-9])$", valueDashboard: "Data Value Related Dashboard", viewValueDashboard: "View Dashboard", + errorInstances: "Error Instances", + successInstances: "Success Instances", + profilingEvents: "Async Profiling Events", + execArgs: "Exec Args", + instances: "Instances", }; export default msg; diff --git a/src/locales/lang/es.ts b/src/locales/lang/es.ts index aff70878..4496b367 100644 --- a/src/locales/lang/es.ts +++ b/src/locales/lang/es.ts @@ -390,5 +390,10 @@ const msg = { mappingTip: "Aviso: La clave de mapeo es una cadena Regex, p. ej. ^([0-9])$", valueDashboard: "Data Value Related Dashboard", viewValueDashboard: "View Dashboard", + errorInstances: "Error Instances", + successInstances: "Success Instances", + profilingEvents: "Async Profiling Events", + execArgs: "Exec Args", + instances: "Instances", }; export default msg; diff --git a/src/locales/lang/zh.ts b/src/locales/lang/zh.ts index dca5b0bb..800d8c78 100644 --- a/src/locales/lang/zh.ts +++ b/src/locales/lang/zh.ts @@ -388,5 +388,10 @@ const msg = { mappingTip: "注意: 映射键是一个正则表达式字符串,比如 ^([0-9])$", valueDashboard: "数据值相关的仪表板", viewValueDashboard: "查看仪表板", + errorInstances: "错误的实例", + successInstances: "成功的实例", + profilingEvents: "异步分析事件", + execArgs: "String任务扩展", + instances: "实例", }; export default msg; diff --git a/src/store/data.ts b/src/store/data.ts index 24749b4d..c0414116 100644 --- a/src/store/data.ts +++ b/src/store/data.ts @@ -47,6 +47,7 @@ export const ControlsTypes = [ WidgetType.DemandLog, WidgetType.Ebpf, WidgetType.NetworkProfiling, + WidgetType.AsyncProfiling, WidgetType.ThirdPartyApp, WidgetType.ContinuousProfiling, WidgetType.TaskTimeline, diff --git a/src/store/modules/async-profiling.ts b/src/store/modules/async-profiling.ts new file mode 100644 index 00000000..2ce5b0b6 --- /dev/null +++ b/src/store/modules/async-profiling.ts @@ -0,0 +1,136 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { defineStore } from "pinia"; +import type { + AsyncProfilingTask, + AsyncProfileTaskCreationRequest, + AsyncProfilerStackElement, + AsyncProfilerTaskProgress, +} from "@/types/async-profiling"; +import { store } from "@/store"; +import graphql from "@/graphql"; +import { useAppStoreWithOut } from "@/store/modules/app"; +import { useSelectorStore } from "@/store/modules/selectors"; +import type { AxiosResponse } from "axios"; +import type { Instance } from "@/types/selector"; + +interface AsyncProfilingState { + taskList: Array>; + selectedTask: Recordable; + taskProgress: Recordable; + instances: Instance[]; + analyzeTrees: AsyncProfilerStackElement[]; + loadingTree: boolean; +} + +export const asyncProfilingStore = defineStore({ + id: "asyncProfiling", + state: (): AsyncProfilingState => ({ + taskList: [], + selectedTask: {}, + taskProgress: {}, + instances: [], + analyzeTrees: [], + loadingTree: false, + }), + actions: { + setSelectedTask(task: Recordable) { + this.selectedTask = task || {}; + }, + setAnalyzeTrees(tree: AsyncProfilerStackElement[]) { + this.analyzeTrees = tree; + }, + async getTaskList() { + const { duration } = useAppStoreWithOut(); + const selectorStore = useSelectorStore(); + const res: AxiosResponse = await graphql.query("getAsyncTaskList").params({ + request: { + startTime: duration.start.getTime(), + endTime: duration.end.getTime(), + serviceId: selectorStore.currentService.id, + }, + }); + if (res.data.errors) { + return res.data; + } + this.taskList = res.data.data.asyncTaskList.tasks || []; + this.selectedTask = this.taskList[0] || {}; + this.setAnalyzeTrees([]); + this.setSelectedTask(this.selectedTask); + if (!this.taskList.length) { + return res.data; + } + return res.data; + }, + async getTaskLogs(param: { taskID: string }) { + const res: AxiosResponse = await graphql.query("getAsyncProfileTaskProcess").params(param); + + if (res.data.errors) { + return res.data; + } + this.taskProgress = res.data.data.taskProgress; + return res.data; + }, + async getServiceInstances(param: { serviceId: string; isRelation: boolean }): Promise> { + if (!param.serviceId) { + return null; + } + const res: AxiosResponse = await graphql.query("queryInstances").params({ + serviceId: param.serviceId, + duration: useAppStoreWithOut().durationTime, + }); + if (!res.data.errors) { + this.instances = res.data.data.pods || []; + } + return res.data; + }, + async createTask(param: AsyncProfileTaskCreationRequest) { + const res: AxiosResponse = await graphql + .query("saveAsyncProfileTask") + .params({ asyncProfilerTaskCreationRequest: param }); + + if (res.data.errors) { + return res.data; + } + this.getTaskList(); + return res.data; + }, + async getAsyncProfilingAnalyze(params: { taskId: string; instanceIds: Array; eventType: string }) { + if (!params.instanceIds.length) { + return new Promise((resolve) => resolve({})); + } + this.loadingTree = true; + const res: AxiosResponse = await graphql.query("getAsyncProfileAnalyze").params({ request: params }); + this.loadingTree = false; + if (res.data.errors) { + this.analyzeTrees = []; + return res.data; + } + const { analysisResult } = res.data.data; + if (!analysisResult) { + this.analyzeTrees = []; + return res.data; + } + this.analyzeTrees = [analysisResult.tree]; + return res.data; + }, + }, +}); + +export function useAsyncProfilingStore(): Recordable { + return asyncProfilingStore(store); +} diff --git a/src/styles/lib.scss b/src/styles/lib.scss index 7ca6a229..696a8a19 100644 --- a/src/styles/lib.scss +++ b/src/styles/lib.scss @@ -139,6 +139,10 @@ margin-bottom: 10px; } +.mb-20 { + margin-bottom: 20px; +} + .mr-5 { margin-right: 5px; } diff --git a/src/types/async-profiling.ts b/src/types/async-profiling.ts new file mode 100644 index 00000000..e6dfa68b --- /dev/null +++ b/src/types/async-profiling.ts @@ -0,0 +1,68 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type AsyncProfilingTask = { + id: string; + serviceId: string; + serviceInstanceIds: string[]; + createTime: number; + events: string; + duration: number; + execArgs: string; +}; + +export type AsyncProfileTaskCreationRequest = { + serviceId: string; + serviceInstanceIds: string[]; + duration: number; + events: string[]; + execArgs: string; +}; + +export type AsyncProfilerStackElement = { + id: string; + parentId: string; + codeSignature: string; + total: number; + self: number; +}; + +export type AsyncProfilerTaskProgress = { + errorInstanceIds: string[]; + successInstanceIds: string[]; + logs: AsyncProfilerTaskLog[]; +}; + +type AsyncProfilerTaskLog = { + id: string; + instanceId: string; + instanceName: string; + operationType: string; + operationTime: number; +}; + +export type StackElement = { + id: string; + originId: string; + name: string; + parentId: string; + codeSignature: string; + total: number; + self: number; + value: number; + children?: StackElement[]; +}; diff --git a/src/types/components.d.ts b/src/types/components.d.ts index 78897e22..247c6b27 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -12,6 +12,8 @@ declare module 'vue' { ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] ElButton: typeof import('element-plus/es')['ElButton'] ElCard: typeof import('element-plus/es')['ElCard'] + ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] + ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup'] ElCollapse: typeof import('element-plus/es')['ElCollapse'] ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem'] ElDialog: typeof import('element-plus/es')['ElDialog'] diff --git a/src/types/profile.d.ts b/src/types/profile.d.ts index ac7fb79f..7324d3e8 100644 --- a/src/types/profile.d.ts +++ b/src/types/profile.d.ts @@ -41,6 +41,9 @@ export interface TaskListItem { dumpPeriod: number; maxSamplingCount: number; logs: TaskLog[]; + errorInstanceIds: string[]; + successInstanceIds: string[]; + serviceInstanceIds: string[]; } export interface SegmentSpan { spanId: string; diff --git a/src/views/dashboard/controls/AsyncProfiling.vue b/src/views/dashboard/controls/AsyncProfiling.vue new file mode 100644 index 00000000..9f1bef8b --- /dev/null +++ b/src/views/dashboard/controls/AsyncProfiling.vue @@ -0,0 +1,85 @@ + + + + diff --git a/src/views/dashboard/controls/index.ts b/src/views/dashboard/controls/index.ts index 01329d33..9cfe1a64 100644 --- a/src/views/dashboard/controls/index.ts +++ b/src/views/dashboard/controls/index.ts @@ -26,6 +26,7 @@ import DemandLog from "./DemandLog.vue"; import Event from "./Event.vue"; import NetworkProfiling from "./NetworkProfiling.vue"; import ContinuousProfiling from "./ContinuousProfiling.vue"; +import AsyncProfiling from "./AsyncProfiling.vue"; import TimeRange from "./TimeRange.vue"; import ThirdPartyApp from "./ThirdPartyApp.vue"; import TaskTimeline from "./TaskTimeline.vue"; @@ -43,6 +44,7 @@ export default { Event, NetworkProfiling, ContinuousProfiling, + AsyncProfiling, TimeRange, ThirdPartyApp, TaskTimeline, diff --git a/src/views/dashboard/controls/tab.ts b/src/views/dashboard/controls/tab.ts index 008c8081..2ae84f11 100644 --- a/src/views/dashboard/controls/tab.ts +++ b/src/views/dashboard/controls/tab.ts @@ -25,6 +25,7 @@ import DemandLog from "./DemandLog.vue"; import Event from "./Event.vue"; import NetworkProfiling from "./NetworkProfiling.vue"; import ContinuousProfiling from "./ContinuousProfiling.vue"; +import AsyncProfiling from "./AsyncProfiling.vue"; import TimeRange from "./TimeRange.vue"; import ThirdPartyApp from "./ThirdPartyApp.vue"; import TaskTimeline from "./TaskTimeline.vue"; @@ -43,5 +44,6 @@ export default { TimeRange, ThirdPartyApp, ContinuousProfiling, + AsyncProfiling, TaskTimeline, }; diff --git a/src/views/dashboard/data.ts b/src/views/dashboard/data.ts index 07032df1..e5a46be4 100644 --- a/src/views/dashboard/data.ts +++ b/src/views/dashboard/data.ts @@ -150,6 +150,7 @@ export enum WidgetType { Event = "Event", NetworkProfiling = "NetworkProfiling", ContinuousProfiling = "ContinuousProfiling", + AsyncProfiling = "AsyncProfiling", ThirdPartyApp = "ThirdPartyApp", TaskTimeline = "TaskTimeline", } @@ -171,6 +172,7 @@ export const ServiceTools = [ { name: "timeline", content: "Add Trace Profiling", id: WidgetType.Profile }, { name: "insert_chart", content: "Add eBPF Profiling", id: WidgetType.Ebpf }, { name: "continuous_profiling", content: "Add Continuous Profiling", id: WidgetType.ContinuousProfiling }, + { name: "async_profiling", content: "Add Async Profiling", id: WidgetType.AsyncProfiling }, { name: "assignment", content: "Add Log", id: WidgetType.Log }, { name: "demand", content: "Add On Demand Log", id: WidgetType.DemandLog }, { name: "event", content: "Add Event", id: WidgetType.Event }, diff --git a/src/views/dashboard/related/async-profiling/Content.vue b/src/views/dashboard/related/async-profiling/Content.vue new file mode 100644 index 00000000..f8768ff8 --- /dev/null +++ b/src/views/dashboard/related/async-profiling/Content.vue @@ -0,0 +1,69 @@ + + + + diff --git a/src/views/dashboard/related/async-profiling/Header.vue b/src/views/dashboard/related/async-profiling/Header.vue new file mode 100644 index 00000000..377307b8 --- /dev/null +++ b/src/views/dashboard/related/async-profiling/Header.vue @@ -0,0 +1,50 @@ + + + + diff --git a/src/views/dashboard/related/async-profiling/components/Filter.vue b/src/views/dashboard/related/async-profiling/components/Filter.vue new file mode 100644 index 00000000..29166959 --- /dev/null +++ b/src/views/dashboard/related/async-profiling/components/Filter.vue @@ -0,0 +1,104 @@ + + + + diff --git a/src/views/dashboard/related/async-profiling/components/NewTask.vue b/src/views/dashboard/related/async-profiling/components/NewTask.vue new file mode 100644 index 00000000..461cc740 --- /dev/null +++ b/src/views/dashboard/related/async-profiling/components/NewTask.vue @@ -0,0 +1,166 @@ + + + + + diff --git a/src/views/dashboard/related/async-profiling/components/TaskList.vue b/src/views/dashboard/related/async-profiling/components/TaskList.vue new file mode 100644 index 00000000..205bf594 --- /dev/null +++ b/src/views/dashboard/related/async-profiling/components/TaskList.vue @@ -0,0 +1,267 @@ + + + + diff --git a/src/views/dashboard/related/async-profiling/components/data.ts b/src/views/dashboard/related/async-profiling/components/data.ts new file mode 100644 index 00000000..6c122f7b --- /dev/null +++ b/src/views/dashboard/related/async-profiling/components/data.ts @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const DurationOptions = [ + { value: "5", label: "5 min" }, + { value: "10", label: "10 min" }, + { value: "15", label: "15 min" }, +]; + +export const ProfilingEvents = [ + { 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 { + CPU = "EXECUTION_SAMPLE", + WALL = "EXECUTION_SAMPLE", + CTIMER = "EXECUTION_SAMPLE", + ITIMER = "EXECUTION_SAMPLE", + LOCK = "JAVA_MONITOR_ENTER", + ALLOC = "OBJECT_ALLOCATION_OUTSIDE_TLAB", +} + +export enum JFREventType { + EXECUTION_SAMPLE = "EXECUTION_SAMPLE", + JAVA_MONITOR_ENTER = "JAVA_MONITOR_ENTER", + THREAD_PARK = "THREAD_PARK", + OBJECT_ALLOCATION_IN_NEW_TLAB = "OBJECT_ALLOCATION_IN_NEW_TLAB", + OBJECT_ALLOCATION_OUTSIDE_TLAB = "OBJECT_ALLOCATION_OUTSIDE_TLAB", + PROFILER_LIVE_OBJECT = "PROFILER_LIVE_OBJECT", +} + +export const ComponentType = "ASYNC_PROFILING"; diff --git a/src/views/dashboard/related/continuous-profiling/data.ts b/src/views/dashboard/related/continuous-profiling/data.ts index fb9d0c5c..97dc7c32 100644 --- a/src/views/dashboard/related/continuous-profiling/data.ts +++ b/src/views/dashboard/related/continuous-profiling/data.ts @@ -29,8 +29,6 @@ export const TargetTypes = [ { label: "NETWORK", value: "NETWORK" }, ]; -export const ComponentType = "CONTINOUS_PROFILING"; - export const HeaderLabels = [ { value: "triggeredCount", label: "Triggered Count", width: 150 }, { value: "lastTriggerTime", label: "Last Trigger Time", width: 170 }, diff --git a/src/views/dashboard/related/ebpf/components/EBPFSchedules.vue b/src/views/dashboard/related/ebpf/components/EBPFSchedules.vue index 82b4ed23..177f1991 100644 --- a/src/views/dashboard/related/ebpf/components/EBPFSchedules.vue +++ b/src/views/dashboard/related/ebpf/components/EBPFSchedules.vue @@ -97,21 +97,12 @@ limitations under the License. --> import type { Option } from "@/types/app"; import { TableHeader, AggregateTypes } from "./data"; import { useEbpfStore } from "@/store/modules/ebpf"; - import { useContinousProfilingStore } from "@/store/modules/continous-profiling"; import type { EBPFProfilingSchedule, Process } from "@/types/ebpf"; import { ElMessage, ElTable } from "element-plus"; import { dateFormat } from "@/utils/dateFormat"; - import { ComponentType } from "@/views/dashboard/related/continuous-profiling/data"; const { t } = useI18n(); - /*global defineProps*/ - const props = defineProps({ - type: { - type: String, - default: "", - }, - }); - const ebpfStore = props.type === ComponentType ? useContinousProfilingStore() : useEbpfStore(); + const ebpfStore = useEbpfStore(); const pageSize = 5; const multipleTableRef = ref>(); const selectedProcesses = ref([]); @@ -126,12 +117,12 @@ limitations under the License. --> return attr.map((d: { name: string; value: string }) => `${d.name}=${d.value}`).join("; "); }; - function changeLabels(opt: any[]) { + function changeLabels(opt: Option[]) { const arr = opt.map((d) => d.value); selectedLabels.value = arr; } - function changeAggregateType(opt: any[]) { + function changeAggregateType(opt: Option[]) { aggregateType.value = opt[0].value; ebpfStore.setAnalyzeTrees([]); } diff --git a/src/views/dashboard/related/ebpf/components/EBPFStack.vue b/src/views/dashboard/related/ebpf/components/EBPFStack.vue index 190d732d..3e73e97f 100644 --- a/src/views/dashboard/related/ebpf/components/EBPFStack.vue +++ b/src/views/dashboard/related/ebpf/components/EBPFStack.vue @@ -23,10 +23,10 @@ limitations under the License. --> import d3tip from "d3-tip"; import { flamegraph } from "d3-flame-graph"; import { useEbpfStore } from "@/store/modules/ebpf"; - import { useContinousProfilingStore } from "@/store/modules/continous-profiling"; - import { ComponentType } from "@/views/dashboard/related/continuous-profiling/data"; + import { useAsyncProfilingStore } from "@/store/modules/async-profiling"; import type { StackElement } from "@/types/ebpf"; import { AggregateTypes } from "./data"; + import { JFREventType, ComponentType } from "@/views/dashboard/related/async-profiling/components/data"; import "d3-flame-graph/dist/d3-flamegraph.css"; import { treeForeach } from "@/utils/flameGraph"; @@ -37,7 +37,7 @@ limitations under the License. --> default: "", }, }); - const ebpfStore = props.type === ComponentType ? useContinousProfilingStore() : useEbpfStore(); + const ebpfStore = props.type === ComponentType ? useAsyncProfilingStore() : useEbpfStore(); const stackTree = ref>(null); const selectStack = ref>(null); const graph = ref>(null); @@ -102,10 +102,7 @@ limitations under the License. --> .direction("s") .html((d: { data: StackElement } & { parent: { data: StackElement } }) => { const name = d.data.name.replace("<", "<").replace(">", ">"); - const valStr = - ebpfStore.aggregateType === AggregateTypes[0].value - ? `
Dump Count: ${d.data.dumpCount}
` - : `
Duration: ${d.data.dumpCount} ns
`; + const valStr = tooltipContent(d.data); const rateOfParent = (d.parent && `
Percentage Of Selected: ${ @@ -125,6 +122,26 @@ limitations under the License. --> d3.select("#graph-stack").datum(stackTree.value).call(flameChart.value); } + function tooltipContent(item: StackElement) { + if (props.type === ComponentType) { + if (!ebpfStore.analyzeTrees.length) { + return; + } + const { type } = ebpfStore.analyzeTrees[0]; + if ([JFREventType.JAVA_MONITOR_ENTER, JFREventType.THREAD_PARK].includes(type)) { + return `
Duration: ${item.dumpCount} ms
`; + } + if (type === JFREventType.EXECUTION_SAMPLE) { + return `
Count: ${item.dumpCount}
`; + } + return `
Memory: ${item.dumpCount} byte
`; + } + + ebpfStore.aggregateType === AggregateTypes[0].value + ? `
Dump Count: ${item.dumpCount}
` + : `
Duration: ${item.dumpCount} ns
`; + } + function countRange() { const list = []; for (const tree of ebpfStore.analyzeTrees) {