Skip to content

Commit 3b59c45

Browse files
committed
Pin FMA+KEDA workloads to a target node for benchmarking
Adds explicit node targeting for the FMA launcher/requester workloads so a benchmark can be confined to one node, including a tainted one: Signed-off-by: dumb0002 <Braulio.Dumba@ibm.com>
1 parent 9d0129a commit 3b59c45

7 files changed

Lines changed: 295 additions & 50 deletions

File tree

config/scenarios/cicd/ocp-keda-fma-hotstart.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,12 @@ scenario:
108108
# type and all free, labels it, and pins the LauncherPopulationPolicy +
109109
# requester Deployment to it; launcherCount/replicas are sized to that
110110
# node's GPU count. Standup fails if no fully-free single-type GPU node.
111+
# Node/label/taint come from the shared top-level `nodePinning` block
112+
# (config/templates/values/defaults.yaml) so they are set in ONE place.
113+
# Uncomment nodeLabel/nodeLabelValue/nodeName here only to override it
114+
# for this scenario alone.
111115
launcherNodeSelection:
112116
enabled: true
113-
nodeLabel: fma-hotstart
114117

115118
# HOT-START CHANGE #1: Deploy all replicas at standup for parallel model loading
116119
# Initially set to maxReplicas so all launcher pods load models simultaneously

config/templates/jinja/24_fma-deployment.yaml.j2

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,17 @@
44
fma-deployment.yaml.j2
55
66
Fast Model Actuation Deployment.
7+
8+
Node pinning resolves from the shared `nodePinning` block (defaults.yaml)
9+
unless the scenario sets the fma.* equivalent, which wins.
710
============================================================================ #}
11+
{% set _np = nodePinning | default({}) %}
12+
{% set _np_on = _np.enabled | default(false) %}
13+
{% set _lns = fma.launcherNodeSelection | default({}) %}
14+
{% set _pin_on = _lns.enabled | default(false) or _np_on %}
15+
{% set _pin_label = _lns.nodeLabel | default('', true) or (_np.nodeLabel if _np_on else '') or 'fma-hotstart' %}
16+
{% set _pin_value = _lns.nodeLabelValue | default('', true) or (_np.nodeLabelValue if _np_on else '') or 'true' %}
17+
{% set _pin_tolerations = fma.tolerations | default([], true) or (_np.tolerations | default([], true) if _np_on else []) %}
818

919
apiVersion: fma.llm-d.ai/v1alpha1
1020
kind: InferenceServerConfig
@@ -84,6 +94,12 @@ spec:
8494
serviceAccountName: fma-launcher
8595
{% if fma.launcher.runtimeClassName is defined and fma.launcher.runtimeClassName %}
8696
runtimeClassName: {{ fma.launcher.runtimeClassName }}
97+
{% endif %}
98+
{% if _pin_tolerations %}
99+
# Launcher pods are created by the FMA controller from this podTemplate,
100+
# so a taint on the target node has to be tolerated here.
101+
tolerations:
102+
{{ _pin_tolerations | toyaml | indent(8, first=True) }}
87103
{% endif %}
88104
containers:
89105
- name: inference-server
@@ -173,9 +189,9 @@ spec:
173189
labelSelector:
174190
matchLabels:
175191
nvidia.com/gpu.present: "true"
176-
{% if fma.launcherNodeSelection is defined and fma.launcherNodeSelection.enabled | default(false) %}
192+
{% if _pin_on %}
177193
# Pin launchers to the single GPU node step_06 selected + labeled.
178-
{{ fma.launcherNodeSelection.nodeLabel | default('fma-hotstart') }}: "true"
194+
{{ _pin_label }}: "{{ _pin_value }}"
179195
{% endif %}
180196
# Skip unhealthy nodes
181197
matchExpressions:
@@ -216,11 +232,15 @@ spec:
216232
dual-pods.llm-d.ai/admin-port: "8081"
217233
dual-pods.llm-d.ai/inference-server-config: fma-{{ model_id_label }}
218234
spec:
219-
{% if fma.launcherNodeSelection is defined and fma.launcherNodeSelection.enabled | default(false) %}
235+
{% if _pin_on %}
220236
# Pin the requester to the single GPU node step_06 selected + labeled.
221237
# ANDed with the nodeAffinity below (which stays load-bearing for WVA).
222238
nodeSelector:
223-
{{ fma.launcherNodeSelection.nodeLabel | default('fma-hotstart') }}: "true"
239+
{{ _pin_label }}: "{{ _pin_value }}"
240+
{% endif %}
241+
{% if _pin_tolerations %}
242+
tolerations:
243+
{{ _pin_tolerations | toyaml | indent(8, first=True) }}
224244
{% endif %}
225245
{# Pick a resolved accelerator type from decode/prefill/standalone
226246
(cluster_resource_resolver.py rewrites `labelValue: auto` into the

config/templates/values/defaults.yaml

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,43 @@ kustomize:
15251525

15261526
# ============================================================================
15271527
# FMA DEPLOYMENT CONFIGURATION
1528+
# ============================================================================
1529+
# Single-node pinning (benchmark isolation)
1530+
#
1531+
# ONE place to name the reserved node and its taint. Set these three values
1532+
# and every workload that reads them lands on that node -- no per-scenario
1533+
# edits. Consumed by:
1534+
# - FMA launchers + requester (24_fma-deployment.yaml.j2)
1535+
# - EPP (12_router-values.yaml.j2)
1536+
#
1537+
# `enabled: false` leaves every consumer untouched, so this is inert until
1538+
# you fill it in. A scenario can still override any consumer individually
1539+
# (fma.tolerations, router.epp.affinity) -- an explicit per-scenario value
1540+
# always wins over these defaults.
1541+
#
1542+
# The harness and data-access pods are deliberately NOT pinned: with a taint
1543+
# on the node they cannot land there, which is what keeps load generation off
1544+
# the measurement node.
1545+
# ============================================================================
1546+
nodePinning:
1547+
enabled: false
1548+
# Node to pin to. Also used as fma.launcherNodeSelection.nodeName, which
1549+
# skips FMA's free-GPU/CPU auto-scan (that scan ignores taints and could
1550+
# otherwise pick a node whose pods never schedule).
1551+
nodeName: ""
1552+
# Label the node already carries, used for pod placement. EPP has no
1553+
# nodeSelector in the router chart, so this becomes a nodeAffinity term
1554+
# there and a nodeSelector for the FMA requester/launchers.
1555+
nodeLabel: ""
1556+
nodeLabelValue: ""
1557+
# Taints to tolerate. A label places a pod; only a matching toleration lets
1558+
# it schedule on a tainted node. Standard corev1.Toleration entries, e.g.
1559+
# - key: reserved
1560+
# operator: Equal
1561+
# value: my-workload
1562+
# effect: NoSchedule
1563+
tolerations: []
1564+
15281565
# For Fast Model Actuation
15291566
# ============================================================================
15301567
fma:
@@ -1538,7 +1575,19 @@ fma:
15381575
# (used by cicd/ocp-wva-fma-hotstart).
15391576
launcherNodeSelection:
15401577
enabled: false
1541-
nodeLabel: fma-hotstart
1578+
# Empty so an inherited nodePinning value is not masked by a default; the
1579+
# effective fallback when neither is set is still fma-hotstart=true.
1580+
nodeLabel: ""
1581+
nodeLabelValue: ""
1582+
# Pin to this node instead of auto-selecting one. Required when the target
1583+
# node is tainted: the auto-scan reads allocatable/committed resources and
1584+
# does not consider taints, so it can pick a node whose pods never schedule.
1585+
nodeName: ""
1586+
1587+
# Tolerations applied to the FMA launcher pods and the requester Deployment.
1588+
# Needed when the target node carries a taint -- a nodeSelector alone places
1589+
# a pod, but only a matching toleration lets it schedule there.
1590+
tolerations: []
15421591

15431592
# Deployment naming
15441593
deployment:

0 commit comments

Comments
 (0)