Usa una imagen de SO personalizada
Puedes usar una imagen de SO personalizada para tus VMs de TPU con el objetivo de precargar software, usar una distribución de SO específica o aplicar modificaciones personalizadas del kernel. Para crear una imagen personalizada, se deben realizar modificaciones específicas en el sistema durante el proceso de creación de la imagen y configurarla para que controle las tareas de tiempo de inicio necesarias para la funcionalidad de la TPU.
Ten en cuenta las siguientes exenciones de responsabilidad si usas una imagen de SO personalizada con TPU:
- Google proporciona imágenes predeterminadas de asistencia a largo plazo (LTS) de Ubuntu optimizadas para TPU. Los cambios del SO que se indican en esta página solo se validan para las imágenes de Ubuntu LTS optimizadas para TPU y compatibles con Google.
- Eres responsable de extrapolar los cambios necesarios del SO para cualquier otra distribución del SO o imágenes personalizadas. Google no garantiza que las modificaciones para Ubuntu que se indican en esta página funcionen con otras distribuciones de SO o con otra imagen de Ubuntu con un kernel personalizado.
- Google no compila ni proporciona pruebas para ninguna imagen de SO que no sean las imágenes predeterminadas de Ubuntu LTS optimizadas para TPU. Debes compilar y probar tu imagen de SO personalizada.
Para obtener más información sobre las imágenes de Ubuntu LTS predeterminadas optimizadas para TPU, consulta Imágenes de SO de TPU.
Requisitos previos
La imagen base debe tener instalados los siguientes componentes:
- Docker
ethtool, versión 6.7 o posterior si usas TPU v6e o TPU7x- Python 3 con los paquetes
PyYAMLyrequests, disponibles en Ubuntu comopython3-yamlypython3-requests - gcloud CLI
Para las VMs de TPU7x, tu imagen base debe usar una versión mínima de kernel de Linux del SO invitado de 6.8.
Realiza modificaciones durante la creación de imágenes
Aplica las siguientes modificaciones mientras compilas tu imagen de Ubuntu personalizada.
Inhabilitar las actualizaciones automáticas
Inhabilita y quita unattended-upgrades para que las actualizaciones de paquetes en segundo plano
no retengan el bloqueo de dpkg ni interrumpan las cargas de trabajo de TPU:
echo 'APT::Periodic::Unattended-Upgrade "0";' > /etc/apt/apt.conf.d/99cloudtpuconf
DEBIAN_FRONTEND=noninteractive apt-get -y purge unattended-upgrades
Vincula dispositivos TPU a VFIO
Para permitir que el SO invitado acceda al hardware de TPU, debes vincular
los dispositivos TPU al controlador vfio-pci.
Crea un archivo de reglas de udev llamado
99-tpu-vfiopci.rulesen/etc/udev/rules.d/:# Rules for binding vfio-enabled TPU devices to vfio-pci. # v5p SUBSYSTEM=="pci", ACTION=="add", ATTRS{vendor}=="0x1ae0", ATTRS{device}=="0x0062", ATTRS{subsystem_vendor}=="0x1ae0", ATTRS{subsystem_device}=="0x00ad", DRIVER!="vfio-pci", TAG+="bind_to_vfio_pci" # v6e SUBSYSTEM=="pci", ACTION=="add", ATTRS{vendor}=="0x1ae0", ATTRS{device}=="0x006f", ATTRS{subsystem_vendor}=="0x1ae0", ATTRS{subsystem_device}=="0x00d1", DRIVER!="vfio-pci", TAG+="bind_to_vfio_pci" # TPU7x SUBSYSTEM=="pci", ACTION=="add", ATTRS{vendor}=="0x1ae0", ATTRS{device}=="0x0076", ATTRS{subsystem_vendor}=="0x1ae0", ATTRS{subsystem_device}=="0x00f2", DRIVER!="vfio-pci", TAG+="bind_to_vfio_pci" # Bind all 'bind_to_vfio_pci' tagged devices to vfio-pci. TAG=="bind_to_vfio_pci", RUN+="/lib/udev/bind_to_vfio_pci.sh $kernel"Crea una secuencia de comandos llamada
bind_to_vfio_pci.shen/lib/udev/:#!/bin/bash # Run ./bind_to_vfio_pci.sh <DBDF> # Binds the device at <DBDF> to vfio-pci. # If the device is already bound to a driver, unbinds it first. # Load the vfio-pci module into the kernel. No-op if already loaded. modprobe vfio-pci DBDF_REGEX="^[[:xdigit:]]{4}:[[:xdigit:]]{2}:[[:xdigit:]]{2}.[[:xdigit:]]$" unset BDF if [[ $1 =~ $DBDF_REGEX ]]; then BDF=$1 else echo "Error: BDF arg ($1) is not in form dddd:bb:dd.f" exit 1 fi PCI_PATH="/sys/bus/pci/devices/$BDF" echo "vfio-pci" > "$PCI_PATH/driver_override" PCI_DRIVER_PATH="$PCI_PATH/driver" if [[ -d "$PCI_DRIVER_PATH" ]]; then curr_driver=$(readlink "$PCI_DRIVER_PATH") curr_driver=${curr_driver##*/} if [[ $curr_driver == "vfio-pci" ]]; then echo "$BDF already bound to vfio-pci" exit 0 else echo "$BDF" > "$PCI_DRIVER_PATH/unbind" if [[ -d "$PCI_DRIVER_PATH" ]]; then echo "Error: Unable to unbind $PCI_DRIVER_PATH" exit 1 fi echo "Unbound $BDF from driver $curr_driver" fi fi echo "$BDF" > /sys/bus/pci/drivers_probe echo "Bound $BDF to vfio-pci" # Grant read/write access on VFIO device to all users IOMMU_GROUP=$(readlink "$PCI_PATH/iommu_group" | xargs basename) VFIO_DEV="/dev/vfio/$IOMMU_GROUP" if [[ -c "$VFIO_DEV" ]]; then chmod 0666 "$VFIO_DEV" else echo "$VFIO_DEV not found" exit 1 fi # Set allow_unsafe_interrupts for x86 platforms. (uname -a | grep -q x86_64) && echo 1 > /sys/module/vfio_iommu_type1/parameters/allow_unsafe_interrupts # This is only needed to avoid non-zero exit code from previous command. echo "All Done!"Haz que la secuencia de comandos sea ejecutable:
chmod +x /lib/udev/bind_to_vfio_pci.shOtorga acceso al dispositivo TPU a todos los usuarios del sistema:
echo 'KERNEL=="accel*" MODE="0666"' >> /etc/udev/rules.d/99-tpu.rules
Modifica la imagen para mejorar el rendimiento
Para garantizar un rendimiento óptimo, ajusta los siguientes límites y parámetros del sistema.
Límites de memoria
Permite que un solo proceso bloquee memoria ilimitada actualizando
/etc/security/limits.conf:
echo '* hard memlock unlimited' >> /etc/security/limits.conf
echo '* soft memlock unlimited' >> /etc/security/limits.conf
Límites de archivos
Aumenta la cantidad de archivos abiertos actualizando /etc/security/limits.conf:
echo "* soft nofile 100000" >> /etc/security/limits.conf
echo "* hard nofile 100000" >> /etc/security/limits.conf
echo "root soft nofile 100000" >> /etc/security/limits.conf
echo "root hard nofile 100000" >> /etc/security/limits.conf
Parámetros del kernel
Actualiza tu configuración de GRUB (por lo general, en /etc/default/grub) para incluir los
siguientes parámetros en GRUB_CMDLINE_LINUX:
idle=poll: Impide que la CPU entre en estados de inactividad de bajo consumo.transparent_hugepage=always: Habilita las páginas enormes transparentes (THP).iommu.passthrough=0: Inhabilita el modo de transferencia de la unidad de administración de la memoria de entrada y salida (IOMMU).panic=-1: Configura el kernel para que se reinicie de inmediato si se produce un error irrecuperable del kernel.intel_iommu=on,sm_on: Habilita la IOMMU de Intel en modo escalable. Es obligatorio para las arquitecturas TPU7x y v5p.
En los siguientes pasos, se muestra cómo actualizar estos parámetros del kernel:
Establece la variable de línea de comandos del kernel con los parámetros comunes:
kernel_cmdline="idle=poll transparent_hugepage=always iommu.passthrough=0 panic=-1"Si compilas una imagen para TPU7x o TPU v5p, agrega el parámetro de IOMMU de Intel:
kernel_cmdline="${kernel_cmdline} intel_iommu=on,sm_on"Actualiza
GRUB_CMDLINE_LINUXen/etc/default/gruby vuelve a generar la configuración de GRUB:sed -i "s/^GRUB_CMDLINE_LINUX=\".*\"/GRUB_CMDLINE_LINUX=\"${kernel_cmdline}\"/" /etc/default/grub echo "Status: New kernel cmdline: $(grep -e '^GRUB_CMDLINE_LINUX=' /etc/default/grub)" update-grub
Instala el agente de vBar
El agente de vBar es necesario para que funcione la red de interconexión entre chips (ICI).
Para extraer la imagen de contenedor del agente de vBar durante la creación de la imagen, ejecuta los siguientes comandos:
Autentica Docker con
gcr.io:gcloud auth configure-docker gcr.ioExtrae la imagen de Docker del agente de vBar:
docker pull gcr.io/cloud-tpu-v2-images/vbar_control_agent:0.0.3
Para aprender a configurar la imagen para que inicie el contenedor del agente de vBar en el momento del inicio, consulta Inicia el agente de vBar.
Opcional: Instala y ejecuta el recopilador de telemetría de IA
El recopilador de telemetría de IA se ejecuta dentro de la VM de TPU y te permite acceder a las métricas de infraestructura y del entorno de ejecución a través de Cloud Monitoring o de tu propia canalización de supervisión basada en Prometheus. Puedes usar el recopilador de telemetría de IA
con un SO personalizado usando la imagen de Docker ai-telemetry-collector. Puedes
instalar la imagen en tu SO personalizado y usar un archivo config.yaml para dictar
los intervalos de recopilación, habilitar o inhabilitar métricas específicas, o cambiar los
destinos de exportación.
Para instalar y ejecutar el recopilador de telemetría de IA, ejecuta los siguientes comandos:
Autentica Docker con
gcr.io:gcloud auth configure-docker gcr.ioExtrae la imagen de Docker del recopilador de telemetría de IA:
docker pull gcr.io/cloud-tpu-v2-images/ai-telemetry-collector:latestEjecuta un contenedor con la imagen de AI Telemetry Collector con la configuración predeterminada:
docker run -d --restart=always --privileged --net=host gcr.io/cloud-tpu-v2-images/ai-telemetry-collector:latestPara obtener información sobre cómo usar un archivo de configuración personalizado o agregar archivos de configuración adicionales, consulta AI Telemetry Collector.
Realiza modificaciones en el tiempo de inicio
Configura tu imagen para que realice las tareas de las siguientes secciones cada vez que se
inicie una VM. Puedes usar la herramienta
cloud-init para
configurar tareas de tiempo de inicio pasando metadatos a tus instancias. Las
configuraciones de las siguientes secciones usan módulos como
write_files
y
runcmd.
Los fragmentos que definen los archivos que se escribirán deben incluirse en la
clave write_files:, y los comandos que se deben ejecutar en el momento del inicio deben
incluirse en la clave runcmd: de tu configuración de cloud-init.
Inicia el agente de vBar
Inicia el contenedor del agente de control de vBar en el momento del inicio:
docker run -d --restart=always --privileged --net=host \
-e HOME=/home/tpu-runtime --name=vbar_control_agent \
gcr.io/cloud-tpu-v2-images/vbar_control_agent:0.0.3 \
vbar_control_agent_files/bin/vbar_control_agent --logtostderr
Configure las variables de entorno
Para asegurarte de que tu entorno se inicialice correctamente para las cargas de trabajo de TPU, debes
recuperar las variables de configuración del entorno de ejecución del servidor de metadatos de Compute Engine
durante el proceso de inicio del sistema. Para ello, agrega el siguiente fragmento a
la sección write_files: de tu configuración de cloud-init, que crea una
secuencia de comandos llamada /var/scripts/configure-env-vars.sh. Esta secuencia de comandos automatiza
la recuperación de atributos de la clave de metadatos tpu-env y los guarda en
/home/tpu-runtime/tpu-env para que los use la pila de software de TPU.
write_files:
- path: /var/scripts/configure-env-vars.sh
permissions: '0755'
owner: root
content: |
#!/bin/bash
grep -q CLOUDSDK_PYTHON /etc/environment || echo "CLOUDSDK_PYTHON=/usr/bin/python3" >> /etc/environment
export HOME=/home/tpu-runtime
mkdir -p "${HOME}"
curl -s 'http://metadata.google.internal/computeMetadata/v1/instance/attributes/tpu-env' -H 'Metadata-Flavor: Google' > /tmp/tpu-env.yaml
python3 -c '
import yaml
with open("/tmp/tpu-env.yaml", "r") as stream_in:
for k, v in (yaml.safe_load(stream_in) or {}).items():
print("{var}={value}".format(var=k, value=str(v)))
' > "${HOME}/tpu-env"
rm -f /tmp/tpu-env.yaml
set -a
source "${HOME}/tpu-env"
set +a
Obtén metadatos de VM
En el siguiente fragmento, se crea una secuencia de comandos llamada /var/scripts/get-vm-metadata.py,
una utilidad de Python para consultar de forma programática el servidor de metadatos en busca de atributos de instancia específicos
y etiquetas de metadatos personalizadas. Agrega lo siguiente a la
sección write_files: de tu configuración de cloud-init:
write_files:
- path: /var/scripts/get-vm-metadata.py
permissions: '0755'
owner: root
content: |
#!/usr/bin/env python3
import os
import sys
import requests
if len(sys.argv) < 2:
sys.stderr.write('Must provide key')
os._exit(1)
key = sys.argv[1]
default = None
if len(sys.argv) > 2:
default = sys.argv[2]
attribute_type = 'attributes'
if len(sys.argv) > 3:
attribute_type = sys.argv[3]
request = requests.get(
'http://metadata.google.internal/computeMetadata/v1/instance/{}/{}'.format(
attribute_type, key
),
headers={'Metadata-Flavor': 'Google'},
)
if request.status_code == 200:
print(request.text)
elif request.status_code in (403, 404):
sys.stderr.write('Metadata key: {} does not exist\n'.format(key))
if default:
print(default)
else:
sys.stderr.write('Lookup failed with: {}'.format(request))
Aumenta los tiempos de espera de Cloud Storage
Si tu carga de trabajo interactúa con Cloud Storage, aumenta la duración de los tiempos de espera
agregando valores de tiempo de espera a /etc/environment. Para ello, agrega el siguiente fragmento a la sección write_files: de tu configuración de cloud-init, que crea una secuencia de comandos llamada /var/scripts/configure-gcs-timeouts.sh.
write_files:
- path: /var/scripts/configure-gcs-timeouts.sh
permissions: '0755'
owner: root
content: |
#!/bin/bash
echo "GCS_RESOLVE_REFRESH_SECS=60" >> /etc/environment
echo "GCS_REQUEST_CONNECTION_TIMEOUT_SECS=300" >> /etc/environment
echo "GCS_METADATA_REQUEST_TIMEOUT_SECS=300" >> /etc/environment
echo "GCS_READ_REQUEST_TIMEOUT_SECS=300" >> /etc/environment
echo "GCS_WRITE_REQUEST_TIMEOUT_SECS=600" >> /etc/environment
Establecer la configuración de red
Para optimizar la capacidad de procesamiento y la latencia de la red en las VMs de TPU, agrega las siguientes
secuencias de comandos a la sección write_files: de tu configuración de cloud-init. En
las VMs TPU v6e y TPU7x, estas secuencias de comandos también habilitan la división de datos de TCP, aumentan
los límites del búfer de recepción de TCP y distribuyen las interrupciones de NIC en los núcleos de NUMA. Estas
secuencias de comandos requieren la secuencia de comandos /var/scripts/get-vm-metadata.py de la
sección Obtén metadatos de VM.
write_files:
- path: /var/scripts/configure-networking.sh
permissions: '0755'
owner: root
content: |
#!/bin/bash
ACCELERATOR_TYPE=$(/usr/bin/python3 /var/scripts/get-vm-metadata.py accelerator-type)
if [[ "$ACCELERATOR_TYPE" =~ ^v6e ]] || [[ "$ACCELERATOR_TYPE" =~ ^tpu7 ]]; then
echo "Enabling max rx buffer size for v6e, tpu7x & tpu7"
for port in $(ls /sys/class/net | grep ens); do
dhclient -r "$port"
if ethtool -h | grep -q tcp-data-split; then
if ethtool -G "$port" tcp-data-split on; then
echo "Max RX buffer size and TCP data split enabled for $port"
else
echo "Unable to enable max RX buffer size and TCP data split for $port"
fi
else
if ethtool --set-priv-flags "$port" enable-max-rx-buffer-size on; then
echo "Max RX buffer size enabled for $port"
else
echo "Unable to enable max RX buffer size for $port"
fi
fi
dhclient "$port"
done
else
echo "Skipping max rx buffer size for TPU generation $ACCELERATOR_TYPE before v6e"
fi
- path: /var/scripts/set_tcp_config.sh
permissions: '0755'
owner: root
content: |
#!/bin/bash
echo "Setting TCP config"
# Disable metrics cache
sysctl -w net.ipv4.tcp_no_metrics_save=1
# Disable slow start after idle
sysctl -w net.ipv4.tcp_slow_start_after_idle=0
# Set rto_min 5ms and enable quickack
sysctl_rto_min_exists=$(sysctl -a | grep tcp_rto_min_us)
if [[ -z "$sysctl_rto_min_exists" ]]; then
ip route show | while IFS= read -r route; do
if ! echo "$route" | grep -q "linkdown"; then
ip route change ${route/lock/} rto_min 5ms quickack 1
fi
done
else
sysctl -w net.ipv4.tcp_rto_min_us=5000
ip route show | while IFS= read -r route; do
if ! echo "$route" | grep -q "linkdown"; then
ip route change ${route/lock/} quickack 1
fi
done
fi
# Increase TCP zerocopy control memory
sysctl -w net.core.optmem_max=131072
# Disable Cubic Hystart Ack-Train
echo 2 > /sys/module/tcp_cubic/parameters/hystart_detect
ACCELERATOR_TYPE=$(/usr/bin/python3 /var/scripts/get-vm-metadata.py accelerator-type)
if [[ "$ACCELERATOR_TYPE" =~ ^v6e ]] || [[ "$ACCELERATOR_TYPE" =~ ^tpu7 ]]; then
# Increase TCP receive buffer limits
echo "4096 41943040 314572800" > /proc/sys/net/ipv4/tcp_rmem
fi
- path: /var/scripts/spread-nic-irqs.sh
permissions: '0755'
owner: root
content: |
#!/bin/bash
ACCELERATOR_TYPE=$(/usr/bin/python3 /var/scripts/get-vm-metadata.py accelerator-type)
if [[ "$ACCELERATOR_TYPE" == v6e* ]] || [[ "$ACCELERATOR_TYPE" == tpu7* ]]; then
node0_cores=$(echo /sys/devices/system/node/node0/cpu[0-9]* | wc -w)
ht_buddies=$(cat /sys/devices/system/cpu/cpu0/topology/core_cpus_list | tr ',' ' ' | wc -w)
total_schedulable_cores=$((node0_cores / ht_buddies))
second_numa_starting_core=${total_schedulable_cores}
first_numa_core=0
second_numa_core=${second_numa_starting_core}
for nic in $(ls -1 /sys/class/net); do
if [[ -d "/sys/class/net/$nic/device" ]]; then
NUM_QUEUES=$(echo /sys/class/net/"$nic"/queues/tx* | wc -w)
base_ntfy_block=$(ls -1 /sys/class/net/"${nic}"/device/msi_irqs | sort -n | head -n 1)
num_ntfy_blocks=$(ls /sys/class/net/"${nic}"/device/msi_irqs/ | wc -w)
tx_irq_base_directory=$((base_ntfy_block))
rx_irq_base_directory=$((base_ntfy_block + (num_ntfy_blocks / 2)))
core=0
max_core=${total_schedulable_cores}
nic_numa=$(cat /sys/class/net/"${nic}"/device/numa_node)
if [[ "${nic_numa}" -eq "1" ]]; then
core=${second_numa_core}
max_core=$((second_numa_starting_core + total_schedulable_cores))
else
core=${first_numa_core}
fi
for ((queue = 0; queue < $NUM_QUEUES; queue++)); do
echo $core > /proc/irq/$((tx_irq_base_directory + $queue))/smp_affinity_list
echo $core > /proc/irq/$((rx_irq_base_directory + $queue))/smp_affinity_list
cp /proc/irq/$((tx_irq_base_directory + $queue))/smp_affinity /sys/class/net/"$nic"/queues/tx-"$queue"/xps_cpus
core=$((core + 1))
if [[ $core -ge $max_core ]]; then
if [[ "${nic_numa}" -eq "1" ]]; then
core=${second_numa_starting_core}
else
core=0
fi
fi
done
if [[ "${nic_numa}" -eq "1" ]]; then
second_numa_core=${core}
else
first_numa_core=${core}
fi
fi
done
else
echo "Skipping NIC IRQ spreading for TPU generation $ACCELERATOR_TYPE before v6e"
fi
Ejecuta las secuencias de comandos de inicio
Para ejecutar las secuencias de comandos de configuración automáticamente cuando se inicia la VM, agrega una
sección runcmd: a tu configuración de cloud-init:
runcmd:
- /var/scripts/configure-env-vars.sh
- /var/scripts/configure-gcs-timeouts.sh
- /var/scripts/configure-networking.sh
- /var/scripts/set_tcp_config.sh
- /var/scripts/spread-nic-irqs.sh
¿Qué sigue?
- Obtén más información para crear una instancia de VM de TPU con tu imagen personalizada.
- Revisa las imágenes de SO de TPU disponibles.
- Obtén más información para administrar VMs de TPU.