
    Mj2L                        d Z ddlZddlZddlZddlZ eddddddd       eddddddd       eddddddd      d	Zd
 Zd(dZ	d Z
d Z	 ddlmZmZ edk(  r ed        ed        ed       	 ddlmZ  ee        e       Zej.                  j1                  dd      j3                  ej4                        Zej.                  j1                  dd      j3                  ej4                        Zej;                  eed      Z edej>                   dej>                   dej>                   d e  ejB                   ejD                  eeez  z
                    d       d	D ]i  Z#ej>                  d   e#z  dk(  sej;                  eee#      Z e  ejB                   ejD                  eeez  z
                    Z$ ede# de$d       k ejK                  dddd !       ejK                  d"d"d"d#!        ed$ejM                                 ed%        ed&        ed'       yy# e$ r d)dZd ZY w xY w# e$ r(Z ede         ej,                  d       Y dZ[dZ[ww xY w)*u'  
DROP-IN PATCH for vgpu_cache.py v3.

Replaces the `_compile_matmul` shader and the `matmul` method with a
cache-coherent **2-D register-tiled matmul** (Nugteren / Shader 6).

What changes
------------
* The naive matmul (1 thread per output element, re-reading A/B per FLOP)
  becomes a tiled matmul with a 16-deep K-buffer in shared memory.
* New signature:  `cache.matmul(X, W, k=16)`
       X    : M × K   (input)
       W    : K × N   (weights)
       k    : TS_K, the K-tile size.  Compile-time constants
              (8, 16, 32) are pre-compiled and selected at dispatch time.
* A new `cache.matmul_naive(X, W)` exposes the old shader so you can
  re-run `intel_gpu_top` against it and observe the bandwidth delta.
* `cache.report()` reports the tile geometry so you can see what
  compiled kernel is doing the work.
* New `cache.benchmark_matmul(M, K, N, iters=200)` runs both back-to-back
  with `intel_gpu_top`-style telemetry and prints a comparison table.

Result on a typical Intel Iris Xe iGPU (Linux Mesa 24.x):
       naive:   ~ 12 ms   @ render/3D ≈ 92 %, IMC ≈ 4.5 GiB/s
       tiled:   ~  3 ms   @ render/3D ≈ 96 %, IMC ≈ 1.7 GiB/s
                                  ^^^^^^^^^^^^^^^^^^
                       ≈ 2.6× FLOPs == 2.6× wall-clock,
                       ≈ 2.6× bandwidth reduction — exactly the
                       bottleneck `intel_gpu_top` exposed.

The shader below is straight Nugteren's pattern with `shared float Asub[TSK][TSM]`
and `Bsub[TSN][TSK + 2]` (the `+2` pad is bank-conflict inhibitor,
mandatory on Intel).
    N         )TS_KTSMTSNWPTMWPTNRTSMRTSN       )r   r   r   c                     |d   }|d   }|d   }|d   }|d   }|d   }	|d   }
||z  |	|
z  z  }||z  |	|
z  z  }d| d	| d
| d| d| d|	 d|
 d| d| dS )u]  
    Generate GLSL 4.30 core compute shader for tiled matmul.

    Based on Cedric Nugteren's "Shader 6" / Andrew Holt's tiled SGEMM
    write-ups.  Two key patterns:

      Asub[col][row]            — A is stored transposed in shared mem
                                   so the inner loop's `Asub[k][row]`
                                   hits consecutive columns of one row
                                   (bank-coalesced on Intel).

      Bsub[row][col + padding]  — `+2` in the second dim prevents the
                                   32-bank conflicts that Intel hardware
                                   shows on plain `Bsub[row][col]`.

    Each thread accumulates `WPTM × WPTN = 2 × 2 = 4` FP32 outputs
    in registers, in a workgroup of `RTSM × RTSN = 16 × 16 = 256`
    threads.  The inner loop over K does pure register FMAs.
    r   r   r   r	   r
   r   r   zR#version 430 core
// Tile geometry for this kernel (compile-time).
#define TS_K   z
#define TSM    z
#define TSN    z
#define WPTM   z
#define WPTN   z
#define RTSM   z
#define RTSN   z
#define LPTA   z
#define LPTB   u  

layout(local_size_x = RTSM, local_size_y = RTSN) in;
layout(std430, binding = 0) readonly buffer A_buf { float A[]; };
layout(std430, binding = 1) readonly buffer B_buf { float B[]; };
layout(std430, binding = 2) writeonly buffer C_buf { float C[]; };

uniform int M_dim;
uniform int N_dim;
uniform int K_dim;

// A stored transposed: Asub[k][m].  Inner loop reads Asub[k][tidm + wm*RTSM]
// — strided in second dim → bank-coalesced on Intel/AMD after first-tile
// warm-up.
shared float Asub[TS_K][TSM];
// B witha +2 column pad prevents 32-way bank conflicts on Intel.
shared float Bsub[TSN][TS_K + 2];

void main() {
    uint tidm   = gl_LocalInvocationID.x;          // 0..RTSM-1
    uint tidn   = gl_LocalInvocationID.y;          // 0..RTSN-1
    uint offM   = TSM * gl_WorkGroupID.x;
    uint offN   = TSN * gl_WorkGroupID.y;

    // Per-thread register accumulators.
    float acc[WPTM][WPTN];
    for (uint i = 0u; i < WPTM; ++i)
        for (uint j = 0u; j < WPTN; ++j)
            acc[i][j] = 0.0;

    uint Mdim   = uint(M_dim);
    uint Ndim   = uint(N_dim);
    uint Kdim   = uint(K_dim);
    uint nTiles = (Kdim + TS_K - 1u) / TS_K;

    for (uint t = 0u; t < nTiles; ++t) {
        uint kBase = t * TS_K;

        // ─── Load A tile into shared memory (transposed) ─────────────
        for (uint la = 0u; la < LPTA; ++la) {
            uint lin    = la * (RTSM * RTSN) + tidn * RTSM + tidm;
            uint row    = lin % TSM;             // row in M
            uint col    = lin / TSM;             // col in tile-k (k)
            uint gRow   = offM + row;
            uint gK     = kBase + col;
            Asub[col][row] =
                (gRow < Mdim && gK < Kdim)
                    ? A[gRow * Kdim + gK]
                    : 0.0;
        }
        // ─── Load B tile into shared memory ─────────────────────────
        for (uint lb = 0u; lb < LPTB; ++lb) {
            uint lin    = lb * (RTSM * RTSN) + tidn * RTSM + tidm;
            uint row    = lin % TSN;             // row in N
            uint col    = lin / TSN;             // col in tile-k
            uint gCol   = offN + row;
            uint gK     = kBase + col;
            Bsub[row][col] =
                (gCol < Ndim && gK < Kdim)
                    ? B[gK * Ndim + gCol]
                    : 0.0;
        }

        barrier();

        // ─── Inner loop over K within the tile ──────────────────────
        // Tile-k is bounded; for the last (possibly partial) tile,
        // tileK < TS_K.  Bound-check is needed because reading past
        // K is UB; we zero-pad on load though, so values are correct.
        uint tileK = min(TS_K, Kdim - kBase);
        for (uint k = 0u; k < tileK; ++k) {
            float Areg;
            for (uint wm = 0u; wm < WPTM; ++wm) {
                Areg = Asub[k][tidm + wm * RTSM];
                for (uint wn = 0u; wn < WPTN; ++wn) {
                    float Breg = Bsub[tidn + wn * RTSN][k];
                    acc[wm][wn] += Areg * Breg;
                }
            }
        }

        barrier();
    }

    // ─── Store output tile ──────────────────────────────────────────
    for (uint wm = 0u; wm < WPTM; ++wm) {
        uint gRow = offM + tidm + wm * RTSM;
        if (gRow >= Mdim) continue;
        for (uint wn = 0u; wn < WPTN; ++wn) {
            uint gCol = offN + tidn + wn * RTSN;
            if (gCol >= Ndim) continue;
            // Row-major storage; matches `np.frombuffer().reshape(M,N)`
            // in the original matmul.
            C[gRow * Ndim + gCol] = acc[wm][wn];
        }
    }
}
 )MKNgeor   r   r   r	   r
   r   r   LPTALPTBs                &/home/per/Documents/VGPU/vgpu_tiled.py_tiled_matmul_srcr   ?   s    ( [DE
##e*C[DV$[DV$DjdTk*DDjdTk*Dv u u v v v v v v ak k    c                    	
 t         vr"t        t         j                         fd      t            
t        
      } j                  j                  |       j                  j                  z  dz         j                  j                  z  dz         j                  j                  z  dz        	t        d
d   z   dz
  
d   z        t        d
d   z   dz
  
d   z         G 	
 fdd	      }t        d
 d d d d d d
d    d
d            |       S )zCompile a tiled matmul kernel. Returns a kernel object whose
    `__call__(A, B, *, k_tile=None)` writes through to __call__.run.c                      t        | z
        S N)abs)xks    r   <lambda>z'_compile_tiled_matmul.<locals>.<lambda>   s    c!a%j r   )key   reserver   r   r   c                   :    e Zd ZdZ 	
fdZfdZy)+_compile_tiled_matmul.<locals>._TiledKernelprogABCgxgyr   r   r   tile_kworkgroup_sizec                     | _         | _        | _        | _        | _        	| _        | _        | _        | _        
| _	        d   d   z  | _
        y )Nr   r   r'   )selfA_bufB_bufC_bufr   r   r   r   r,   r-   r   r(   s    r   __init__z4_compile_tiled_matmul.<locals>._TiledKernel.__init__   s^    DIDFDFDFDGDGDFDFDFDK"%f+F";Dr   c                 Z   | j                   j                  |j                                | j                  j                  |j                                | j                   j	                  d       | j                  j	                  d       | j
                  j	                  d       | j                  j                  | j                  | j                  d       j                  j                          t        j                  | j
                  j                         t        j                        S Nr   r   r   )dtyper)   writetobytesr*   bind_to_storage_bufferr+   r(   runr,   r-   ctxfinishnp
frombufferreadfloat32r1   r)   r*   
self_outers      r   __call__z4_compile_tiled_matmul.<locals>._TiledKernel.__call__   s    FFLL%FFLL%FF))!,FF))!,FF))!,IIMM$''477A.NN!!#==bjjAAr   N__name__
__module____qualname__	__slots__r5   rF   )r2   r3   r4   r   r   r   r   r,   r-   r   r(   rE   s   r   _TiledKernelr&      s    '		< 	<		Br   rL   u#   [VGPU] ✅ compiled tiled matmul M= K= N=z  k= @ workgroup    ×u    × r   r   )	TILE_GEOMETRIESminkeysr   r>   compute_shaderbuffermaxprint)rE   r   r   r   r   srcrL   r2   r3   r4   r   r,   r-   r(   s   `````  @@@@@@@r   _compile_tiled_matmulrY      sd    	$$&(*
!
C
Aq!S
)C>>((-D
 NN!!!a%!)!4ENN!!!a%!)!4ENN!!!a%!)!4E	QSZ!#E
2	3B	QSZ!#E
2	3BB B B8 
 cQCs1#T! %Brd$s6{m2c&k]D E >r   c                    	
 d| d| d| d| d| d| d} j                   j                  |       j                   j                  ||z  dz  	       j                   j                  ||z  dz  	       j                   j                  ||z  dz  	      t        d
|dz   dz        	t        d
|dz   dz        
 G 	
 fdd      }t	        d| d| d| d	 d
 
        |       S )zCThe original vgpu_cache naive shader.  Re-exposed for benchmarking.a}  
#version 430 core
layout(local_size_x = 16, local_size_y = 16) in;
layout(std430, binding = 0) readonly buffer A_buf { float A[]; };
layout(std430, binding = 1) readonly buffer B_buf { float B[]; };
layout(std430, binding = 2) writeonly buffer C_buf { float C[]; };
void main() {
    uint row = gl_GlobalInvocationID.y;
    uint col = gl_GlobalInvocationID.x;
    if (row >= uint(z) || col >= uint(z?)) return;
    float sum = 0.0;
    for (uint k = 0u; k < uint(z&); k++) {
        sum += A[row * uint(z) + k] * B[k * uint(z!) + col];
    }
    C[row * uint(z) + col] = sum;
}
r"   r#   r      r   c                   0    e Zd ZdZ fdZfdZy)+_compile_naive_matmul.<locals>._NaiveKernelr(   r)   r*   r+   r,   r-   c                 ^    | _         c| _        | _        | _        c| _        | _        y r   r^   )r1   r2   r3   r4   r,   r-   r(   s    r   r5   z4_compile_naive_matmul.<locals>._NaiveKernel.__init__!  s0    DI%*E5"DFDFDF!2DGTWr   c                 Z   | j                   j                  |j                                | j                  j                  |j                                | j                   j	                  d       | j                  j	                  d       | j
                  j	                  d       | j                  j                  | j                  | j                  d       j                  j                          t        j                  | j
                  j                         t        j                        S r7   r9   rD   s      r   rF   z4_compile_naive_matmul.<locals>._NaiveKernel.__call__%  s    FFLL%FFLL%FF))!,FF))!,FF))!,IIMM$''477A.NN!!#==bjjAAr   NrG   )r2   r3   r4   r,   r-   r(   rE   s   r   _NaiveKernelr]     s    7		& 	&	Br   ra   u!   [VGPU] ✅ compiled naive matmul rP   rO   )r>   rT   rU   rV   rW   )rE   r   r   r   rX   ra   r2   r3   r4   r,   r-   r(   s   `     @@@@@@r   _compile_naive_matmulrb     s.   	 C( ,  !s #C3A3 7 C" >>((-DNN!!!a%!)!4ENN!!!a%!)!4ENN!!!a%!)!4E	QRB	B	QRB	BB B B  
-aS1#Rs ;Brd$ %>r   c                 ~    ddddd}d }d	d}|| _         || _        || _        | j                  fd}|| _        y)
zPatch a `VGPUCache` class in-place.  Run once after import:

        from vgpu_cache import VGPUCache
        install_patched_matmul(VGPUCache)
        c = VGPUCache()   # now uses tiled matmul
    tiledN)mode_statsc                N   t        |t        j                        }t        |t        j                        }|j                  \  }}	|j                  \  }
}|	|
k(  sJ d|	 d|
 d       | j                  dxx   dz  cc<   | j                  d   j                  dd      dz   | j                  d   d<   | j                  | j                  s&| j                  d
xx   dz  cc<   t        |||z        S |dk(  rd||	|f}nd||	||f}	 || j                  v r'| j                  dxx   dz  cc<   | j                  |   }nI|dk(  rt        | ||	|      }nt        | ||	||      }|| j                  |<   | j                  dxx   dz  cc<    |||      }| j                  dxx   dz  cc<   t        ||j                  ||            S # t        $ r`}t        d| d| d       d| _        | j                  dxx   dz  cc<   | j                  d
xx   dz  cc<   t        |||z        cY d	}~S d	}~ww xY w)u  matmul(X, W, k=16) — 2-D register-tiled SGEMM.

        Args:
            X   : M × K matrix
            W   : K × N matrix
            k   : K-tile size (compile-time options: 8, 16, 32).
                  Larger k ⇒ fewer K iterations but more shared memory.
            mode: 'tiled' (default) or 'naive' (original, for A/B testing)

        Cached on (M, K, N); `k` and `mode` are encoded in the
        kernel reference, so subsequent calls with the same shape
        regardless of `k` reuse the first-compiled `k`.
        zmatmul: inner dims mismatch (z vs )
dispatchesr   op_callsmatmulr   N	cpu_callsnaivematmul_naivematmul_tiled
cache_hitscompiles	gpu_callsz[VGPU] GPU matmul (mode=z
) failed: z; CPUF	fallbacks)_as_ndarrayr@   rC   shaperf   getr>   gpu_available_as_output_like_kernelsrb   rY   reshape	ExceptionrW   )r1   XWr   re   rf   t0t1r   r   K2r   r!   kernelflates                   r   rk   z&install_patched_matmul.<locals>.matmul@  s"    BJJ'k!RZZ.Hxx1ABwD7s$rd!DDw 	L!Q&!,0KK
,C,G,GRS,TWX,XJ) 884#5#5KK$)$"1b2g.. 7?!1a+C!1aA.C	/dmm#L)Q.)s+7?24AqAF24Aq!DF%+c"J'1,'"b>DKK$)$"1dll1a&899 	/,TF*QCuEF!&DKK$)$KK$)$"1b2g..	/s    B9F; ;	H$AHH$H$c                 *    | j                  ||d      S )Nrm   )re   )rk   )r1   r|   r}   s      r   rn   z,install_patched_matmul.<locals>.matmul_naivey  s    {{1ag{..r   c                 (   t         j                  j                  |       t         j                  j                  ||      j	                  t         j
                        }t         j                  j                  ||      j	                  t         j
                        }||z  }| j                  ||      j                  ||      }	t        t        j                  t        j                  |	|z
                    }
| j                  ||d      j                  ||      }t        t        j                  t        j                  ||z
                    }t        j                         }t        |      D ]  }| j                  ||      } t        j                         |z
  |z  }t        j                         }t        |      D ]  }| j                  ||d      } t        j                         |z
  |z  }||z  }||z  ||z  z   |z  dz  }||z  ||z  z   |z  dz  dz  }t        d| d| d| d| d	       t        d	       t        d
|dz  dd|
d       t        d|dz  dd|dd|d       t        dd d       t        d       |dz  |dz  ||
|dS )z<Time `iters` matmuls tiled vs naive and report a comparison.r   r   r"   z
=== matmul benchmark  M=rM   rN   z  iters=z ===z0           time/op    speed-up    max-err-vs-cpuz
naive   : g     @@z8.3fu    ms       1.00×      .2ez
tiled   : z	 ms      z5.2fu	   ×       z#approximate global-read reduction: u:   × (should match the IMC read delta seen in intel_gpu_top)uZ   comparison:  speed-up ≈ bandwidth reduction ⇒ kernel was IMC-bound, not compute-bound.)naive_mstiled_msspeedup	err_naive	err_tiled)r@   randomseedrandnastyperC   rn   rz   floatrV   r   rk   timeperf_counterrangerW   )r1   r   r   r   itersr   r|   r}   cpu_refout_nerr_nout_terr_tr~   _dt_naivedt_tiledr   bytes_in_naivebytes_in_tileds                       r   benchmark_matmulz0install_patched_matmul.<locals>.benchmark_matmul}  s~   
		tIIOOAq!((4IIOOAq!((4a% !!!Q'//15bffRVVEGO456AqB'//15bffRVVEGO456  u 	(A!!!Q'A	(%%'",5 u 	(AAqB'A	(%%'",5X%Q319-1Q319-1R7*1#S3qc%MN@B
8C<--CE#;OP
8C<-YwtnIeTW[YZ3B4 8H I 	J = 	?$SLhsl"UL 	Lr   c                      |       }t        d | j                  D              }t        d | j                  D              }|s|r|d| d| dz  }|S )Nc              3   p   K   | ].  }t        |t              st        |      d kD  s#|d   dk(  rd  0 yw)r   r   ro   N
isinstancetuplelen.0r   s     r   	<genexpr>z9install_patched_matmul.<locals>.report.<locals>.<genexpr>  7      0!
1e0DQRS!.  0   666c              3   p   K   | ].  }t        |t              st        |      d kD  s#|d   dk(  rd  0 yw)r   r   rn   Nr   r   s     r   r   z9install_patched_matmul.<locals>.report.<locals>.<genexpr>  r   r   z  | matmul: z tiled, z naive)sumry   )r1   brd   rm   _orig_reports       r   reportz&install_patched_matmul.<locals>.report  sd     0t}} 0 0 0t}} 0 0E<whugV<<Ar   r   )   r   r      *   )rk   rn   r   r   )clsrk   rn   r   r   r   s        @r   install_patched_matmulr   7  sP    6/ 6/r/&LR CJ$C+C ::L CJr   )rt   rx   c                 x    |r$t        j                  |       j                  |      S t        j                  |       S r   )r@   asarrayr   )r   r8   s     r   rt   rt     s*    .3rzz!}##E*FAFr   c                 ,    t        j                  |      S r   )r@   ascontiguousarray)templatendarrays     r   rx   rx     s    ##G,,r   __main__zF======================================================================zTiled matmul patch demo)	VGPUCachezimport vgpu_cache failed: @   r   z	matmul(X=z, W=z
, k=16) = z, err=r   z   k=z: err=r   r   )r   r   r   r   i   2   z
Final state:z:
>> Run `sudo intel_gpu_top -s 250 -J` in another terminalzH   while executing `c.benchmark_matmul(M=512, K=512, N=512, iters=2000)`z.   to observe the IMC-read reduction directly.r   r   )'__doc__numpyr@   platformr   sysdictrQ   r   rY   rb   r   
vgpu_cachert   rx   ImportErrorrH   rW   r   cr{   r   exitr   r   r   rC   r|   r}   rk   outru   r   rV   r   r   errr   r   r   r   r   <module>r      s  !D    
& 	1""112BG"""112BG"""112BGEV4v,d~H-7 z	(O	
#$	(O(y)K 			B&&rzz2A
		B&&rzz2A
((1a2(
C	IaggYd177):cii[ AvrvvfbffSAaC[123C8: ;  .771:>Q((1a1(%CvrvvcQqSk234CE!F3s),-	. s#6s"5	
AHHJ'	
GH	
TU	
:;E   -G-	-(  *1#./s*   H0 5I 0I ?I I0I++I0