import { Box, Button, Checkbox, Dialog, DialogContent, DialogTitle, FormControlLabel, InputLabel, Link, MenuItem, Select, TextField, Tooltip, Typography, } from "@mui/material"; import React, { PropsWithChildren, useEffect, useState } from "react"; import { HelpInfo } from "../components/Tooltip"; import { ClassNameProps } from "./props"; let cachedProfilingEnabled: boolean | null = null; let fetchPromise: Promise | null = null; const fetchProfilingEnabled = (): Promise => { if (cachedProfilingEnabled !== null) { return Promise.resolve(); } if (!fetchPromise) { fetchPromise = fetch("/api/profiling_enabled") .then((res) => res.json()) .then((data) => { cachedProfilingEnabled = data.data.profilingEnabled; }) .catch(() => { cachedProfilingEnabled = false; }); } return fetchPromise; }; const useProfilingEnabled = () => { const [enabled, setEnabled] = useState(cachedProfilingEnabled ?? false); useEffect(() => { fetchProfilingEnabled().then(() => setEnabled(cachedProfilingEnabled ?? false), ); }, []); return enabled; }; const PROFILING_DISABLED_TOOLTIP = "Profiling is disabled by default for security. " + "Set RAY_DASHBOARD_ENABLE_PROFILING=1 environment variable on the Ray head node to enable. " + "See https://docs.ray.io/en/latest/ray-observability/user-guides/profiling.html#enabling-dashboard-profiling"; const DisabledProfilingLabel = ({ children, }: { children: React.ReactNode; }) => ( {children} ); type CpuProfilingLinkProps = PropsWithChildren< { pid: string | number | null | undefined; nodeId: string | null | undefined; type: string | null; } & ClassNameProps >; type TaskProfilingStackTraceProps = { taskId: string | null | undefined; attemptNumber: number; nodeId: string; }; type MemoryProfilingProps = PropsWithChildren< { pid: string | number | null | undefined; nodeId: string | null | undefined; type?: string | null; } & ClassNameProps >; type TaskMemoryProfilingProps = { taskId: string | null | undefined; attemptNumber: number; nodeId: string; }; type MemoryProfilingButtonProps = { profilerUrl: string; type?: string | null; }; export const TaskCpuProfilingLink = ({ taskId, attemptNumber, nodeId, }: TaskProfilingStackTraceProps) => { const profilingEnabled = useProfilingEnabled(); if (!taskId) { return null; } if (!profilingEnabled) { return ( CPU Flame Graph ); } return ( CPU Flame Graph ); }; export const TaskCpuStackTraceLink = ({ taskId, attemptNumber, nodeId, }: TaskProfilingStackTraceProps) => { const profilingEnabled = useProfilingEnabled(); if (!taskId) { return null; } if (!profilingEnabled) { return Stack Trace; } return ( Stack Trace ); }; export const CpuStackTraceLink = ({ pid, nodeId, type = "", }: CpuProfilingLinkProps) => { const profilingEnabled = useProfilingEnabled(); if ( !pid || !nodeId || typeof pid === "undefined" || typeof nodeId === "undefined" ) { return
; } if (!profilingEnabled) { return ( Stack Trace{type ? ` (${type})` : ""} ); } return ( Stack Trace{type ? ` (${type})` : ""} ); }; export const CpuProfilingLink = ({ pid, nodeId, type = "", }: CpuProfilingLinkProps) => { const profilingEnabled = useProfilingEnabled(); if (!pid || !nodeId) { return
; } if (!profilingEnabled) { return ( CPU Flame Graph{type ? ` (${type})` : ""} ); } return ( CPU Flame Graph{type ? ` (${type})` : ""} ); }; export const ProfilerButton = ({ profilerUrl, type, }: MemoryProfilingButtonProps) => { const [duration, setDuration] = useState(5); const [leaks, setLeaks] = useState(true); const [native, setNative] = useState(false); const [allocator, setAllocator] = useState(false); const [open, setOpen] = useState(false); const [format, setFormat] = useState("flamegraph"); const handleOpen = () => { setOpen(true); }; const handleClose = () => { setOpen(false); }; return (
Memory Profiling{type ? ` (${type})` : ""} Memory Profiling Config Format setDuration(parseInt(e.target.value, 10))} required />
setLeaks(e.target.checked)} /> } label={
Leaks Enable memory leaks, instead of peak memory usage. Refer to Memray documentation for more details.
} />
setNative(e.target.checked)} /> } label={
Native Track native (C/C++) stack frames. Refer to Memray documentation for more details.
} />
setAllocator(e.target.checked)} /> } label={
Python Allocator Tracing Record allocations made by the pymalloc allocator. Refer to Memray documentation for more details.
} />
); }; export const MemoryProfilingButton = ({ pid, nodeId, type = "", }: MemoryProfilingProps) => { const profilingEnabled = useProfilingEnabled(); if (!pid || !nodeId) { return
; } if (!profilingEnabled) { return ( Memory Profiling{type ? ` (${type})` : ""} ); } const profilerUrl = `memory_profile?pid=${pid}&node_id=${nodeId}`; return ; }; export const TaskMemoryProfilingButton = ({ taskId, attemptNumber, nodeId, }: TaskMemoryProfilingProps) => { const profilingEnabled = useProfilingEnabled(); if (!taskId) { return null; } if (!profilingEnabled) { return ( Memory Profiling ); } const profilerUrl = `memory_profile?task_id=${taskId}&attempt_number=${attemptNumber}&node_id=${nodeId}`; return ; };