ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • VGPR, SGPR 사용여부 확인
    실험실 2020. 9. 24. 01:35

     

    GPU에 대해서 더 공부하고 싶은 차에 [번역] INTRO TO GPU SCALARIZATION – PART 1 글을 봤었고, SGPR/SALU를 사용하는 경우 Wave내에 모든 Thread가 동일한 코드를 사용하게 되어서 성능 향상이 있을 것이라고 했습니다.

     

     

    사실 이쪽은 완전히 새로운 영역이라... 성능차이가 정말 나는 것인가? 한 번해보고 싶었는데, 현재 Shader 코드가 VGPR/VALU or SGPR/SALU를 사용하는지 여부도 확인하는 법을 몰랐습니다. 최근에 렌더독을 이용하면 이 것을 확인 할 수 있다는 것을 알게 되었고, 실제로 Shader 코드가 사용하는 레지스터를 판별 할 수 있는지 한번 테스트 해봤습니다.

     

    [번역] INTRO TO GPU SCALARIZATION – PART 1에서는 Note[0]에 SALU에는 ISA에 부동소수점 연산 명령어가 없어서 VALU가 될 거라고 하던데, 실제 AMD "Vega" Instruction Set Architecture에 나와있는 것을 확인했습니다.

     

    출처 : https://developer.amd.com/wp-content/resources/Vega_Shader_ISA.pdf#page35

     

     

    그리고 렌더독으로 쉐이더 코드를 테스트 해본 결과 float인 경우 SGPR의 데이터를 VGPR에 올린 뒤 VALU로 연산되는 것을 아래 코드로 확인할 수 있습니다. 렌더독에서 Disassembly type을 Vega20으로 하여 디버깅 한 예 입니다.

     

     

    //////////////////////////////////////////////////////////////////////////////////	
    // 아래 코드가 주석대로 SGPR과 VGPR에 올라가는지 확인 해보자.
    //
    // This will be in a SGPR
    // -> [OK 잘 올라감]
    float s_value = LightDirection.x;
    
    // This will be put in VGPRs via a VMEM load as pixelCoord is in VGPRs
    // -> [VGPR에 잘 올라감]
    float4 v_textureSample = ShaderTextures[0].Sample(SamplerType, Input.Tex);
    
    // This will be put in SGPRs via a SMEM load as 0 is constant.
    // -> [SGPR에 잘 올라감]
    TestInput s_someData = TestStructuredBuffer.Load(0);
    
    // This should be an SALU op (output in SGPR) since both operands are in SGPRs
    // (Note, check note [0])
    // -> [여기서 SALU가 사용될 것이라고 했지만 아니었음. SGPR에는 32bit Integer와 
    //     32 bit or 64 bit Bit연산만 지원해서 VGPR로 옮긴 뒤 VALU로 연산함]
    // * s_someData.Color.x 는 float임 *
    float s_someModifier = s_value + s_someData.Color.x;
    
    //// This will be a VALU (output in VGPR) since one operand is VGPR.
    // -> [VGPR에 잘 올라감]
    float4 v_finalResult = s_someModifier * v_textureSample;
    
    return v_finalResult;
    //////////////////////////////////////////////////////////////////////////////////	
    
    
    ; Disassembly for GCN (Vega 20)
    
    ; -------- Statistics ---------------------
    ; SGPRs: 27 out of 104 used
    ; VGPRs: 5 out of 256 used
    ; LDS: 0 out of 65536 bytes used
    ; 0 bytes scratch space used
    ; Instructions: 12 ALU, 3 Control Flow, 1 TFETCH
    
    ; -------- Disassembly --------------------
    ; ****** 각 어셈블리 라인의 우측에 HLSL 코드의 실제 라인을 써뒀으니 참고. ******
    shader main
      asic(GFX9)
      type(PS)
                                                                // s_ps_state in s0
    
      s_mov_b32     m0, s24                                 // 000000000000: BEFC0018
      s_mov_b64     s[2:3], exec                            // 000000000004: BE82017E
      s_wqm_b64     exec, exec                              // 000000000008: BEFE077E               // 여기서 float4 v_textureSample = ShaderTextures[0].Sample(SamplerType, Input.Tex);
      v_interp_p1_f32  v2, v0, attr0.x                      // 00000000000C: D4080000               //
      v_interp_p1_f32  v3, v0, attr0.y                      // 000000000010: D40C0100               //
      v_interp_p2_f32  v2, v1, attr0.x                      // 000000000014: D4090001               // 이까지
      v_interp_p2_f32  v3, v1, attr0.y                      // 000000000018: D40D0101
      image_sample  v[0:3], v[2:4], s[4:11], s[16:19] dmask:0xf // 00000000001C: F0800F00 00810002
      s_buffer_load_dword  s0, s[20:23], 0x10               // 000000000024: C022000A 00000010      // float s_value = LightDirection.x;
      s_buffer_load_dword  s1, s[12:15], 0x00               // 00000000002C: C0220046 00000000      // TestInput s_someData = TestStructuredBuffer.Load(0);
      s_waitcnt     lgkmcnt(0)                              // 000000000034: BF8CC07F
      v_mov_b32     v4, s0                                  // 000000000038: 7E080200               // float s_value = LightDirection.x;
      v_add_f32     v4, s1, v4                              // 00000000003C: 02080801               // float s_someModifier = s_value + s_someData.Color.x;
      s_waitcnt     vmcnt(0)                                // 000000000040: BF8C0F70
      v_mul_f32     v0, v4, v0                              // 000000000044: 0A000104               // 여기서 float4 v_finalResult = s_someModifier * v_textureSample;
      v_mul_f32     v1, v4, v1                              // 000000000048: 0A020304               //
      v_mul_f32     v2, v4, v2                              // 00000000004C: 0A040504               //
      v_mul_f32     v3, v4, v3                              // 000000000050: 0A060704               // 이까지
      s_mov_b64     exec, s[2:3]                            // 000000000054: BEFE0102
      v_cvt_pkrtz_f16_f32  v0, v0, v1                       // 000000000058: D2960000 00020300
      v_cvt_pkrtz_f16_f32  v1, v2, v3                       // 000000000060: D2960001 00020702
      exp           mrt0, v0, v0, v1, v1 done compr vm      // 000000000068: C4001C0F 00000100      // return v_finalResult;
      s_endpgm                                              // 000000000070: BF810000
    end
    
    
    

     

    그 외에 더 다양한 툴을 프로파일링에 사용할 수 있는데, 대부분 DX12나 Vulkan에서 사용가능한 것 같네요. 특히, DX12 부터는 Wave intrinsics의 사용이 가능합니다. [번역] INTRO TO GPU SCALARIZATION – PART 1 에서 설명하는 나머지 부분은 API를 숙지하고 다시 해봐야겠네요.

     

     

    추가

    StructuredBuffer에 int를 전달하여 SGPR로 ALU연산이 되는지 한번 확인해봤는데, 실제로 그렇게 됩니다.

    /////////////////////////////////////////////////////////////    
    TestInput s_someData = TestStructuredBuffer.Load(0);
    int k = s_someData.Color * s_someData.Color * 2.0;
         
    return k;
    /////////////////////////////////////////////////////////////
    
    ; Disassembly for GCN (Vega 20)
    
    ; -------- Statistics ---------------------
    ; SGPRs: 11 out of 104 used
    ; VGPRs: 3 out of 256 used
    ; LDS: 0 out of 65536 bytes used
    ; 0 bytes scratch space used
    ; Instructions: 2 ALU, 2 Control Flow, 0 TFETCH
    
    ; -------- Disassembly --------------------
    shader main
      asic(GFX9)
      type(PS)
                                                                // s_ps_state in s0
    
      s_buffer_load_dword  s0, s[4:7], 0x00                 // 000000000000: C0220002 00000000
      s_waitcnt     lgkmcnt(0)                              // 000000000008: BF8CC07F
      s_mul_i32     s0, s0, s0                              // 00000000000C: 92000000           // int k = s_someData.Color * s_someData.Color 부분에 해당
      v_cvt_f32_i32  v0, s0 mul:2                           // 000000000010: D1450000 08000000  // 위의 결과에 2를 곱함
      v_cvt_pkrtz_f16_f32  v0, v0, v0                       // 000000000018: D2960000 00020100
      s_nop         0x0000                                  // 000000000020: BF800000
      s_nop         0x0000                                  // 000000000024: BF800000
      exp           mrt0, v0, v0, v0, v0 done compr vm      // 000000000028: C4001C0F 00000000
      s_endpgm                                              // 000000000030: BF810000
    end
    
    

    '실험실' 카테고리의 다른 글

    [PBR] Substance/Roughness/Metalic  (0) 2021.05.03
    BRDF 정리 노트 (작성중)  (0) 2020.11.11
    Radiometric Quantities  (0) 2020.10.26

    댓글

Designed by Tistory & scahp.