Skip to content

Support torchrun-style InfiniTrain multi-process launch - #184

Open
chen2021673 wants to merge 6 commits into
masterfrom
8_proc
Open

Support torchrun-style InfiniTrain multi-process launch#184
chen2021673 wants to merge 6 commits into
masterfrom
8_proc

Conversation

@chen2021673

@chen2021673 chen2021673 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Summary

InfiniTrain’s existing parallel execution model primarily launches multiple training threads within a single process. This PR adds a torchrun-style multi-process launcher, allowing each local process to bind to its own GPU while preserving the existing intra-process multithreading mode. It also fixes DataLoader and NCCL unique ID file conflicts in multi-process environments.

  • Add support for launching training processes through infini_run using nproc_per_node.
  • Ensure that the NCCL unique ID is generated only by the communication group’s root rank, with per-run file isolation, atomic publication, and cleanup.
  • Use global batches as the unit for distributed DataLoader partitioning and retrieval, aligning with Megatron’s behavior and fixing out-of-range batch access.
  • Add an 8-process integration test.

Changes

  • Update infini_run to:

    • support -- as the launcher/training-args separator
    • launch nproc_per_node child processes
    • inject both InfiniTrain and torchrun-compatible rank env vars
    • propagate child process failures via exit code
  • Update parallel runtime to:

    • read torchrun-compatible env vars as fallback
    • validate process topology and rank bounds
    • map local process/thread rank to CUDA device index
  • Update GPT-2/Llama3 examples and parallel helpers to use local-device mapping.

  • Update scripts/run_models_and_profile.bash to:

    • always launch model commands through infini_run
    • treat nproc_per_node as launcher-only config
    • keep nthread_per_process as the per-process thread count
  • Update scripts/test_config.json to use multi-process configs:

    • 8-thread cases become nproc_per_node=8, nthread_per_process=1
    • original 4-rank VPP cases become nproc_per_node=4, nthread_per_process=1
  • Add documentation describing behavior, compatibility, and example usage.

Compatibility

Existing direct runs remain supported:

./llama3 ... --nthread_per_process 8

The launcher can also preserve the old single-process multi-thread behavior:

./infini_run --nproc_per_node=1 ./llama3 ... --nthread_per_process 8

The recommended single-node 8-GPU multi-process usage is:

./infini_run --nproc_per_node=8 ./llama3 ... --nthread_per_process 1

Test

image image

Comment thread example/gpt2/main.cc
} else {
Train({0, 0, 1, 1});
nn::parallel::Rank rank(nn::parallel::global::GetGlobalProcRank(), 0, nn::parallel::global::GetNprocPerNode(),
FLAGS_nthread_per_process);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rank 构造函数是:Rank::Rank(int process_rank, int thread_rank, int process_size, int thread_size)

原先第三个参数传的是 global num of processes,现在换成了 num of processes per rank,层次变化了,而 rank 其他 function 逻辑都没改,会在 rank 相关的判断中出现错误,比如 bool Rank::IsParallel() const { return thread_size_ * process_size_ > 1; } 里面会对 nnode=N 但是每个节点单进程、单线程的情况判断为 IsParallel() == false。最好 check 一下 Rank 类里面的逻辑。

@chen2021673 chen2021673 Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

第三个参数原来的注释就是Total number of processes on this node,可能是笔误。这里我修改如下:

  1. 保持参数含义不变(num of processes per node),命名改成更易懂的 processes_per_node_ 等;
  2. 修改 IsParallel() 函数,用GetWorldSize() 判断;
  3. 检查其他地方有没有类似错误,修改。

Comment thread infini_train/include/core/ccl/ccl.h Outdated
virtual void GetAsyncError(const CclComm *comm, CclStatus *async_error) const;

virtual void GetUniqueId(CclUniqueId **unique_id) const;
virtual void CreateUniqueId(CclUniqueId **unique_id, bool generate_id) const;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个接口的名字和参数都不建议改,因为对标的是 nccl 接口 GetUniqueId() ,后续国产平台的应该也都是类似签名。

下面的 nccl_impl.h 的继承实现也得改回来。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread tools/infini_run/infini_run.cc Outdated
SetEnvInt("WORLD_SIZE", proc_world_size);
SetEnvInt("GROUP_RANK", FLAGS_node_rank);
SetEnvInt("ROLE_RANK", global_proc_rank);
SetEnvInt("ROLE_WORLD_SIZE", proc_world_size);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这几个好像没用到?可以先删掉

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
} else if (exit_code == 0) {
exit_code = 1;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这块退出,好像也没有做某个子进程异常退出的时候清理其他进程的逻辑?如果 exit code 非 0 的话感觉正常情况应该要把所有其他正在运行的子进程都清理完毕再返回

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

修改逻辑为:跟踪所有运行中的子进程;任一子进程异常退出或 fork 失败时,向其余进程发送 SIGTERM,继续回收全部子进程后返回首个失败码。

Comment thread tools/infini_run/infini_run.cc Outdated
int proc_world_size = FLAGS_nnodes * FLAGS_nproc_per_node;
std::string master_addr = FLAGS_rdzv_endpoint.substr(0, FLAGS_rdzv_endpoint.find(':'));
std::string master_port = FLAGS_rdzv_endpoint.substr(FLAGS_rdzv_endpoint.find(':') + 1);
const std::string run_id = FLAGS_nnodes == 1 ? GenerateLocalRunId() : "";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这块多机还是会使用原先的默认命名,没达到效果,可能得看下怎么改。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

修改:多机必须通过 --rdzv_id 指定;单机未指定时仍自动生成。参考https://docs.pytorch.org/docs/2.13/elastic/run.html

Add a dedicated 8_proc test group containing the 8-process variants of
the original basic multi-GPU cases.
Track DataLoader progress by global batches so distributed ranks slice data
consistently and can resume/cycle from saved consumption counts.

Also scope CCL unique ID files per run, generate NCCL IDs only on the main
rank, clean up run-local rendezvous files, and add DataLoader coverage.
- derive parallel state from the global world size
- clarify global rank and per-node process semantics
- add multi-node rank regression coverage
- restore the NCCL-compatible GetUniqueId interface
- add torchrun-style --rdzv_id support
- use the shared ID to isolate CCL unique-ID files
- preserve automatic run ID generation for single-node runs
- document rdzv_id in the multi-node example
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants