FORM NOT VOID, MIND NO CORE

Appendix

2026.08.10

Appendix A: Hands-On Manual

The brilliance of theory ultimately demands the confirmation of practice. This appendix provides you with an end-to-end, hands-on experimental guide, translating the core concepts explored in the main text -- from low-level driver installation to high-level scheduling, inference, and monitoring -- into executable commands and runnable code for your local environment.

We understand that in the complex domain of AI infrastructure, environmental variability is the greatest challenge. This manual is therefore designed with an emphasis on simplifying dependencies, clarifying prerequisites, and providing detailed annotations for every critical step. We encourage you not simply to "copy-paste" your way through the experiments, but to reflect on the principles behind each step and connect them with the knowledge points in the main text.

Ready your terminal, and let us begin this ultimate exercise of "linking theory with practice."

Environment Preparation Script: Rapid Experiment Environment Setup with Terraform/Ansible

In real production environments, we use Terraform to automate the creation of cloud resources (VPCs, virtual machines, load balancers) and then Ansible to perform fine-grained configuration on those VMs (installing drivers, configuring software). This is a complex but powerful Infrastructure as Code (IaC) workflow.

Because complete IaC scripts are tightly coupled to specific cloud providers (AWS, Azure, GCP, Alibaba Cloud, etc.) and your account configuration, providing a universal script that runs on any cloud is impractical. This section therefore provides a conceptual, templated Ansible Playbook designed to illustrate the core logic of automated configuration. Use it as a starting point and adapt it to your own environment.

For local experiments, we recommend using a physical or virtual machine running Linux (e.g., Ubuntu 22.04) with an NVIDIA GPU or access to an Ascend card.

Ansible Playbook Template (for configuring GPU nodes)

This Playbook demonstrates the automated installation of Docker, NVIDIA drivers, the NVIDIA Container Toolkit, and lightweight K8s (k3s) on one or more fresh Ubuntu nodes.

Prerequisites:

  1. You have a control machine with Ansible installed (pip install ansible).
  2. You have one or more target GPU nodes that the control machine can access via SSH without a password.
  3. You have configured Ansible's inventory file (e.g., /etc/ansible/hosts) on the control machine, defining your GPU node group.
[gpu_nodes]
192.168.1.101
192.168.1.102

Playbook file (setup_gpu_node.yml):

---
- hosts: gpu_nodes
  become: yes
  vars:
    nvidia_driver_version: "535"

  tasks:
    - name: 1. Update APT cache and install prerequisite
      apt:
        update_cache: yes
        name: ['apt-transport-https', 'ca-certificates', 'curl', 'gnupg-agent', 'software-properties-common']
        state: present

    - name: 2. Add Docker's official GPG key
      apt_key:
        url: https://download.docker.com/linux/ubuntu/gpg
        state: present

    - name: 3. Add Docker repository
      apt_repository:
        repo: deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable
        state: present

    - name: 4. Install Docker Engine
      apt:
        name: ['docker-ce', 'docker-ce-cli', 'containerd.io']
        state: present

    - name: 5. Add NVIDIA driver repository
      apt_repository:
        repo: ppa:graphics-drivers/ppa
        state: present

    - name: 6. Install NVIDIA Driver
      apt:
        name: "nvidia-driver-{{ nvidia_driver_version }}"
        state: present
      register: driver_install
      notify: Reboot node

    - name: 7. Add NVIDIA Container Toolkit repository
      shell: |
        curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
        curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
        sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
        tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

    - name: 8. Install NVIDIA Container Toolkit
      apt:
        update_cache: yes
        name: nvidia-container-toolkit
        state: present

    - name: 9. Configure Docker to use NVIDIA runtime and restart
      shell: |
        nvidia-ctk runtime configure --runtime=docker
        systemctl restart docker

    - name: 10. Install k3s (Lightweight Kubernetes)
      shell: |
        curl -sfL https://get.k3s.io | sh -
        mkdir -p $HOME/.kube
        cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config
        chown $(id -u):$(id -g) $HOME/.kube/config
      args:
        creates: /usr/local/bin/k3s

  handlers:
    - name: Reboot node
      reboot:
        msg: "Rebooting node after NVIDIA driver installation"
        connect_timeout: 5
        reboot_timeout: 300
        pre_reboot_delay: 0
        post_reboot_delay: 30
        test_command: whoami

How to Run:

Execute on your control machine: ansible-playbook -i /etc/ansible/hosts setup_gpu_node.yml

This Playbook automatically completes the standardized configuration of all nodes, laying a solid foundation for subsequent K8s experiments.

Lab 1 - Basic Environment: Step-by-Step Installation of Ascend Drivers and the CANN Software Stack

This lab guides you through the most basic and critical software stack installation on a server equipped with a Huawei Ascend AI processor.

Prerequisites:

  • The server is running a supported operating system (e.g., EulerOS or the specified Ubuntu version).
  • You have root or sudo access to the server.
  • You have downloaded the AIA-Ascend-Driver-*.run and AIA-Ascend-Toolkit-*.run files matching your hardware model and OS version from the Huawei official website or a mirror source.

Steps:

Step 1: Check hardware and environment

Before installation, confirm that the system recognizes the Ascend device.

lspci | grep -i ascend

You should see output similar to Processing accelerators: Huawei Technologies Co., Ltd. Ascend 910 AI Processor.

Step 2: Install the driver

The driver serves as the bridge between the operating system kernel and the NPU hardware.

# Grant execute permission
chmod +x AIA-Ascend-Driver-*.run

# Execute installation with root privileges
sudo ./AIA-Ascend-Driver-*.run --install

During installation, read the prompts carefully. After installation, a server reboot is typically required to load the new kernel modules.

sudo reboot

Step 3: Install the CANN toolkit

CANN (Compute Architecture for Neural Networks) is Ascend's application enablement software stack, comprising compilers, acceleration libraries, toolchains, and more.

# Grant execute permission
chmod +x AIA-Ascend-Toolkit-*.run

# Execute installation with root privileges
# --install-path specifies the installation path, --install-for-all installs for all users
sudo ./AIA-Ascend-Toolkit-*.run --install --install-path=/usr/local/ascend --install-for-all

Step 4: Configure environment variables

To allow the system to locate CANN commands and libraries, add the relevant paths to your environment variables. The CANN installation package conveniently provides a script for this purpose. Add the following lines to your ~/.bashrc or the system's /etc/profile:

# Edit .bashrc file
vim ~/.bashrc

# Add the following line at the end of the file (modify the path according to your actual installation path)
source /usr/local/ascend/ascend-toolkit/set_env.sh

# Make the configuration effective immediately
source ~/.bashrc

Step 5: Verify the installation

This is the most critical step -- confirming that our installation was successful.

# Execute the npu-smi command
npu-smi info

If the installation is successful, you will see output similar to the following, listing detailed information about all NPU cards on the server, including model, ID, temperature, power consumption, and HBM usage.

+-------------------------------------------------------------------------------------------+
| npu-smi 21.0.2                  Version: 21.0.2                                           |
+-------------------------------+-----------------+-----------------------------------------+
| NPU     Name                  | Health          | Power(W)          Temp(C)               |
| Chip    Device-Chip-Id        | Bus-Id          | AICore(%)         HBM(MB)               |
+===============================+=================+=========================================+
| 0       Ascend 910B           | OK              | 110.0             45                    |
| 0       0-0                   | 0000:C1:00.0    | 0                 0 / 32768             |
+-------------------------------+-----------------+-----------------------------------------+
| 1       Ascend 910B           | OK              | 108.0             44                    |
| 0       1-0                   | 0000:C2:00.0    | 0                 0 / 32768             |
+-------------------------------+-----------------+-----------------------------------------+
... (other NPU cards)

Seeing this interface, congratulations -- you have built the basic software runtime environment for the Ascend AI processor!

Lab 2 - Scheduling in Practice: Configuring Volcano in K8s and Submitting a Distributed PyTorch Job

This lab walks you through the core content of Chapter 5: using the Volcano scheduler to resolve the distributed training deadlock problem that native K8s cannot handle.

Prerequisites:

  • You have a functional K8s cluster with GPU/NPU support already configured on the nodes (i.e., Device Plugin is installed).
  • You have the Helm client installed.

Step 1: Install Volcano

Use Helm for one-click installation of Volcano.

helm repo add volcano-sh https://volcano-sh.github.io/charts
helm repo update
helm install volcano volcano-sh/volcano -n volcano-system --create-namespace

Verify installation:

kubectl get pods -n volcano-system

You should see Pods such as volcano-scheduler and volcano-controller in Running state.

Step 2: Prepare the PyTorch distributed training application

We will use a classic PyTorch MNIST distributed training script.

File (mnist_distributed.py):

import torch
import torch.distributed as dist
import torch.nn as nn
import torch.optim as optim
from torch.nn.parallel import DistributedDataParallel as DDP
from torchvision import datasets, transforms
import os

def setup(rank, world_size):
    os.environ['MASTER_ADDR'] = os.environ.get('MASTER_ADDR', 'localhost')
    os.environ['MASTER_PORT'] = os.environ.get('MASTER_PORT', '12355')
    dist.init_process_group("nccl", rank=rank, world_size=world_size)

def cleanup():
    dist.destroy_process_group()

class Net(nn.Module):
    # ... (a simple CNN model definition)
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)
    def forward(self, x):
        x = self.conv1(x)
        x = torch.relu(x)
        x = self.conv2(x)
        x = torch.relu(x)
        x = torch.max_pool2d(x, 2)
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        x = torch.relu(x)
        x = self.fc2(x)
        return torch.log_softmax(x, dim=1)

def train(rank, world_size):
    setup(rank, world_size)
  
    device = torch.device(f"cuda:{rank % torch.cuda.device_count()}")
  
    transform = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.1307,), (0.3081,))
    ])
    dataset = datasets.MNIST('../data', train=True, download=True, transform=transform)
    train_sampler = torch.utils.data.distributed.DistributedSampler(dataset, num_replicas=world_size, rank=rank)
    train_loader = torch.utils.data.DataLoader(dataset, batch_size=64, sampler=train_sampler)

    model = Net().to(device)
    ddp_model = DDP(model, device_ids=[device])

    optimizer = optim.SGD(ddp_model.parameters(), lr=0.01)

    for epoch in range(3):
        train_sampler.set_epoch(epoch)
        for batch_idx, (data, target) in enumerate(train_loader):
            data, target = data.to(device), target.to(device)
            optimizer.zero_grad()
            output = ddp_model(data)
            loss = nn.functional.nll_loss(output, target)
            loss.backward()
            optimizer.step()
            if batch_idx % 10 == 0:
                print(f"Rank {rank}, Epoch {epoch}, Batch {batch_idx}, Loss: {loss.item()}")
  
    cleanup()

if __name__ == '__main__':
    # Volcano injects VC_TASK_INDEX and VC_WORKER_NUM environment variables
    rank = int(os.environ.get("VC_TASK_INDEX", "0"))
    world_size = int(os.environ.get("VC_WORKER_NUM", "1"))
    print(f"Starting training on Rank {rank} of {world_size}...")
    train(rank, world_size)

Step 3: Build the Docker image

File (Dockerfile):

FROM pytorch/pytorch:2.1.0-cuda12.1-cudnn8-runtime

WORKDIR /app

COPY mnist_distributed.py .

# Download dataset to avoid downloading at runtime
RUN python -c "from torchvision import datasets; datasets.MNIST('../data', download=True)"

CMD ["python", "mnist_distributed.py"]

Build and push to your image registry:

docker build -t your-registry/pytorch-dist-mnist:v1 .
docker push your-registry/pytorch-dist-mnist:v1

Step 4: Write and submit a VolcanoJob

This is the core step. We define a distributed job requiring 2 Pods (each with 1 GPU).

File (volcano_pytorch_job.yml):

apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
  name: pytorch-mnist-dist-job
spec:
  schedulerName: volcano
  minAvailable: 2 # Core: Gang Scheduling, must assemble 2 Pods before starting
  queue: default
  tasks:
    - name: worker
      replicas: 2
      template:
        spec:
          containers:
            - name: pytorch-worker
              image: your-registry/pytorch-dist-mnist:v1
              resources:
                limits:
                  nvidia.com/gpu: 1 # Each Pod requests 1 GPU
          restartPolicy: OnFailure

Submit the job:

kubectl apply -f volcano_pytorch_job.yml

Step 5: Observe and verify

# View PodGroup status -- the core object of Volcano scheduling
kubectl get podgroup

# View Pod status -- you will see both Pods created and entering Running state almost simultaneously
kubectl get pods -l volcanosh.dev/job-name=pytorch-mnist-dist-job

# View logs of one Pod
kubectl logs pytorch-mnist-dist-job-worker-0

In the logs, you will see training output from different ranks (Rank 0 and Rank 1) interleaved, confirming that distributed training has been successfully established and is running!

Lab 3 - Stress Testing in Practice: Deploying a vLLM Service, Simulating 100 Concurrent Requests, and Generating a Performance Report

This lab guides you through the inference service deployment and stress testing covered in Chapter 8.

Prerequisites:

  • One or more machines with NVIDIA GPUs, with drivers and Docker already installed.
  • Python environment installed.

Step 1: Deploy the vLLM service

We will use the simplest method -- vLLM's official Docker image -- to deploy a Llama 3 8B Instruct model service.

# Pull the vLLM image
docker pull vllm/vllm-openai:latest

# Start the service
# Note: This requires a good network connection to download the model, which will be cached at ~/.cache/huggingface
docker run --gpus all -d \
  -p 8000:8000 \
  -v ~/.cache/huggingface:/root/.cache/huggingface \
  --name vllm_server \
  vllm/vllm-openai:latest \
  --model meta-llama/Meta-Llama-3-8B-Instruct

Note: The Llama 3 model requires access authorization from Hugging Face. Ensure you are logged into HF and have accepted its terms of use.

Step 2: Verify the service

Use curl to test whether the service is working correctly.

curl http://localhost:8000/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "meta-llama/Meta-Llama-3-8B-Instruct",
        "messages": [
            {"role": "user", "content": "Hello! What is your name?"}
        ]
    }'

If the model responds, the service deployment is successful.

Step 3: Prepare the Locust stress test script

Install Locust: pip install locust

File (locustfile.py): (Referencing the script from Section 8.3, we provide a simplified non-streaming version for quick onboarding)

from locust import task, HttpUser
import random

class LLMUser(HttpUser):
    @task
    def generate(self):
        prompts = ["What is the capital of France?", "Write a short poem about the sea.", "Explain black holes to a 5-year-old."]
        payload = {
            "model": "meta-llama/Meta-Llama-3-8B-Instruct",
            "messages": [{"role": "user", "content": random.choice(prompts)}],
            "max_tokens": 100
        }
        self.client.post("/v1/chat/completions", json=payload, name="/v1/chat/completions")

Step 4: Start the stress test

locust -f locustfile.py --host http://localhost:8000

Step 5: Analyze the performance report

  1. Open a browser and navigate to http://localhost:8089.
  2. Enter Total users as 100, Spawn rate as 10.
  3. Click "Start swarming."
  4. Observe the "Charts" tab:
    • Total Requests per Second (RPS): The number of requests your service completes per second.
    • Response Time (ms): The distribution of response times, focusing on the 95th and 99th percentile values. These represent the experience of the vast majority of users.
  5. Generate report: In the "Download Data" tab, you can download a detailed CSV report for offline analysis and archiving.

By adjusting the number of concurrent users, you can identify the service's "performance inflection point" -- the concurrency level at which response times begin to degrade sharply. This provides critical data for capacity planning.

Lab 4 - Monitoring and Alerting: Configuring Prometheus Rules to Trigger Alerts When GPU Temperature Exceeds 80 C or Memory Usage Exceeds 95%

This lab guides you through the observability content from Chapter 9, configuring core hardware alerts for your GPU cluster.

Prerequisites:

  • A K8s cluster with Prometheus Operator deployed (typically installed via the kube-prometheus-stack Helm chart).
  • DCGM-Exporter is deployed on the GPU nodes in the cluster.

Step 1: Understand the PrometheusRule CRD

In the Prometheus Operator ecosystem, alert rules are defined through a Kubernetes custom resource called PrometheusRule. We will create a YAML file to define our rules.

Step 2: Write the alert rule YAML file

File (gpu-alerts.yml):

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: gpu-alerts
  labels:
    # This label must match the ruleSelector of your Prometheus instance
    prometheus: kube-prometheus 
    role: alert-rules
spec:
  groups:
    - name: gpu.rules
      rules:
        - alert: GPUTemperatureHigh
          expr: DCGM_FI_DEV_GPU_TEMP > 80
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "GPU high temperature on {{ $labels.nodename }}"
            description: "GPU {{ $labels.gpu }} on node {{ $labels.nodename }} has been over 80 C for 5 minutes. Current value is {{ $value }} C."

        - alert: GPUMemoryHigh
          expr: (DCGM_FI_DEV_FB_USED / DCGM_FI_DEV_FB_TOTAL) * 100 > 95
          for: 10m
          labels:
            severity: critical
          annotations:
            summary: "GPU high memory usage on {{ $labels.nodename }}"
            description: "GPU {{ $labels.gpu }} on node {{ $labels.nodename }} memory usage has been over 95% for 10 minutes. Current usage is {{ $value | printf `%.2f` }}%."

        - alert: GPUXidErrorDetected
          expr: rate(DCGM_FI_DEV_XID_ERRORS[5m]) > 0
          for: 1m
          labels:
            severity: critical
          annotations:
            summary: "GPU XID Error Detected on {{ $labels.nodename }}"
            description: "GPU {{ $labels.gpu }} on node {{ $labels.nodename }} is reporting XID errors. This may indicate a software or hardware issue. Please investigate dmesg logs."

Annotations:

  • expr: The PromQL query expression, defining the trigger condition for the alert.
  • for: The duration the condition must hold true, preventing false positives from transient fluctuations.
  • labels.severity: Defines the alert severity level, enabling differentiated routing in Alertmanager.
  • annotations: Defines the detailed alert information. {{ $labels... }} and {{ $value }} are template variables that will be replaced with actual values in the alert notification.

Step 3: Apply the rules and verify

# Apply the rules to your K8s cluster (typically in the monitoring namespace)
kubectl apply -f gpu-alerts.yml -n monitoring

After a few minutes, Prometheus will load these new rules.

  1. Open the Prometheus UI (via kubectl port-forward).
  2. Navigate to the "Alerts" page. You should see the three newly added rules -- GPUTemperatureHigh, GPUMemoryHigh, GPUXidErrorDetected -- in Inactive state.

Step 4: Simulate triggering alerts (optional but recommended)

To verify that the alert path is functional, we need to artificially trigger the conditions.

  • Trigger temperature alert: On a GPU node, run a high-intensity GPU stress testing tool such as gpu-burn.
# Run on a GPU node
docker run --rm --gpus all -it wshuyi/gpu-burn -t 600 # Run for 10 minutes

Simultaneously, observe nvidia-smi in another terminal. When the temperature exceeds 80 C and persists for 5 minutes, the alert state in Prometheus will change to Pending, then Firing.

  • Trigger memory alert: Write a simple PyTorch script that allocates a large tensor.

Step 5: View the alert

When the alert enters Firing state, if you have configured Alertmanager, you will receive a formatted alert message in your configured notification channel (e.g., Slack, DingTalk), containing the details you defined in annotations.

At this point, you have successfully installed the most basic "automatic alarm system" for your AI infrastructure!

Appendix B: Efficiency Toolbox

In the grand engineering endeavor of AI infrastructure, we need not only systematic knowledge and deep insight, but also a set of "sharp tools" that can rapidly translate this wisdom into action. Just as excellent programmers do not reinvent the wheel, experienced AI Infra engineers should be adept at automating and tooling repetitive work.

This appendix provides you with an "Efficiency Toolbox" containing two carefully crafted tools. The first is the "Intelligent Computing Center Compute Resource Planning Calculator," which encapsulates the complex mathematical formulas from Chapter 7 into an easy-to-use Excel spreadsheet, allowing you to complete a cluster planning estimation worth hundreds of millions of yuan in seconds. The second is a Python operations script library, offering a series of plug-and-play scripts to help you perform daily tasks such as one-click cluster health inspections and quick compute demand calculations.

These tools are your accelerators for transforming from a "theorist" into a "practitioner." Keep them in your arsenal, continuously refine and expand them in your daily work, and make them the sharpest and most capable part of your personal knowledge system.

The "Intelligent Computing Center Compute Resource Planning Calculator.xlsx"

This Excel calculator transforms the memory usage and training time estimation models from Chapter 7 into an interactive, visual planning tool. Simply fill in the model's key parameters and your business objectives in the "Input" area, and it will automatically calculate the required resource scale and related performance metrics in the "Output" area.

Calculator Structure Design

We designed this Excel file to contain two main worksheets: Training_Estimator (Training Resource Estimator) and Inference_Memory_Estimator (Inference Memory Estimator).

Sheet 1: Training_Estimator

This worksheet is the core of the calculator, used for resource planning of pre-training or full fine-tuning.

[Input Area] - Yellow background cells

A. Model Parameters

Parameter NameSymbolExample ValueUnitNotes
Model ParametersP70B (Billions)e.g., for Llama 2 70B, enter 70
Number of LayersL80
Hidden Dimensionh8192
Number of Attention Headsa64
Sequence Lengths4096Tokens

B. Data & Goals

Parameter NameSymbolExample ValueUnitNotes
Training Data SizeD2T (Trillions)Tokens
Target Training DaysDays90Days

C. Hardware & Parallelism

Parameter NameSymbolExample ValueUnitNotes
GPU Model-A100-80G(Dropdown menu selection)
Single Card Peak ComputePeak312TFLOPS (FP16)(Auto-filled based on GPU model)
Single Card Memory CapacityMem_GPU80GB(Auto-filled based on GPU model)
Data Parallel SizeDP64
Tensor Parallel SizeTP8
Pipeline Parallel SizePP8
Global Batch SizeGBS1024
MFU (Model FLOPs Utilization)MFU40%%The most critical empirical value

[Output Area] - Green background cells

A. Training Time & Compute Requirements

Metric NameFormula (Excel Expression)ResultUnit
Total Compute (FLOPs)=6 * P * 10^9 * D * 10^128.40E+23FLOPs
Required Total Effective Compute=A2 / (Days * 24 * 3600)1.08E+17FLOPS
=B2 / 10^12107,527TFLOPS (Effective)
Required Total GPUs=B3 / (Peak * MFU)862Cards
Recommended Cluster Size=ROUNDUP(B4, -2)900Cards
Actual Estimated Training Days=(A2 / (B5 * Peak * MFU * 10^12)) / (24*3600)86.4Days

B. Memory Analysis - Based on ZeRO-1 + TP + PP

Metric NameFormula (Excel Expression)ResultUnit
Model Parameters (per GPU)=2 * P / TP17.5GB
Optimizer States (per GPU)=12 * P / (DP * TP)1.64GB
Gradient Footprint (per GPU)=4 * P / (DP * TP)0.55GB
Activation Footprint per GPU (simplified estimate; actual usage depends strongly on activation recomputation and related strategies)=(34 * s * (GBS/DP) * h * L) / (TP * 10^9)19.3GB
Estimated Peak Memory (per GPU)=SUM(B8:B11)39.0GB
Memory Sufficient?=IF(B12 <= Mem_GPU, "Yes", "No! Exceeded!")Yes

C. Network Bandwidth Requirement

Metric NameFormula (Excel Expression)ResultUnit
All-Reduce Communication Volume (DP; simplified per-iteration estimate)= (2 * P * 10^9 * 2) / (TP * (DP-1)/DP)8.75GB
All-Gather/Reduce-Scatter (TP)= (2 * P * 10^9 * 2 * (TP-1)/TP) / (TP * PP)0.05GB
P2P Bandwidth (PP)=(s * (GBS/DP) * h * 2 * 2) / (TP * PP)0.01GB
Aggregated Average Bandwidth per GPU (total communication volume per iteration divided by estimated iteration time)= (B14+B15+B16) * 8 / 10^9 * (1/ (A2/(B5*Peak*MFU*10^12)) )~21Gbps

These network results are for first-pass capacity planning, not link acceptance. Actual requirements vary materially with communication-compute overlap, topology, congestion, protocol overhead, and the collective-communication implementation.

Instructions:

  1. First, fill in your model, data, and target parameters in the [Input Area].
  2. Adjust the DP, TP, PP parameters in [Hardware & Parallelism].
  3. Observe the "Required Total GPUs" and "Memory Sufficient?" in the [Output Area].
  4. Your goal is: under the condition that "Memory is Sufficient," find a combination of DP, TP, PP where the "Recommended Cluster Size" is within your budget and the "Actual Estimated Training Days" meets your timeline.
  5. Continuously adjust DP, TP, PP and MFU (if you are confident in your cluster optimization, you can increase MFU), performing "What-If" analysis to find the optimal resource configuration.

Python Operations Script Library

This script library provides a series of ready-to-use operations tools to help you automate daily inspection and calculation tasks.

check_cluster_health.py: One-Click Cluster Health Inspection

This script uses the Kubernetes Python client to discover all nodes, then SSH into each node to execute nvidia-smi or npu-smi, parse the output, and generate a concise health report.

Prerequisites:

  • Install Python libraries: pip install kubernetes paramiko pandas
  • Your machine has ~/.kube/config configured to access the target K8s cluster.
  • Your machine can SSH passwordlessly into all nodes in the cluster.

Script (check_cluster_health.py):

import argparse
import paramiko
import pandas as pd
from kubernetes import client, config
from datetime import datetime

def ssh_run_command(hostname, command):
    """Execute command on a remote node via SSH and return output."""
    try:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(hostname, username='root', timeout=5) # Modify username as needed
        stdin, stdout, stderr = ssh.exec_command(command)
        output = stdout.read().decode('utf-8')
        error = stderr.read().decode('utf-8')
        ssh.close()
        if error and "command not found" not in error:
            return f"ERROR: {error}"
        return output
    except Exception as e:
        return f"SSH_ERROR: {str(e)}"

def parse_nvidia_smi(output):
    """Parse nvidia-smi output and extract key health metrics."""
    if "NVIDIA-SMI has failed" in output or "ERROR" in output:
        return [{"gpu_id": "ALL", "health": "FAIL", "message": output}]
  
    devices = []
    lines = output.split('\n')
    # Very simplified parsing; in production, use nvidia-smi --query-gpu=... --format=csv
    for i, line in enumerate(lines):
        if "MiB" in line and "%" in line:
            parts = line.split()
            gpu_id = parts[1]
            temp = parts[3]
            power = parts[5]
            mem_used = parts[9]
            mem_total = parts[11]
            gpu_util = parts[13]
          
            health = "OK"
            message = []
            if int(temp.replace('C','')) > 85:
                health = "WARN"
                message.append(f"Temp>85C({temp})")
            if int(power.replace('W','')) > 350: # Assuming power threshold of 350W
                health = "WARN"
                message.append(f"Power>350W({power})")

            devices.append({
                "gpu_id": gpu_id,
                "health": health if message else "OK",
                "message": ", ".join(message) if message else "N/A"
            })
    return devices

def get_k8s_nodes(label_selector=""):
    """Get the list of nodes from the K8s cluster matching the label selector."""
    config.load_kube_config()
    v1 = client.CoreV1Api()
    nodes = v1.list_node(label_selector=label_selector)
    return [node.status.addresses[0].address for node in nodes.items]

def main():
    parser = argparse.ArgumentParser(description="Cluster Health Checker")
    parser.add_argument("--vendor", type=str, default="nvidia", choices=["nvidia", "ascend"], help="GPU/NPU vendor")
    parser.add_argument("--nodes", type=str, help="Comma-separated list of node IPs. Overrides k8s discovery.")
    parser.add_argument("--label", type=str, default="nvidia.com/gpu=true", help="K8s node label selector for discovery.")
    args = parser.parse_args()

    if args.nodes:
        nodes_to_check = args.nodes.split(',')
    else:
        print(f"Discovering nodes with label '{args.label}' from Kubernetes...")
        nodes_to_check = get_k8s_nodes(args.label)
        print(f"Found {len(nodes_to_check)} nodes: {nodes_to_check}")

    if args.vendor == "nvidia":
        command = "nvidia-smi"
        parser_func = parse_nvidia_smi
    elif args.vendor == "ascend":
        command = "npu-smi info"
        # You would need to write a similar parsing function for npu-smi
        # parser_func = parse_npu_smi 
        print("Ascend NPU parser not implemented in this example.")
        return

    results = []
    for node in nodes_to_check:
        print(f"Checking node: {node} ...")
        output = ssh_run_command(node, command)
        health_info = parser_func(output)
        for device in health_info:
            results.append({
                "node": node,
                "device_type": args.vendor.upper(),
                "device_id": device["gpu_id"],
                "health": device["health"],
                "message": device["message"],
            })
  
    report_df = pd.DataFrame(results)
  
    print("\n" + "="*50)
    print(f"  Cluster Health Report - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print("="*50)
    print(report_df.to_string())

    # Print problem summary
    failed_nodes = report_df[report_df['health'] != 'OK']
    if not failed_nodes.empty:
        print("\n" + "!"*20 + "  PROBLEM SUMMARY  " + "!"*20)
        print(failed_nodes.to_string())
        print("!"*59)
    else:
        print("\n" + "="*10 + "  All checks passed! Cluster is healthy. " + "="*10)

if __name__ == "__main__":
    main()

How to Use:

  1. Inspect all K8s nodes with the nvidia.com/gpu=true label: python check_cluster_health.py
  2. Specify nodes for inspection: python check_cluster_health.py --nodes 192.168.1.101,192.168.1.102

This script outputs a clear table indicating whether each card on each node is healthy, and if not, the likely reason (e.g., high temperature). This is very useful for daily inspections and preliminary fault diagnosis.

calc_model_flops.py: Quickly Calculate Theoretical Model FLOPs

This script encapsulates the 6PD formula from Chapter 7 into a simple command-line tool, helping you quickly estimate the total compute required to train a model and the time required on a specific cluster.

Script (calc_model_flops.py):

import argparse

def sizeof_fmt(num, suffix=""):
    for unit in ["", "K", "M", "G", "T", "P", "E", "Z"]:
        if abs(num) < 1000.0:
            return f"{num:3.1f}{unit}{suffix}"
        num /= 1000.0
    return f"{num:.1f}Y{suffix}"

def main():
    parser = argparse.ArgumentParser(description="Estimate LLM Training FLOPs and Time")
  
    # Model and Data parameters
    parser.add_argument("-p", "--params", type=float, required=True, help="Model parameters in billions (e.g., 70 for 70B)")
    parser.add_argument("-d", "--data_tokens", type=float, required=True, help="Training data size in trillions of tokens (e.g., 2 for 2T)")
  
    # Hardware and Performance parameters
    parser.add_argument("-n", "--num_gpus", type=int, required=True, help="Number of GPUs in the cluster")
    parser.add_argument("--peak_tflops", type=float, required=True, help="Peak TFLOPS of a single GPU at target precision (e.g., 312 for A100 FP16)")
    parser.add_argument("--mfu", type=float, default=0.4, help="Model FLOPs Utilization (MFU), a value between 0 and 1 (default: 0.4)")
  
    args = parser.parse_args()

    # --- Calculations ---
  
    # 1. Total FLOPs
    total_flops = 6 * (args.params * 1e9) * (args.data_tokens * 1e12)
  
    # 2. Cluster effective throughput
    single_gpu_effective_tflops = args.peak_tflops * args.mfu
    cluster_effective_tflops = single_gpu_effective_tflops * args.num_gpus
  
    # 3. Estimated training time
    if cluster_effective_tflops == 0:
        estimated_seconds = float('inf')
    else:
        estimated_seconds = total_flops / (cluster_effective_tflops * 1e12)
  
    estimated_days = estimated_seconds / (24 * 3600)

    # --- Print Report ---
  
    print("\n" + "="*50)
    print("  LLM Training Estimation Report")
    print("="*50)
  
    print("\n[Input Parameters]")
    print(f"  - Model Size: {args.params}B parameters")
    print(f"  - Dataset Size: {args.data_tokens}T tokens")
    print(f"  - Cluster Size: {args.num_gpus} GPUs")
    print(f"  - Single GPU Peak Performance: {args.peak_tflops} TFLOPS")
    print(f"  - Assumed MFU: {args.mfu:.2%}")
  
    print("\n[Estimated Requirements]")
    print(f"  - Total Training FLOPs: {sizeof_fmt(total_flops, 'FLOPs')}")
    print(f"  - Cluster Effective Throughput: {cluster_effective_tflops:,.2f} TFLOPS")
  
    print("\n[Final Estimation]")
    print(f"  - Estimated Training Time: {estimated_days:.2f} days")
    print("="*50)
  
    print("\nNote: This is a theoretical estimation. Actual time may vary based on network, storage, and software stack efficiency.")

if __name__ == "__main__":
    main()

How to Use:

Suppose you want to estimate the time required to train a 70B model with 2T tokens on a cluster of 1024 A100s (FP16 peak 312 TFLOPS), assuming an MFU of 40%:

python calc_model_flops.py \
  --params 70 \
  --data_tokens 2 \
  --num_gpus 1024 \
  --peak_tflops 312 \
  --mfu 0.4

Output:

==================================================
  LLM Training Estimation Report
==================================================

[Input Parameters]
  - Model Size: 70.0B parameters
  - Dataset Size: 2.0T tokens
  - Cluster Size: 1024 GPUs
  - Single GPU Peak Performance: 312.0 TFLOPS
  - Assumed MFU: 40.00%

[Estimated Requirements]
  - Total Training FLOPs: 840.0EFLOPs
  - Cluster Effective Throughput: 127,795.20 TFLOPS

[Final Estimation]
  - Estimated Training Time: 76.08 days
==================================================

Note: This is a theoretical estimation. Actual time may vary based on network, storage, and software stack efficiency.

This script provides a fast, convenient way to verify the plans you developed in the Excel calculator, or to quickly produce order-of-magnitude estimates for compute needs in daily discussions.

Closing Words

This Efficiency Toolbox is your catalyst for transforming theoretical knowledge into productive power. These tools are not perfect, but they provide a solid starting point. The real value lies in how you continuously refine, extend, and customize them based on your team's specific needs. Let them grow with you, becoming the indispensable "right-hand tools" of a top-tier AI Infra engineer.