Skip to content

Commit fd1446d

Browse files
committed
[train]: generate operator statistics by PyTorch Profiler.
1 parent fecf6e7 commit fd1446d

1 file changed

Lines changed: 57 additions & 1 deletion

File tree

flagscale/train/megatron/training/training.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ def set_startup_timestamps(program_start=None, main_entry=None):
6868
except ImportError:
6969
has_rl_utils = False
7070

71+
import csv
72+
from torch.autograd.profiler import DeviceType
73+
PROFILER_NCCL_FILTER = {"nccl", "AllReduce", "AllGather", "AllToAll", "Broadcast", "ReduceScatter"}
74+
PROFILER_MEM_FILTER = {"memcpy", "memset"}
75+
7176
# Canonical list of RL timer names to include in timers_to_log.
7277
# When the profiling branch is merged, this will be imported from rl_profiling
7378
# as RL_LOGGABLE_TIMER_NAMES instead of being defined here.
@@ -3217,7 +3222,58 @@ def get_e2e_base_metrics():
32173222
def trace_handler(p):
32183223
profile_dir = Path(f"{args.tensorboard_dir}/../torch_profile")
32193224
profile_dir.mkdir(parents=True, exist_ok=True)
3220-
p.export_chrome_trace(f"{profile_dir}/rank-{torch.distributed.get_rank()}.json.gz")
3225+
rank = torch.distributed.get_rank()
3226+
p.export_chrome_trace(f"{profile_dir}/rank-{rank}.json.gz")
3227+
# CUDA kernel profiling
3228+
csv_cuda = f"{profile_dir}/rank-{rank}_cuda_kernel_non_comm.csv"
3229+
cuda_rows = []
3230+
for item in p.key_averages():
3231+
op_name = item.key
3232+
# collect only non-communication ops with non-zero CUDA time
3233+
if hasattr(item, 'cuda_time_total') and item.cuda_time_total > 0:
3234+
# filter out communication and memory copy ops
3235+
is_nccl = any(w.lower() in op_name.lower() for w in PROFILER_NCCL_FILTER)
3236+
is_mem = any(w.lower() in op_name.lower() for w in PROFILER_MEM_FILTER)
3237+
if is_nccl or is_mem:
3238+
continue
3239+
avg_cuda = item.cuda_time_total / item.count if item.count > 0 else 0.0
3240+
cuda_rows.append({
3241+
"kernel_name": op_name,
3242+
"count": item.count,
3243+
"total_cuda_us": item.cuda_time_total,
3244+
"avg_cuda_us": round(avg_cuda, 2),
3245+
"self_cuda_us": item.self_cuda_time_total
3246+
})
3247+
cuda_rows.sort(key=lambda x: x["total_cuda_us"], reverse=True)
3248+
with open(csv_cuda, "w", newline="", encoding="utf-8-sig") as f:
3249+
field_names = ["kernel_name", "count", "total_cuda_us", "avg_cuda_us", "self_cuda_us"]
3250+
writer = csv.DictWriter(f, fieldnames=field_names)
3251+
writer.writeheader()
3252+
writer.writerows(cuda_rows)
3253+
print(f"[CUDA] non communication op list is saved to: {csv_cuda}")
3254+
# PyTorch ATen op profiling
3255+
csv_torch = f"{profile_dir}/rank-{rank}_torch_aten_op.csv"
3256+
torch_rows = []
3257+
for item in p.key_averages():
3258+
op_name = item.key
3259+
if item.device_type != DeviceType.CPU:
3260+
continue
3261+
avg_cpu = item.cpu_time_total / item.count if item.count > 0 else 0.0
3262+
torch_rows.append({
3263+
"aten_op_name": op_name,
3264+
"count": item.count,
3265+
"total_cpu_us": item.cpu_time_total,
3266+
"avg_cpu_us": round(avg_cpu, 2),
3267+
"self_cpu_us": item.self_cpu_time_total
3268+
})
3269+
3270+
torch_rows.sort(key=lambda x: x["total_cpu_us"], reverse=True)
3271+
with open(csv_torch, "w", newline="", encoding="utf-8-sig") as f:
3272+
field_names = ["aten_op_name", "count", "total_cpu_us", "avg_cpu_us", "self_cpu_us"]
3273+
writer = csv.DictWriter(f, fieldnames=field_names)
3274+
writer.writeheader()
3275+
writer.writerows(torch_rows)
3276+
print(f"[Torch Aten] op list is saved to: {csv_torch}")
32213277
prof = torch.profiler.profile(
32223278
schedule=torch.profiler.schedule(
32233279
wait=max(args.profile_step_start - 1, 0),

0 commit comments

Comments
 (0)