Skip to content

Commit b93f944

Browse files
feat: Add Perf profiler multi-event selector with checkbox UI
1 parent b80eea5 commit b93f944

File tree

2 files changed

+162
-42
lines changed

2 files changed

+162
-42
lines changed

src/gprofiler/frontend/src/components/console/ProfilingStatusPage.jsx

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,28 @@ import PageHeader from '../common/layout/PageHeader';
2020
import ProfilingHeader from './header/ProfilingHeader';
2121
import ProfilingTopPanel from './header/ProfilingTopPanel';
2222

23+
// Constants
24+
const DEFAULT_PROFILING_FREQUENCY = 11;
25+
const DEFAULT_MAX_PROCESSES = 10;
26+
const DEFAULT_DURATION = 60;
27+
28+
// Helper function to build profile URL
29+
const buildProfileUrl = (host, service, view) => {
30+
const baseUrl = `${window.location.protocol}//${window.location.host}`;
31+
const params = {
32+
filter: `hn,is,${host}`,
33+
gtab: '1',
34+
pm: '1',
35+
rtms: '1',
36+
service: service,
37+
time: '1h',
38+
view: view,
39+
wp: '100'
40+
};
41+
const queryParams = new URLSearchParams(params).toString();
42+
return `${baseUrl}${PAGES.profiles.to}?${queryParams}`;
43+
};
44+
2345
const columns = [
2446
{ field: 'service', headerName: 'service name', flex: 1, sortable: true },
2547
{ field: 'host', headerName: 'host name', flex: 1, sortable: true },
@@ -72,13 +94,12 @@ const columns = [
7294

7395
if (!host || !service) return '';
7496

75-
const baseUrl = `${window.location.protocol}//${window.location.host}`;
76-
const continuousProfileUrl = `${baseUrl}${PAGES.profiles.to}?filter=hn,is,${encodeURIComponent(host)}&gtab=1&pm=1&rtms=1&service=${encodeURIComponent(service)}&time=1h&view=flamegraph&wp=100`;
77-
const adhocProfileUrl = `${baseUrl}${PAGES.profiles.to}?filter=hn,is,${encodeURIComponent(host)}&gtab=1&pm=1&rtms=1&service=${encodeURIComponent(service)}&time=1h&view=adhoc&wp=100`;
97+
const continuousProfileUrl = buildProfileUrl(host, service, 'flamegraph');
98+
const adhocProfileUrl = buildProfileUrl(host, service, 'adhoc');
7899

79100
return (
80101
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
81-
<a
102+
<a
82103
href={continuousProfileUrl}
83104
target="_blank"
84105
rel="noopener noreferrer"
@@ -90,14 +111,14 @@ const columns = [
90111
</a>
91112
<a
92113
href={adhocProfileUrl}
93-
target="_blank"
94-
rel="noopener noreferrer"
114+
target="_blank"
115+
rel="noopener noreferrer"
95116
style={{ color: '#1976d2', textDecoration: 'none', fontSize: '0.875rem' }}
96-
onMouseOver={(e) => e.target.style.textDecoration = 'underline'}
97-
onMouseOut={(e) => e.target.style.textDecoration = 'none'}
98-
>
117+
onMouseOver={(e) => e.target.style.textDecoration = 'underline'}
118+
onMouseOut={(e) => e.target.style.textDecoration = 'none'}
119+
>
99120
View Adhoc Profile
100-
</a>
121+
</a>
101122
</Box>
102123
);
103124
},
@@ -131,20 +152,23 @@ const ProfilingStatusPage = () => {
131152
const [enablePerfSpect, setEnablePerfSpect] = useState(false);
132153

133154
// Profiling frequency state
134-
const [profilingFrequency, setProfilingFrequency] = useState(11);
155+
const [profilingFrequency, setProfilingFrequency] = useState(DEFAULT_PROFILING_FREQUENCY);
135156

136157
// Max processes state
137-
const [maxProcesses, setMaxProcesses] = useState(10);
158+
const [maxProcesses, setMaxProcesses] = useState(DEFAULT_MAX_PROCESSES);
138159

139160
// Profiling mode state (Ad Hoc vs Continuous)
140161
const [profilingMode, setProfilingMode] = useState('continuous'); // 'adhoc' or 'continuous'
141162

142163
// Duration state
143-
const [duration, setDuration] = useState(60);
164+
const [duration, setDuration] = useState(DEFAULT_DURATION);
144165

145166
// Profiler configurations state
146167
const [profilerConfigs, setProfilerConfigs] = useState({
147-
perf: 'enabled_restricted', // 'enabled_restricted', 'enabled_aggressive', 'disabled'
168+
perf: {
169+
mode: 'enabled_restricted', // 'enabled_restricted', 'enabled_aggressive', 'disabled'
170+
events: ['cpu-cycles'] // Array of events: 'cpu-cycles', 'instructions', 'cache-misses', etc.
171+
},
148172
async_profiler: {
149173
enabled: true,
150174
time: 'cpu' // 'cpu' or 'wall'

src/gprofiler/frontend/src/components/console/header/ProfilingTopPanel.jsx

Lines changed: 124 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import React from 'react';
44
import { COLORS } from '../../../theme/colors';
55
import Flexbox from '../../common/layout/Flexbox';
66

7+
// Constants
8+
const DEFAULT_PROFILING_FREQUENCY = 11; // Hz - industry standard for low overhead
9+
const DEFAULT_MAX_PROCESSES = 10;
10+
const DEFAULT_DURATION = 60; // seconds
11+
const CONTINUOUS_MODE_DURATION = 60; // Fixed duration for continuous mode
12+
713
const PanelDivider = () => <Divider orientation='vertical' sx={{ borderColor: 'grey.dark', opacity: 0.1 }} flexItem />;
814

915
const ProfilingTopPanel = ({
@@ -49,6 +55,38 @@ const ProfilingTopPanel = ({
4955
}));
5056
};
5157

58+
// Helper function to handle perf profiler nested config changes
59+
const handlePerfProfilerConfigChange = (field, value) => {
60+
onProfilerConfigsChange(prev => ({
61+
...prev,
62+
perf: {
63+
...prev.perf,
64+
[field]: value
65+
}
66+
}));
67+
};
68+
69+
// Helper function to toggle perf events
70+
const handlePerfEventToggle = (eventName, isChecked) => {
71+
const currentEvents = profilerConfigs.perf?.events || [];
72+
const newEvents = isChecked
73+
? [...currentEvents, eventName]
74+
: currentEvents.filter(ev => ev !== eventName);
75+
handlePerfProfilerConfigChange('events', newEvents);
76+
};
77+
78+
// Perf event configuration
79+
const perfEvents = [
80+
{ value: 'cpu-cycles', label: 'CPU Cycles', tooltip: 'Total processor cycles executed' },
81+
{ value: 'instructions', label: 'Instructions', tooltip: 'Instructions executed by the CPU' },
82+
{ value: 'cache-misses', label: 'Cache Misses', tooltip: 'Failed cache lookups - indicates memory access issues' },
83+
{ value: 'cache-references', label: 'Cache References', tooltip: 'Total cache access attempts' },
84+
{ value: 'branch-instructions', label: 'Branch Instructions', tooltip: 'Conditional jump instructions executed' },
85+
{ value: 'branch-misses', label: 'Branch Misses', tooltip: 'Mispredicted branches - impacts pipeline efficiency' },
86+
{ value: 'stalled-cycles-frontend', label: 'Stalled Cycles (Frontend)', tooltip: 'CPU cycles stalled waiting for instructions' },
87+
{ value: 'stalled-cycles-backend', label: 'Stalled Cycles (Backend)', tooltip: 'CPU cycles stalled during execution (CPU-dependent)' }
88+
];
89+
5290
// Profiler configuration definitions
5391
const profilerDefinitions = [
5492
{
@@ -361,46 +399,104 @@ const ProfilingTopPanel = ({
361399
</AccordionSummary>
362400
<AccordionDetails sx={{ p: 3 }}>
363401
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(300px, 1fr))', gap: 3 }}>
364-
{/* Render Perf Profiler first */}
365-
{profilerDefinitions.filter(p => p.key === 'perf').map((profiler) => (
366-
<Box key={profiler.key} sx={{
402+
{/* Render Perf Profiler first with Event Selector */}
403+
<Box sx={{
367404
border: '1px solid #e0e0e0',
368405
borderRadius: 2,
369406
p: 2,
370407
backgroundColor: '#fafafa'
371408
}}>
372409
<Typography variant="body2" sx={{ fontSize: '0.875rem', fontWeight: 600, mb: 0.5 }}>
373-
{profiler.name}
410+
Perf Profiler
374411
</Typography>
375412
<Typography variant="body2" sx={{ fontSize: '0.75rem', color: 'text.secondary', mb: 2 }}>
376-
{profiler.description}
413+
C, C++, Go, Kernel
377414
</Typography>
415+
416+
{/* Mode Selection */}
378417
<RadioGroup
379-
value={profilerConfigs[profiler.key]}
380-
onChange={(e) => handleProfilerConfigChange(profiler.key, e.target.value)}
418+
value={profilerConfigs.perf?.mode || 'enabled_restricted'}
419+
onChange={(e) => handlePerfProfilerConfigChange('mode', e.target.value)}
420+
>
421+
<Tooltip
422+
title="Profiles only top N containers/process"
423+
placement="right"
424+
arrow
381425
>
382-
{profiler.options.map((option) => (
383-
<Tooltip
384-
key={option.value}
385-
title={option.tooltip || ''}
386-
placement="right"
387-
arrow
388-
>
389-
<FormControlLabel
390-
value={option.value}
391-
control={<Radio size="small" />}
392-
label={
393-
<Typography variant="body2" sx={{ fontSize: '0.75rem' }}>
394-
{option.label}
395-
</Typography>
396-
}
397-
sx={{ mb: 0.5 }}
398-
/>
399-
</Tooltip>
400-
))}
401-
</RadioGroup>
426+
<FormControlLabel
427+
value="enabled_restricted"
428+
control={<Radio size="small" />}
429+
label={
430+
<Typography variant="body2" sx={{ fontSize: '0.75rem' }}>
431+
Enabled Restricted
432+
</Typography>
433+
}
434+
sx={{ mb: 0.5 }}
435+
/>
436+
</Tooltip>
437+
<Tooltip
438+
title="Profiles all processes"
439+
placement="right"
440+
arrow
441+
>
442+
<FormControlLabel
443+
value="enabled_aggressive"
444+
control={<Radio size="small" />}
445+
label={
446+
<Typography variant="body2" sx={{ fontSize: '0.75rem' }}>
447+
Enabled Aggressive
448+
</Typography>
449+
}
450+
sx={{ mb: 0.5 }}
451+
/>
452+
</Tooltip>
453+
<FormControlLabel
454+
value="disabled"
455+
control={<Radio size="small" />}
456+
label={
457+
<Typography variant="body2" sx={{ fontSize: '0.75rem' }}>
458+
Disabled
459+
</Typography>
460+
}
461+
sx={{ mb: 0.5 }}
462+
/>
463+
</RadioGroup>
464+
465+
{/* Event Selection - Only show when perf is enabled */}
466+
{profilerConfigs.perf?.mode !== 'disabled' && (
467+
<Box sx={{ ml: 3, mt: 2 }}>
468+
<Typography variant="body2" sx={{ fontSize: '0.75rem', fontWeight: 500, mb: 1 }}>
469+
Event Types (select one or more):
470+
</Typography>
471+
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
472+
{perfEvents.map(event => (
473+
<Tooltip
474+
key={event.value}
475+
title={event.tooltip}
476+
placement="right"
477+
arrow
478+
>
479+
<FormControlLabel
480+
control={
481+
<Checkbox
482+
checked={profilerConfigs.perf?.events?.includes(event.value) || false}
483+
onChange={(e) => handlePerfEventToggle(event.value, e.target.checked)}
484+
size="small"
485+
/>
486+
}
487+
label={
488+
<Typography variant="body2" sx={{ fontSize: '0.75rem' }}>
489+
{event.label}
490+
</Typography>
491+
}
492+
sx={{ mb: 0.5 }}
493+
/>
494+
</Tooltip>
495+
))}
496+
</Box>
497+
</Box>
498+
)}
402499
</Box>
403-
))}
404500

405501
{/* Custom Async Profiler Configuration - Right after Perf */}
406502
<Box sx={{

0 commit comments

Comments
 (0)