11name : Profile
22
3+ # Independent profiling requests use priority-scheduled runner slots.
34on : # zizmor: ignore[concurrency-limits]
45 workflow_dispatch :
56 inputs :
@@ -17,6 +18,11 @@ on: # zizmor: ignore[concurrency-limits]
1718 required : false
1819 type : string
1920 default : ' 64'
21+ moe-debug :
22+ description : " Enable MoE debug patch and log (MOE_DEBUG_LOG)"
23+ required : false
24+ type : boolean
25+ default : false
2026 ref :
2127 description : " Ref (branch/sha) to checkout"
2228 required : false
3036 INFERENCEX_E2E_ROOT : ${{ github.workspace }}
3137 PORT : ' 8888'
3238 INFMAX_CONTAINER_WORKSPACE : ' /workspace'
39+ DSV41_MIN_CUDAGRAPH_CAPTURE_SIZE : ' 1'
40+ MODEL_DOWNLOAD_LOCK_TIMEOUT : ' 21600'
3341 ENROOT_IMPORT_TIME_LIMIT : ' 120'
3442 SALLOC_TIME_LIMIT : ' 480'
43+ KEEP_LOGS : ' 0'
3544 EVAL_ONLY : ' false'
3645 RUN_EVAL : ' false'
3746 IS_AGENTIC : ' 0'
3847 IS_MULTINODE : ' false'
48+ SCENARIO_SUBDIR : fixed_seq_len/
3949 HF_TOKEN : ${{ secrets.INFERENCEX_OFFICIAL_RO_HF_TOKEN }}
4050 HF_HUB_CACHE : ' /mnt/hf_hub_cache/'
4151 RANDOM_RANGE_RATIO : ' 0.8'
42- REQUIRE_POWER : ' 0 '
52+ PERFETTO_RELAY_URL : https://semianalysisai.github.io/InferenceX-trace-storage
4353 PYTHONDONTWRITEBYTECODE : ' 1'
4454 PYTHONPYCACHEPREFIX : /tmp/inferencex-pycache
4555
@@ -98,10 +108,12 @@ jobs:
98108 python -P -m infx.workflows.ci_priority \
99109 --policy "${PRIORITY_ROOT}/configs/ci-priority.yaml" \
100110 --event-name "${GITHUB_EVENT_NAME}" \
101- --queue-namespace "${GITHUB_RUN_ID}:${GITHUB_RUN_ATTEMPT}")
111+ --queue-namespace "${GITHUB_RUN_ID}:${GITHUB_RUN_ATTEMPT}" \
112+ --criteria-json "${PRIORITY_CRITERIA}")
102113 echo "raw=$CONFIG_JSON" >> "$GITHUB_OUTPUT"
103114
104115 env :
116+ PRIORITY_CRITERIA : ${{ inputs.moe-debug && '["patchwork"]' || '' }}
105117 INPUTS_CONFIG_FILE : ${{ inputs.config-file }}
106118 INPUTS_CONFIG_KEY : ${{ inputs.config-key }}
107119 INPUTS_CONC : ${{ inputs.conc }}
@@ -198,8 +210,6 @@ jobs:
198210 ) }}
199211 env :
200212 EXP_NAME : ${{ matrix.config.exp-name }}
201- SRT_RECIPE : ${{ matrix.config.srt-recipe }}
202- RECIPE_FINGERPRINT : ${{ matrix.config.recipe-fingerprint }}
203213 MODEL : ${{ matrix.config.model }}
204214 MODEL_PREFIX : ${{ matrix.config.model-prefix }}
205215 ISL : ${{ matrix.config.isl }}
@@ -217,6 +227,8 @@ jobs:
217227 CONC : ${{ matrix.config.conc }}
218228 SPEC_DECODING : ${{ matrix.config.spec-decoding }}
219229 DISAGG : ${{ matrix.config.disagg }}
230+ MOE_DEBUG : ' 0'
231+ MOE_DEBUG_LOG : ${{ (inputs.moe-debug) && '/workspace/moe_debug.tp0.log' || '' }}
220232 steps :
221233 - name : Slurm cleanup
222234 run : |
@@ -231,6 +243,8 @@ jobs:
231243 done
232244 fi
233245
246+ # A cancelled or crashed job can leave git state in this persistent
247+ # workspace that breaks checkout; re-cloning fixes it and is idempotent.
234248 - name : Checkout code
235249 id : checkout
236250 continue-on-error : true
@@ -239,7 +253,6 @@ jobs:
239253 fetch-depth : 0
240254 ref : ${{ inputs.ref || github.sha }}
241255 clean : false
242- submodules : true
243256 persist-credentials : false
244257
245258 - name : Wipe workspace after failed checkout
@@ -251,6 +264,7 @@ jobs:
251264 uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
252265 with : *checkout-inputs
253266
267+ # With clean: false above, nested checkouts also persist between jobs.
254268 - name : Checkout result tooling
255269 id : checkout-tooling
256270 continue-on-error : true
@@ -299,31 +313,59 @@ jobs:
299313 run : |
300314 "$INFERENCEX_LAUNCH_PYTHON" -P -m infx.launch cleanup
301315
302- - name : Launch job script
316+ - name : Launch + Profile (single-node sglang/vllm)
317+ id : run
303318 env :
304319 RUNNER_NAME : ${{ runner.name }}
305- JOB_CHECK_RUN_ID : ${{ job.check_run_id }}
306- RESULT_FILENAME_BASE : ${{ env.EXP_NAME }}_${{ env.PRECISION }}_${{ env.FRAMEWORK }}_tp${{ env.TP }}-pp${{ env.PP_SIZE }}-dcp${{ env.DCP_SIZE }}-pcp${{ env.PCP_SIZE }}-ep${{ env.EP_SIZE }}-dpa${{ env.DP_ATTENTION }}_disagg-${{ env.DISAGG }}_spec-${{ env.SPEC_DECODING }}_conc${{ env.CONC }}_a${{ github.run_attempt }}_${{ runner.name }}
320+ PROFILE : ' 1'
321+ SGLANG_TORCH_PROFILER_DIR : /workspace/
322+ VLLM_TORCH_PROFILER_DIR : /workspace/
323+ VLLM_RPC_TIMEOUT : ' 1800000'
307324 shell : bash
308325 run : |
309326 if [[ -f inferencex-e2e/configs/runners.yaml ]]; then cd inferencex-e2e; fi
310327 export GITHUB_WORKSPACE="$PWD"
311328 echo "INFERENCEX_E2E_ROOT=$PWD" >> "$GITHUB_ENV"
312329 set -eo pipefail
313- RESULT_FILENAME=$(python3 -m infx.results.result_filename)
314- export RESULT_FILENAME
315- echo "RESULT_FILENAME=${RESULT_FILENAME}" >> "$GITHUB_ENV"
316330 export GPU_COUNT=$((TP * PP_SIZE * PCP_SIZE))
317331 echo "GPU_COUNT=${GPU_COUNT}" >> "$GITHUB_ENV"
332+ ep_val="${EP_SIZE:-1}"
333+ res_name="${EXP_NAME}_${PRECISION}_${FRAMEWORK}_tp${TP}-pp${PP_SIZE}-dcp${DCP_SIZE}-pcp${PCP_SIZE}_ep${ep_val}_dpa_${DP_ATTENTION}_conc${CONC}_${RUNNER_NAME}"
334+ export RESULT_FILENAME="${res_name}"
335+ echo "RESULT_FILENAME=${res_name}" >> "$GITHUB_ENV"
318336
319337 source benchmarks/runtime_settings.sh
320338 "$INFERENCEX_LAUNCH_PYTHON" -m infx.launch run
321339
322- if [ ! -f "${RESULT_FILENAME }.json" ]; then
323- echo "Run failed: Benchmark result ${RESULT_FILENAME }.json not found." >&2
340+ if [ ! -f "${res_name }.json" ]; then
341+ echo "Run failed: Benchmark result ${res_name }.json not found." >&2
324342 exit 1
325343 fi
326344
345+ trace_path="profile_${res_name}.trace.json.gz"
346+ if [ -f "$trace_path" ]; then
347+ echo "trace=$PWD/$trace_path" >> "$GITHUB_OUTPUT"
348+ if [ "${FRAMEWORK}" = "sglang" ]; then
349+ # Try to locate corresponding TP-0 traces produced by SGLang profiler
350+ merged_latest=$(ls -t profiles/merged-*.trace.json.gz 2>/dev/null | head -n1 || true)
351+ if [ -n "${merged_latest}" ] && [ -f "${merged_latest}" ]; then
352+ ts_name="${merged_latest##*/}"
353+ ts_name="${ts_name#merged-}"
354+ ts_name="${ts_name%.trace.json.gz}"
355+ tp0_decode="profiles/${ts_name}-TP-0-DECODE.trace.json.gz"
356+ tp0_extend="profiles/${ts_name}-TP-0-EXTEND.trace.json.gz"
357+ if [ -f "${tp0_decode}" ]; then
358+ echo "tp0_decode=$PWD/${tp0_decode}" >> "$GITHUB_OUTPUT"
359+ fi
360+ if [ -f "${tp0_extend}" ]; then
361+ echo "tp0_extend=$PWD/${tp0_extend}" >> "$GITHUB_OUTPUT"
362+ fi
363+ fi
364+ fi
365+ else
366+ echo "Profile trace not found: $trace_path" >&2
367+ fi
368+
327369 - name : Process result (json -> agg)
328370 env :
329371 RUNNER_TYPE : ${{ matrix.config.runner }}
@@ -333,3 +375,108 @@ jobs:
333375 source "$PYTHONPATH/benchmarks/check_env.sh"
334376 check_env_vars INFERENCEX_RESULTS_PYTHON
335377 "$INFERENCEX_RESULTS_PYTHON" -P -m infx.results.fixed_sequence
378+
379+ - name : Upload profile as artifact
380+ if : ${{ steps.run.outputs.trace != '' }}
381+ uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
382+ with :
383+ name : profile_${{ env.RESULT_FILENAME }}
384+ path : ${{ steps.run.outputs.trace }}
385+ if-no-files-found : ignore
386+
387+ - name : Upload TP-0-DECODE trace as artifact
388+ if : ${{ steps.run.outputs.tp0_decode != '' }}
389+ uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
390+ with :
391+ name : profile_${{ env.RESULT_FILENAME }}_TP0_DECODE
392+ path : ${{ steps.run.outputs.tp0_decode }}
393+ if-no-files-found : ignore
394+
395+ - name : Upload TP-0-EXTEND trace as artifact
396+ if : ${{ steps.run.outputs.tp0_extend != '' }}
397+ uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
398+ with :
399+ name : profile_${{ env.RESULT_FILENAME }}_TP0_EXTEND
400+ path : ${{ steps.run.outputs.tp0_extend }}
401+ if-no-files-found : ignore
402+
403+ - name : Upload MoE debug log as artifact
404+ if : ${{ env.MOE_DEBUG == '1' }}
405+ uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
406+ with :
407+ name : moe_debug_${{ env.RESULT_FILENAME }}
408+ path : ${{ env.INFERENCEX_E2E_ROOT }}/moe_debug.tp0.log
409+ if-no-files-found : ignore
410+
411+ - name : Checkout storage repo
412+ id : checkout-storage
413+ if : ${{ steps.run.outputs.trace != '' }}
414+ continue-on-error : true
415+ uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
416+ with : &storage-inputs
417+ repository : SemiAnalysisAI/InferenceX-trace-storage
418+ path : storage
419+ ref : master
420+ # Storage-repository deploy key for authorized profiling dispatches.
421+ ssh-key : ${{ secrets.PROFILER_STORAGE_DEPLOY_KEY }} # zizmor: ignore[secrets-outside-env]
422+ fetch-depth : 0
423+ # This separate storage checkout pushes trace commits using its scoped deploy key.
424+ persist-credentials : true # zizmor: ignore[artipacked]
425+
426+ - name : Wipe storage repo after failed checkout
427+ if : ${{ steps.checkout-storage.outcome == 'failure' }}
428+ run : rm -rf "$GITHUB_WORKSPACE/storage"
429+
430+ - name : Retry storage repo checkout
431+ if : ${{ steps.checkout-storage.outcome == 'failure' }}
432+ uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
433+ with : *storage-inputs # zizmor: ignore[artipacked]
434+
435+ - name : Push profile to storage repo
436+ if : ${{ steps.run.outputs.trace != '' }}
437+ id : push
438+ env :
439+ MATRIX_CONFIG_RUNNER : ${{ matrix.config.runner }}
440+ MATRIX_CONFIG_EXP_NAME : ${{ matrix.config['exp-name'] }}
441+ MATRIX_EP : ${{ matrix.config.ep || 1 }}
442+ TRACE_LOCAL : ${{ steps.run.outputs.trace }}
443+ shell : bash
444+ run : |
445+ set -eo pipefail
446+
447+ dest_dir="storage/profiles/${GITHUB_SHA}/${MATRIX_CONFIG_RUNNER}/${FRAMEWORK}/${MATRIX_CONFIG_EXP_NAME}_${PRECISION}_tp${TP}_pp${PP_SIZE}_dcp${DCP_SIZE}_pcp${PCP_SIZE}_ep${MATRIX_EP}_conc${CONC}"
448+ mkdir -p "$dest_dir"
449+ cp "$TRACE_LOCAL" "$dest_dir/trace.json.gz"
450+
451+ pushd storage >/dev/null
452+ git config user.name "github-actions"
453+ git config user.email "github-actions@github.com"
454+ git add -A
455+ git commit -m "Add profile: ${GITHUB_SHA} ${MATRIX_CONFIG_EXP_NAME} tp${TP} pp${PP_SIZE} dcp${DCP_SIZE} pcp${PCP_SIZE} ep${MATRIX_EP} conc${CONC}" || echo "Nothing to commit"
456+ git push
457+ STORAGE_SHA="$(git rev-parse HEAD)"
458+ popd >/dev/null
459+
460+ export RAW_URL="https://raw.githubusercontent.com/SemiAnalysisAI/InferenceX-trace-storage/${STORAGE_SHA}/profiles/${GITHUB_SHA}/${MATRIX_CONFIG_RUNNER}/${FRAMEWORK}/${MATRIX_CONFIG_EXP_NAME}_${PRECISION}_tp${TP}_pp${PP_SIZE}_dcp${DCP_SIZE}_pcp${PCP_SIZE}_ep${MATRIX_EP}_conc${CONC}/trace.json.gz"
461+ export TITLE="${MATRIX_CONFIG_EXP_NAME}_${PRECISION}_tp${TP}_pp${PP_SIZE}_dcp${DCP_SIZE}_pcp${PCP_SIZE}_ep${MATRIX_EP}_conc${CONC}"
462+
463+ enc_src="$(python3 -c 'import os,urllib.parse; print(urllib.parse.quote(os.environ["RAW_URL"], safe=""))')"
464+ enc_title="$(python3 -c 'import os,urllib.parse; print(urllib.parse.quote(os.environ["TITLE"], safe=""))')"
465+
466+ relay="${PERFETTO_RELAY_URL%/}"
467+ RELAY_URL="${relay}/?src=${enc_src}&title=${enc_title}"
468+
469+ echo "raw_url=$RAW_URL" >> "$GITHUB_OUTPUT"
470+ echo "relay_url=$RELAY_URL" >> "$GITHUB_OUTPUT"
471+
472+ - name : Print Perfetto link (relay)
473+ if : ${{ steps.push.outputs.relay_url != '' }}
474+ env :
475+ RELAY_URL : ${{ steps.push.outputs.relay_url }}
476+ RAW_URL : ${{ steps.push.outputs.raw_url }}
477+ shell : bash
478+ run : |
479+ set -eo pipefail
480+ echo "RAW trace URL: $RAW_URL"
481+ echo "Perfetto Relay URL: $RELAY_URL"
482+ printf "\n**Perfetto (Relay):** %s\n" "$RELAY_URL" >> "$GITHUB_STEP_SUMMARY"
0 commit comments