Tamil Newsஞாயிறு, 15 நவம்பர் 2026
சமீபத்தியம்
நாடு மீண்டும் வங்குரோத்து (bankruptcy) நிலையை நோக்கி நகர்வதாக முன்னாள் அமைச்சர் ராஜித சேனாரத்ன (Rajitha Senaratne) எச்சரிக்கைதம்புட்டேகமயில் (Thambuttegama) நிவாரணம் தேவைப்படும் குடும்பம் ஒன்றுக்கு வீடு: முன்னாள் ஜனாதிபதி சந்திரிகா பண்டாரநாயக்க குமாரதுங்க (Chandrika Bandaranaike Kumaratunga) சொந்த நிதியில் நிர்மாணம்புதுப்பிப்பு (Updated): புற்றுநோய் கதிர்வீச்சுச் சிகிச்சை (radiotherapy): ஐந்து வைத்தியசாலைகளுக்கான கருவிக் கொள்வனவு தாமதம் குறித்து மருத்துவர் எச்சரிக்கைபுதுப்பிப்பு (Updated): கங்குவா (Kanguva) பின்னடைவுக்குப் பிறகு சூர்யா (Suriya): மூன்றாவது ரூ.200 கோடி வசூலை (box office) நோக்கி சீன் (Scene)பாகிஸ்தான் (Pakistan) தார்பேலா (Tarbela) நீர்மின் திட்டத்தில் (hydropower project) தடுப்புச் சுவர் இடிந்ததாகத் தகவல்இலங்கைச் (Sri Lanka) சுற்றுலாவை (tourism) மேம்படுத்த சர்வதேச ஒலிபரப்பு நிறுவனங்கள் (broadcasting organisations) விருப்பம்: அமைச்சர் (Minister)நொச்சியாகமவில் (Nochchiyagama) கொலைக்கு உதவிய குற்றச்சாட்டில் 38 வயது நபர் கைதுசிங்கராஜ காட்டில் (Sinharaja Forest) அரிய பூச்சி, ஊர்வன இனங்களைச் சேகரித்த குற்றச்சாட்டில் நான்கு சீன நாட்டவர் (Chinese nationals) கைது

உருவாக்கப்பட்ட Triton குறியீடு, GEMM எடுத்துக்காட்டுகள் மற்றும் ROCm warp-size பிரச்சினைகள்

வரலாற்றுக் கால Linux PC கணினிக் குழுவின் விளக்கப் படம்; நவீன GPU கணினிக் குழு அல்ல.

வரலாற்றுக் கால Linux PC கணினிக் குழுவின் விளக்கப் படம்; நவீன GPU கணினிக் குழு அல்ல.

இந்த மூன்று நடைமுறை வழிமுறைகளை ஆராய்வது, அதாவது torch.compile-ஆல் உருவாக்கப்பட்ட Triton குறியீட்டை பரிசீலிப்பது, tile செய்யப்பட்ட மாத்திரைப் பெருக்கல் (matrix multiplication, GEMM) குறியீட்டை ஒப்பிடுவது, மற்றும் CUDA-ஐ AMD ROCm-க்கு மாற்றும்போது எழும் warp-size பிரச்சினைகளைக் கையாள்வது, உயர்மட்ட AI framework-கள் எவ்வாறு நேரடியாக hardware அறிவுறுத்தல்களாக மொழிபெயர்க்கப்படுகின்றன என்பதை விளக்குகிறது.

1. torch.compile ஆல் உருவாக்கப்பட்ட Triton குறியீட்டைப் பரிசீலித்தல்

RMSNorm (x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + eps) * weight) போன்ற ஒரு வழக்கமான PyTorch செயல்பாட்டை @torch.compile மூலம் மடக்கும்போது, TorchInductor பின்னணியில் ஒரே ஒரு இணைக்கப்பட்ட (fused) Triton kernel-ஐ உருவாக்குவதன் மூலம் நான்கு தனித்த HBM round-trips-ஐ நீக்குகிறது.

TORCH_LOGS="output_code" python script.py என உங்கள் script-ஐ இயக்கினால், compiler-ஆல் உருவாக்கப்பட்ட உண்மையான Triton குறியீடு அச்சிடப்படும்; அது இவ்வாறு இருக்கும்:

import triton
import triton.language as tl

@triton.jit
def triton_per_fused_mul_pow_rsqrt_0(in_ptr0, in_ptr1, out_ptr0, xnumel, rnumel, XBLOCK: tl.constexpr):
    RBLOCK: tl.constexpr = 4096
    xoffset = tl.program_id(0) * XBLOCK
    xindex = xoffset + tl.arange(0, XBLOCK)[:, None]
    xmask = xindex < xnumel
    rindex = tl.arange(0, RBLOCK)[None, :]
    rmask = rindex < rnumel

    # 1. Single coalesced read of input tensor (x) and weight vector from HBM
    x = tl.load(in_ptr0 + (rindex + (4096 * xindex)), rmask & xmask, other=0.0).to(tl.float32)
    w = tl.load(in_ptr1 + (rindex), rmask, eviction_policy='evict_last').to(tl.float32)

    # 2. Compute square, row-wise mean, and reciprocal square root entirely in registers
    x_sq = x * x
    row_sum = tl.sum(x_sq, 1)[:, None]
    rstd = tl.rsqrt((row_sum / 4096.0) + 1e-06)

    # 3. Multiply by inverse standard deviation and learned weight, then write once
    out = (x * rstd) * w
    tl.store(out_ptr0 + (rindex + (4096 * xindex)), out, rmask & xmask)
  • Compiler தானாகக் கண்டுபிடித்தது: weight vector w-இல் உள்ள eviction_policy='evict_last' என்பதைக் கவனியுங்கள். w ஒவ்வொரு வரிசையிலும் (xindex) மீண்டும் மீண்டும் பயன்படுத்தப்படுகிறது என்பதை TorchInductor தானாகவே கண்டறிந்து, x-ஐ ஒரே ஒரு முறை streaming செய்யும்போது w-ஐ chip-மீது பிணைத்து வைக்குமாறு GPU-யின் L2 cache-க்கு அறிவுறுத்துகிறது.

2. அடுத்தடுத்து ஒப்பிடக்கூடிய மாத்திரைப் பெருக்கல் (Matrix Multiplication, GEMM) குறியீடு: CUDA C++ எதிர் Triton

மாத்திரைப் பெருக்கல் (C = A × B), CUDA C++-இல் உள்ள கைமுறை thread synchronization-க்கும் Triton-இல் உள்ள declarative tile கணிதத்திற்கும் இடையிலான பெரும் வேறுபாட்டைத் தெளிவுபடுத்துகிறது.

A. CUDA C++ (வெளிப்படையான Shared Memory Tiling & Sync Barriers)

CUDA C++-இல், ஒவ்வொரு thread-ம் ஒரு scalar வெளியீட்டு உறுப்பை (acc) கணக்கிடுகிறது; அதே வேளை thread-கள் tiles-ஐ __shared__ memory-யில் ஏற்ற கைமுறையாக ஒத்துழைக்கின்றன:

#define TILE 16

__global__ void gemm_cuda(const float* A, const float* B, float* C, int M, int N, int K) {
    __shared__ float sA[TILE][TILE];
    __shared__ float sB[TILE][TILE];

    int row = blockIdx.y * TILE + threadIdx.y;
    int col = blockIdx.x * TILE + threadIdx.x;
    float acc = 0.0f;

    for (int t = 0; t < (K + TILE - 1) / TILE; ++t) {
        // 1. Each thread manually loads 1 element into Shared Memory
        sA[threadIdx.y][threadIdx.x] = (row < M && t * TILE + threadIdx.x < K)
                                       ? A[row * K + t * TILE + threadIdx.x] : 0.0f;
        sB[threadIdx.y][threadIdx.x] = (t * TILE + threadIdx.y < K && col < N)
                                       ? B[(t * TILE + threadIdx.y) * N + col] : 0.0f;
        __syncthreads(); // Mandatory barrier before reading shared tiles

        // 2. Inner dot product across the 16x16 tile
        for (int k = 0; k < TILE; ++k) {
            acc += sA[threadIdx.y][k] * sB[k][threadIdx.x];
        }
        __syncthreads(); // Mandatory barrier before loading next tile
    }

    if (row < M && col < N) C[row * N + col] = acc;
}

B. OpenAI Triton (Declarative 2D Tile Accumulation & Tensor Cores)

Triton-இல், ஒரே ஒரு program block, tl.dot() பயன்படுத்தி முழு BLOCK_M × BLOCK_N வெளியீட்டு tile-ஐயும் கணக்கிடுகிறது; இது தானாகவே hardware Tensor Cores-ஆகத் தாழ்த்தப்படுகிறது:

@triton.jit
def gemm_triton(A_ptr, B_ptr, C_ptr, M, N, K,
                stride_am, stride_ak, stride_bk, stride_bn, stride_cm, stride_cn,
                BLOCK_M: tl.constexpr, BLOCK_N: tl.constexpr, BLOCK_K: tl.constexpr):
    pid_m = tl.program_id(0)
    pid_n = tl.program_id(1)

    offs_m = pid_m * BLOCK_M + tl.arange(0, BLOCK_M)
    offs_n = pid_n * BLOCK_N + tl.arange(0, BLOCK_N)
    offs_k = tl.arange(0, BLOCK_K)

    a_ptrs = A_ptr + (offs_m[:, None] * stride_am + offs_k[None, :] * stride_ak)
    b_ptrs = B_ptr + (offs_k[:, None] * stride_bk + offs_n[None, :] * stride_bn)

    # Accumulate in FP32 registers while multiplying FP16 tiles on Tensor Cores
    acc = tl.zeros((BLOCK_M, BLOCK_N), dtype=tl.float32)
    for k in range(0, K, BLOCK_K):
        a = tl.load(a_ptrs, mask=(offs_m[:, None] < M) & (k + offs_k[None, :] < K), other=0.0)
        b = tl.load(b_ptrs, mask=(k + offs_k[:, None] < K) & (offs_n[None, :] < N), other=0.0)
        acc = tl.dot(a, b, acc)  # Hardware Tensor Core instruction
        a_ptrs += BLOCK_K * stride_ak
        b_ptrs += BLOCK_K * stride_bk

    c_ptrs = C_ptr + stride_cm * offs_m[:, None] + stride_cn * offs_n[None, :]
    tl.store(c_ptrs, acc.to(tl.float16), mask=(offs_m[:, None] < M) & (offs_n[None, :] < N))

3. CUDA C++-ஐ AMD ROCm (HIP)-க்கு மாற்றும்போது எழும் Warp-Size பிரச்சினைகள்

AMD-யின் HIP interface வழியாக தாழ்மட்ட CUDA C++ kernels-ஐ AMD Instinct GPU-களுக்கு (MI300X அல்லது MI325X போன்றவை) மாற்றும்போது, syntax மொழிபெயர்ப்பு (cudaMalloc → hipMalloc) எளிதானது. எனினும், NVIDIA warp-களில் 32 threads இருக்கும்போது, AMD CDNA wavefront-களில் 64 threads இருப்பதால், அமைதியான தர்க்கப் பிழைகள் (logical bugs) அடிக்கடி ஏற்படுகின்றன.

பிரச்சினைப் பகுதிநிலைபெயர்த்த NVIDIA CUDA முறை (Hardcoded Pattern)AMD Instinct (CDNA)-இல் ஏன் முறிவதுஇடம்பெயர் சாத்தியமான தீர்வு (Portable Fix)
1. Warp Reduction Loopsfor (int offset = 16; offset > 0; offset /= 2)16-இல் இருந்து தொடங்குவது முதல் 32 threads-ஐ மட்டுமே குறைக்கிறது; AMD-யின் 64-thread wavefront-இன் மேல் 32 threads-ஐ புறக்கணிக்கிறது.warpSize / 2-ஐ மாறிலியாகப் (dynamically) பயன்படுத்தவும் (for (int offset = warpSize / 2; offset > 0; offset /= 2)).
2. Bitmask Lane Masks__shfl_xor_sync(0xffffffff, val, offset)0xffffffff என்பது 32-bit integer mask; 64-thread wavefront-இல் இது மேல் 32 lanes-ஐ வெட்டிவிடுகிறது (அவற்றுக்கு 64-bit 0xffffffffffffffffULL mask தேவைப்படுகிறது).HIP-யின் mask இல்லாத __shfl_xor(val, offset) அல்லது 64-bit uint64_t mask (~0ULL) பயன்படுத்தவும்.
3. Shared Memory Sizing__shared__ float warp_sums[32]; (assuming max 1024 threads / 32 = 32 warps)64-thread wavefront-களுடன், 1024 threads என்பது 16 wavefront-களுக்குச் சமம்; இது பாதி shared memory-ஐ வீணடிக்கிறது அல்லது tid / 32-ஐ தவறாக index செய்கிறது.int warp_id = threadIdx.x / warpSize; எனக் கணக்கிட்டு, blockDim.x / warpSize பயன்படுத்தி array-களின் அளவை நிர்ணயிக்கவும்.
4. Ballot Return Typesunsigned int active = __ballot_sync(0xffffffff, pred);__ballot, AMD GPU-களில் 64-bit uint64_t-ஐத் திருப்புகிறது; அதை 32-bit unsigned int-இல் சேமிப்பது threads 32–63-இன் வாக்குகளை இழக்கச் செய்கிறது.ballot முடிவுகளை எப்போதும் uint64_t-இல் சேமித்து, __popc()-க்குப் பதிலாக __popcll() பயன்படுத்தவும்.
  • Triton ஏன் நான்கு பிரச்சினைகளையும் தவிர்க்கிறது: OpenAI Triton-இல், tl.sum(), tl.max() போன்ற செயல்பாடுகள் நிலைபெயர்த்த 32-thread warp-களுக்குப் பதிலாக முழு logical tensor பரிமாணங்கள் மீதும் இயங்குகின்றன. Compilation-இன்போது, Triton-இன் NVPTX backend, NVIDIA GPU-களுக்குத் தானாகவே 32-thread shuffle trees-ஐ வெளியிடுகிறது; அதேபோல் அதன் AMDGPU backend, AMD Instinct GPU-களுக்கு 64-thread wavefront reductions-ஐ வெளியிடுகிறது. இதனால் warp-size பிழைகள் வடிவமைப்பிலேயே நீக்கப்படுகின்றன.

PyTorch bytecode capture மற்றும் Triton code generation முதல் CUDA எதிர் AMD wavefront இயக்கவியல் வரை, நவீன GPU kernels-இன் முழு வாழ்க்கைச் சுழற்சியையும் இப்போது ஆராய்ந்துள்ளோம்.

மேலும் செயற்கை நுண்ணறிவு மற்றும் தொழில்நுட்பச் செய்திகள்