import {Fragment, useCallback, useMemo, useState} from 'react'; import {Link} from 'react-router'; import styled from '@emotion/styled'; import {clamp} from 'lodash'; import {Button} from 'sentry/components/button'; import ButtonBar from 'sentry/components/buttonBar'; import EmptyStateWarning from 'sentry/components/emptyStateWarning'; import ProjectBadge from 'sentry/components/idBadge/projectBadge'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import Panel from 'sentry/components/panels/panel'; import {Tooltip} from 'sentry/components/tooltip'; import {IconChevron, IconWarning} from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {Project} from 'sentry/types/project'; import {formatAbbreviatedNumber} from 'sentry/utils/formatters'; import {useAggregateFlamegraphQuery} from 'sentry/utils/profiling/hooks/useAggregateFlamegraphQuery'; import {useProfilingFunctionMetrics} from 'sentry/utils/profiling/hooks/useProfilingFunctionMetrics'; import {generateProfileRouteFromProfileReference} from 'sentry/utils/profiling/routes'; import useOrganization from 'sentry/utils/useOrganization'; import useProjects from 'sentry/utils/useProjects'; import {getPerformanceDuration} from 'sentry/views/performance/utils/getPerformanceDuration'; import {ContentContainer, StatusContainer} from './styles'; function sortFunctions(a: Profiling.FunctionMetric, b: Profiling.FunctionMetric) { return b.sum - a.sum; } function useMemoryPagination(items: any[], size: number) { const [pagination, setPagination] = useState({ start: 0, end: size, }); const page = Math.floor(pagination.start / size); const toPage = useCallback( (p: number) => { const next = clamp(p, 0, Math.floor(items.length / size)); setPagination({ start: clamp(next * size, 0, items.length - size), end: Math.min(next * size + size, items.length), }); }, [size, items] ); return { page, start: pagination.start, end: pagination.end, nextButtonProps: { disabled: pagination.end >= items.length, onClick: () => toPage(page + 1), }, previousButtonProps: { disabled: pagination.start <= 0, onClick: () => toPage(page - 1), }, }; } export function SlowestFunctionsTable() { const {projects} = useProjects(); const query = useAggregateFlamegraphQuery({ dataSource: 'profiles', metrics: true, }); const sortedMetrics = useMemo(() => { return query.data?.metrics?.sort(sortFunctions) ?? []; }, [query.data?.metrics]); const pagination = useMemoryPagination(sortedMetrics, 5); const [expandedFingerprint, setExpandedFingerprint] = useState< Profiling.FunctionMetric['fingerprint'] | null >(null); const projectsLookupTable = useMemo(() => { return projects.reduce( (acc, project) => { acc[project.id] = project; return acc; }, {} as Record ); }, [projects]); const hasFunctions = query.data?.metrics && query.data.metrics.length > 0; return ( {query.isLoading && ( )} {query.isError && ( )} {!query.isError && !query.isLoading && !hasFunctions && (

{t('No functions found')}

)} {hasFunctions && query.isFetched && ( {t('Slowest functions')} {t('Package')} {t('Project')} {t('Count()')} {t('p75()')} {t('p95()')} {t('p99()')} {/* @TODO remove sum before relasing */} {t('Sum()')} {sortedMetrics.slice(pagination.start, pagination.end).map((f, i) => { return ( ); })} )}