Usa herramientas de XLA

El flujo de trabajo de desarrollo de XLA suele centrarse en la IR HLO, que representa el procesamiento funcional aislado que se le proporciona al compilador. XLA incluye varias herramientas de línea de comandos (descritas a continuación) que consumen HLO y lo ejecutan, o proporcionan una etapa de compilación intermedia. El uso de esas herramientas es invaluable para un ciclo de iteración compile->modify->run rápido, ya que el HLO se puede visualizar y se puede hackear, y cambiar y ejecutarlo de manera iterativa suele ser la forma más rápida de entender y corregir el rendimiento o el comportamiento de XLA.

Por lo general, la forma más fácil de obtener el HLO para un programa que se compila con XLA es usar la variable de entorno XLA_FLAGS:

XLA_FLAGS=--xla_dump_to=/tmp/myfolder ./myprogram-entry-point

que almacena todos los archivos HLO previos a la optimización en la carpeta especificada, junto con muchos otros artefactos útiles.

Ejecuta fragmentos de HLO: run_hlo_module

La herramienta run_hlo_module funciona en HLO de optimización previa y, de forma predeterminada, compila, ejecuta y compara con la implementación del intérprete de referencia de forma predeterminada. Por ejemplo, la invocación habitual para ejecutar un archivo de entrada computation.hlo en una GPU NVIDIA y comprobar su precisión es la siguiente:

run_hlo_module --platform=CUDA --reference_platform=Interpreter computation.hlo

Al igual que con todas las herramientas, --help se puede usar para obtener la lista completa de opciones.

Ejecución de fragmentos de HLO con compatibilidad con SPMD: multihost_hlo_runner

El ejecutor de HLO de varios hosts es una herramienta muy similar, pero con la salvedad de que es compatible con SPMD, incluida la comunicación entre hosts. Una invocación típica se ve de la siguiente manera:

hlo_runner_main  --device_type=gpu --use_spmd_partitioning=true --num_partitions=4 --num_replicas=1 --hlo_file=computation.hlo

Ejecución de pases o etapas de compilación de HLO: hlo-opt

Cuando depuras o comprendes el funcionamiento del compilador, suele ser útil obtener la expansión para un hardware en particular en un punto específico de la canalización (ya sea HLO, HLO optimizado, TritonIR o LLVM) para una entrada HLO (estable) determinada.

hlo-opt admite varias etapas de salida: PTX, HLO después de las optimizaciones, IR de LLVM antes de las optimizaciones o TritonIR. El conjunto exacto de etapas admitidas depende de la plataforma (p.ej., PTX es específico de NVIDIA) y se puede ver con el comando --list-stages:

$ hlo-opt --platform=CUDA --list-stages
hlo
llvm
ptx

Después de seleccionar una etapa, el usuario puede escribir el resultado de la conversión de una plataforma determinada en una transmisión determinada:

$ hlo-opt myinput.hlo --platform=CUDA --stage=llvm

que imprimiría el volcado en stdout (o en un archivo determinado si se especificó -o).

Uso sin dispositivos

El acceso a una GPU no es necesario para la mayor parte de la compilación y, si se especifica una especificación de GPU en la línea de comandos, podemos obtener, p.ej., resultados de PTX sin acceso a un acelerador:

$ hlo-opt  --platform=CUDA --stage=llvm  --xla_gpu_target_config_filename=(pwd)/tools/data/gpu_specs/a100_80.txtpb input.hlo

Las especificaciones para las GPU populares se envían con el compilador, y el archivo proporcionado es la serialización de cadenas de device_description.proto:

gpu_device_info {
  cuda_compute_capability {
    major: 8
    minor: 0
  }
  threads_per_block_limit: 1024
  threads_per_warp: 32
  shared_memory_per_block: 127152
  shared_memory_per_core: 65536
  threads_per_core_limit: 2048
  core_count: 6192
  fpus_per_core: 64
  block_dim_limit_x: 2147483647
  block_dim_limit_y: 65535
  block_dim_limit_z: 65535
  memory_bandwidth: 2039000000000
  l2_cache_size: 4194304
  clock_rate_ghz: 1.1105
  device_memory_size: 79050250240
}
platform_name: "CUDA"

La compilación sin dispositivos puede tener problemas si se requiere el ajuste automático. Afortunadamente, también podemos proporcionarlos en la línea de comandos:

hlo-opt  --platform=CUDA --stage=llvm  --xla_gpu_target_config_filename=gpu_specs/a100_80.txtpb --xla_gpu_load_autotune_results_from=results.textpb input.hlo

El archivo de ajuste automático es la serialización de texto de autotune_results.proto, cuyo ejemplo se ve de la siguiente manera:

version: 2
results {
  device: "sm_8.0 with 42331013120B RAM, 108 cores, 1410000KHz clock, 1215000KHz mem clock, 41943040B L2$"
  hlo: "{\n  tmp_0 = f16[1,16,17,3]{3,2,1,0} parameter(0)\n  tmp_1 = f16[16,51]{1,0} bitcast(f16[1,16,17,3]{3,2,1,0} tmp_0)\n  tmp_2 = s8[16,17,3]{2,1,0} parameter(1)\n  tmp_3 = s8[51,16]{0,1} bitcast(s8[16,17,3]{2,1,0} tmp_2)\n  tmp_4 = f16[51,16]{0,1} convert(s8[51,16]{0,1} tmp_3)\n  tmp_5 = f16[16,16]{1,0} dot(f16[16,51]{1,0} tmp_1, f16[51,16]{0,1} tmp_4), lhs_contracting_dims={1}, rhs_contracting_dims={0}\n  ROOT tmp_6 = f16[1,16,16]{2,1,0} bitcast(f16[16,16]{1,0} tmp_5)\n}"
  result {
    run_time {
      nanos: 31744
    }
    triton {
      block_m: 32
      block_n: 32
      block_k: 32
      split_k: 1
      num_stages: 1
      num_warps: 4
    }
  }
}

La base de datos de ajuste automático se puede serializar con XLA_FLAGS=--xla_gpu_dump_autotune_results_t=<myfile.pbtxt>.

Cómo ejecutar un pase de compilador único

También se admiten las marcas de XLA_FLAGS, por lo que la herramienta se puede usar para probar la ejecución de un solo pase:

hlo-opt --platform=CUDA --stage=hlo --xla-hlo-enable-passes-only=algebraic_simplifer input.hlo