sgl-project/sglang · error · Exception

Trace file is empty.

Error message

Trace file is empty.

What it means

rpd_to_chrome_trace opens the ROCm RPD profiling database and queries MIN(start) from rocpd_api; a NULL result means the API-event table has no rows, i.e. the captured profile contains no kernel/API activity, so conversion cannot proceed.

Source

Thrown at python/sglang/srt/utils/rpd_utils.py:72

                    ',{"name":"thread_name","ph":"M","pid":"%s","tid":"%s","args":{"name":"%s"}}\n'
                    % (row[0], row[1], "HSA " + str(row[1]))
                )
                outfile.write(
                    ',{"name":"thread_sort_index","ph":"M","pid":"%s","tid":"%s","args":{"sort_index":"%s"}}\n'
                    % (row[0], row[1], row[1] * 2 - 1)
                )
            except ValueError:
                outfile.write("")
    except:
        pass

    rangeStringApi = ""
    rangeStringOp = ""
    rangeStringMonitor = ""
    min_time = connection.execute("select MIN(start) from rocpd_api;").fetchall()[0][0]
    max_time = connection.execute("select MAX(end) from rocpd_api;").fetchall()[0][0]
    if min_time is None:
        raise Exception("Trace file is empty.")

    print("Timestamps:")
    print(f"\t    first: \t{min_time/1000} us")
    print(f"\t     last: \t{max_time/1000} us")
    print(f"\t duration: \t{(max_time-min_time) / 1000000000} seconds")

    start_time = min_time / 1000
    end_time = max_time / 1000

    if start:
        if "%" in start:
            start_time = (
                (max_time - min_time) * (int(start.replace("%", "")) / 100) + min_time
            ) / 1000
        else:
            start_time = int(start)
        rangeStringApi = "where rocpd_api.start/1000 >= %s" % (start_time)
        rangeStringOp = "where rocpd_op.start/1000 >= %s" % (start_time)

View on GitHub (pinned to 0132848349)

Solutions

  1. Re-profile with a wider window: ensure GPU work occurs between start and stop
  2. Verify with sqlite3 <file> 'select count(*) from rocpd_api;' that events exist before converting
  3. Check the RPD/ROCprofiler capture configuration actually enabled API/kernel records
  4. Discard empty runs and only convert DBs with nonzero event counts

Example fix

# before
rpd_to_chrome_trace('empty.rpd')  # Exception: Trace file is empty.
# after
import sqlite3
if sqlite3.connect('run.rpd').execute('select count(*) from rocpd_api').fetchone()[0] > 0:
    rpd_to_chrome_trace('run.rpd')
Defensive patterns

Strategy: validation

Validate before calling

import sqlite3
def rpd_has_events(path: str) -> bool:
    con = sqlite3.connect(path)
    try:
        return con.execute('select count(*) from rocpd_api').fetchone()[0] > 0
    finally:
        con.close()

Type guard

null

Try / catch

try:
    rpd_to_chrome_trace(path)
except Exception as e:
    if 'Trace file is empty' in str(e):
        logger.warning('empty RPD capture %s; skipping conversion', path)

Prevention

When it happens

Trigger: Calling rpd_to_chrome_trace on an RPD sqlite file produced by a profiling session that recorded nothing — profiler started and stopped before work ran, wrong pass/iteration range, or capture failed silently.

Common situations: Short-lived benchmarks where the profiler window misses all kernels; RPD tool version/config capturing zero API records; converting placeholder DBs.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/27988ce21e4377c5. Report an issue: GitHub.