* -------------------------------------------------------------------------
* This file is part of the MindStudio project.
* Copyright (c) 2025 Huawei Technologies Co.,Ltd.
*
* MindStudio is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*/
import React, { useState, useEffect, useRef } from 'react';
import { observer } from 'mobx-react-lite';
import { runInAction } from 'mobx';
import { Spin, CollapsiblePanel } from '@insight/lib/components';
import { message } from 'antd';
import { useTranslation } from 'react-i18next';
import type { TFunction } from 'i18next';
import { CardInfo, Session } from '../entity/session';
import { MemorySession, MemoryGraphType, GroupBy } from '../entity/memorySession';
import MemoryDetailTableFilter from './MemoryDetailTableFilter';
import { AntTableChart, TableByComponent } from './AntTableChart';
import { MemorySizeQueryCondition, OperatorMemoryCondition, StaticMemoryCondition } from '../entity/memory';
import { fetchDynamicOperatorMaxMin, fetchStaticOperatorMaxMin, operatorsMemoryGet, staticOpMemoryListGet } from '../utils/RequestUtils';
import { customConsole as console } from '@insight/lib/utils';
import { SortOrder } from 'antd/lib/table/interface';
import type { ResizeTableRef } from '@insight/lib';
const enum CompareSource {
DIFFERENCE = 'Difference',
BASELINE = 'Baseline',
COMPARISON = 'Comparison',
};
const setSelectedRecord = (memorySession: MemorySession, record?: any): void => {
const memoryType: string = memorySession.memoryType;
runInAction(() => {
switch (memoryType) {
case MemoryGraphType.DYNAMIC:
memorySession.selectedRecord = record;
break;
case MemoryGraphType.STATIC:
memorySession.selectedStaticRecord = record;
break;
default:
break;
};
});
};
const buildDynamicSearchParam = (memorySession: MemorySession, tempCurrent: number, isCompare: boolean): OperatorMemoryCondition => {
const rankValue = memorySession.getSelectedRankValue();
const param: OperatorMemoryCondition = {
rankId: rankValue.rankInfo.rankId,
dbPath: rankValue.dbPath,
type: memorySession.groupId,
currentPage: tempCurrent,
pageSize: memorySession.pageSize,
searchName: memorySession.searchEventOperatorName,
minSize: memorySession.minSize,
maxSize: memorySession.maxSize,
filters: memorySession.filters,
rangeFilters: memorySession.rangeFilters,
isOnlyShowAllocatedOrReleasedWithinInterval: memorySession.isOnlyShowAllocatedOrReleasedWithinInterval,
isCompare,
};
if (memorySession.selectedRange) {
param.startTime = memorySession.selectedRange.startTs;
param.endTime = memorySession.selectedRange.endTs;
};
return param;
};
const buildStaticSearchParam = (memorySession: MemorySession, tempCurrent: number, isCompare: boolean): StaticMemoryCondition => {
const rankValue = memorySession.getSelectedRankValue();
const param: StaticMemoryCondition = {
rankId: rankValue.rankInfo.rankId,
dbPath: rankValue.dbPath,
graphId: memorySession.memoryGraphId,
currentPage: tempCurrent,
pageSize: memorySession.pageSize,
searchName: memorySession.searchEventOperatorName,
minSize: memorySession.minSize,
maxSize: memorySession.maxSize,
isCompare,
};
if (memorySession.staticSelectedRange) {
param.startNodeIndex = memorySession.staticSelectedRange.startTs;
param.endNodeIndex = memorySession.staticSelectedRange.endTs;
};
return param;
};
const buildSearchParam = (memorySession: MemorySession, tempCurrent: number, isCompare: boolean): any => {
const memoryType = memorySession.memoryType;
switch (memoryType) {
case MemoryGraphType.DYNAMIC:
return buildDynamicSearchParam(memorySession, tempCurrent, isCompare);
case MemoryGraphType.STATIC:
return buildStaticSearchParam(memorySession, tempCurrent, isCompare);
default:
return buildDynamicSearchParam(memorySession, tempCurrent, isCompare);
};
};
const getFetchApi = (memoryType: string): any => {
switch (memoryType) {
case MemoryGraphType.DYNAMIC:
return operatorsMemoryGet;
case MemoryGraphType.STATIC:
return staticOpMemoryListGet;
default:
return operatorsMemoryGet;
};
};
const getFetchSizeApi = (memoryType: string): any => {
switch (memoryType) {
case MemoryGraphType.DYNAMIC:
return fetchDynamicOperatorMaxMin;
case MemoryGraphType.STATIC:
return fetchStaticOperatorMaxMin;
default:
return fetchDynamicOperatorMaxMin;
};
};
const buildSearchSizeParam = (memorySession: MemorySession, isCompare: boolean): MemorySizeQueryCondition => {
const selectedCard = memorySession.getSelectedRankValue();
const param: MemorySizeQueryCondition = { rankId: selectedCard.rankInfo.rankId, dbPath: selectedCard.dbPath, type: memorySession.groupId, isCompare };
switch (memorySession.memoryType) {
case MemoryGraphType.STATIC:
param.graphId = memorySession.memoryGraphId;
break;
default:
break;
};
return param;
};
export const handleOperatorDetails = (operatorDetails: any[], isCompare: boolean, t: TFunction): any => {
return isCompare
? operatorDetails.map(item => {
if (item.diff === undefined || item.diff === null) {
return item;
}
item.diff.source = t(CompareSource.DIFFERENCE);
item.diff.children = [{ ...item.baseline, source: t(CompareSource.BASELINE) }, { ...item.compare, source: t(CompareSource.COMPARISON) }];
return item.diff;
})
: operatorDetails.map(item => item.compare);
};
const MemoryDetailTable = observer(({ session, memorySession }:
{ session: Session; memorySession: MemorySession }) => {
const isCompare: boolean = session.compareRank.isCompare;
const memoryType: string = memorySession.memoryType;
const [memoryTableData, setMemoryTableData] = useState<any>([]);
const [memoryTableHead, setMemoryTableHead] = useState<any>([]);
const [tableSpin, setTableSpin] = useState<boolean>(false);
const [total, setTotal] = useState<number>(0);
const { t } = useTranslation('memory');
const tableRef = useRef<ResizeTableRef>(null);
const handleReset = (): void => {
clearFilters();
tableRef.current?.clearAllFilters();
tableRef.current?.clearAllSorts();
};
const onRowSelected = (record?: any, rowIndex?: number): void => {
setSelectedRecord(memorySession, record);
};
const handlePageChanged = (newCurrent: number, newPageSize: number): void => {
runInAction(() => {
memorySession.current = newCurrent;
memorySession.pageSize = newPageSize;
});
};
const handleOrderChange = (newOrder: SortOrder): void => {
runInAction(() => {
memorySession.order = newOrder;
});
};
const handleOrderByChange = (newOrderBy: string): void => {
runInAction(() => {
memorySession.orderBy = newOrderBy;
});
};
const handleFiltersChange = (filters: any): void => {
const newFilters: MemorySession['filters'] = {};
const newRangeFilters: MemorySession['rangeFilters'] = {};
Object.keys(filters).forEach((key: string) => {
const filter = filters[key];
if (filter === null || filter === undefined || filter.length < 1) {
return;
}
if (filter.length === 2) {
newRangeFilters[key] = filter.map(Number);
} else {
newFilters[key] = filter[0];
}
});
runInAction(() => {
memorySession.filters = newFilters;
memorySession.rangeFilters = newRangeFilters;
});
};
const preParamCheck = (): boolean => {
const isRankIdConditionInvalid = memorySession.selectedRankId === '';
const isStaticMemoryInvalid = memorySession.memoryType === MemoryGraphType.STATIC && memorySession.memoryGraphId === '';
if (isRankIdConditionInvalid || isStaticMemoryInvalid) {
setMemoryTableData([]);
setTotal(0);
runInAction(() => {
memorySession.isBtnDisabled = true;
memorySession.current = 1;
memorySession.pageSize = 10;
memorySession.minSize = 0;
memorySession.maxSize = 0;
});
return false;
};
if (memorySession.maxSize < memorySession.minSize) {
message.warning(t('Invalid Size Warning'));
return false;
};
return true;
};
const setTempCurrent = (resetCurrent = false): number => {
let tempCurrent = memorySession.current;
if (resetCurrent) {
tempCurrent = 1;
runInAction(() => {
memorySession.current = 1;
});
}
return tempCurrent;
};
const setParamOtherCondition = (param: any): any => {
let newParam = param;
if (memorySession.order !== null) {
newParam = { order: memorySession.order, orderBy: memorySession.orderBy, ...param };
}
setTableSpin(true);
runInAction(() => {
memorySession.isBtnDisabled = true;
});
return newParam;
};
const fetchDetailTableData = (param: any): void => {
const fetchApi = getFetchApi(memorySession.memoryType);
fetchApi(param).then((resp: any) => {
const tableDataDetails = resp.operatorDetail;
setTotal(resp.totalNum);
setMemoryTableData(handleOperatorDetails(tableDataDetails, isCompare, t));
if (JSON.stringify(memoryTableHead) !== JSON.stringify(resp.columnAttr)) {
setMemoryTableHead(resp.columnAttr);
}
}).catch((err: any) => {
console.error(err);
}).finally(() => {
setTableSpin(false);
runInAction(() => {
memorySession.isBtnDisabled = false;
});
});
};
const setDetailTableData = (resetCurrent = false): void => {
if (!preParamCheck() || memorySession.groupId === GroupBy.COMPONENT) {
return;
};
const tempCurrent = setTempCurrent(resetCurrent);
let param = buildSearchParam(memorySession, tempCurrent, isCompare);
param = setParamOtherCondition(param);
fetchDetailTableData(param);
};
const selectedCard = React.useMemo(() => {
const rankValue = memorySession.getSelectedRankValue();
return {
cardId: memorySession.selectedRankId,
dbPath: rankValue.dbPath,
index: rankValue.index,
} as CardInfo;
}, [memorySession.selectedRankId]);
const clearFilters = (): void => {
runInAction(() => {
memorySession.order = null;
memorySession.orderBy = undefined;
memorySession.filters = {};
memorySession.rangeFilters = {};
});
};
useEffect(() => {
clearFilters();
}, [memoryType]);
useEffect(() => {
if (memorySession.groupId === GroupBy.COMPONENT) {
clearFilters();
}
}, [memorySession.groupId]);
useEffect(() => {
if (memorySession.selectedRankId === '' || memorySession.memoryType === '') {
setDetailTableData();
return;
}
if (memorySession.groupId === GroupBy.COMPONENT) {
return;
}
const fetchSizeApi = getFetchSizeApi(memorySession.memoryType);
const params = buildSearchSizeParam(memorySession, isCompare);
fetchSizeApi(params).then((res: { minSize: number; maxSize: number }) => {
runInAction(() => {
memorySession.defaultMinSize = res.minSize ?? 0;
memorySession.defaultMaxSize = res.maxSize ?? 0;
memorySession.minSize = memorySession.defaultMinSize;
memorySession.maxSize = memorySession.defaultMaxSize;
setDetailTableData();
});
}).catch((err: any) => {
console.error(err);
});
}, [memorySession.selectedRankId, memorySession.groupId, memorySession.memoryGraphId, isCompare, memoryType]);
useEffect(() => {
setDetailTableData();
}, [memorySession.selectedRange, memorySession.staticSelectedRange, memorySession.current, memorySession.pageSize,
session.isAllMemoryCompletedSwitch, memorySession.order, memorySession.orderBy, memorySession.filters,
memorySession.rangeFilters, t]);
useEffect(() => {
handleReset();
}, [session.projectChangedTrigger]);
return (
<CollapsiblePanel title={t('Memory Allocation/Release Details')} secondary>
{memorySession.groupId === GroupBy.COMPONENT
? <TableByComponent session={session} />
: <>
<MemoryDetailTableFilter session={session} memorySession={memorySession} queryDetailData={setDetailTableData} onReset={handleReset}></MemoryDetailTableFilter>
<Spin spinning={tableSpin}>
<AntTableChart
ref={tableRef}
tableData={{
columns: memoryTableHead,
rows: memoryTableData,
}}
memoryType={memorySession.memoryType as MemoryGraphType}
onRowSelected={onRowSelected}
current={memorySession.current}
pageSize={memorySession.pageSize}
onPageChange={handlePageChanged}
onOrderChange={handleOrderChange}
onOrderByChange={handleOrderByChange}
onFiltersChange={handleFiltersChange}
total={total}
isCompare={isCompare}
selectedCard={selectedCard}
/>
</Spin>
</>}
</CollapsiblePanel>
);
});
export default MemoryDetailTable;