Grupos de execução

Reportar um problema View source Nightly · 8.1 · 8.0 · 7.5 · 7.4

Os grupos de execução permitem várias plataformas de execução em um único destino. Cada grupo de execução tem suas próprias dependências de toolchain e executa a própria resolução de toolchain.

Contexto

Os grupos de execução permitem que o autor da regra defina conjuntos de ações, cada um com uma plataforma de execução potencialmente diferente. Várias plataformas de execução podem permitir que as ações sejam executadas de maneira diferente, por exemplo, compilando um app iOS em um worker remoto (Linux) e vinculando/assinando o código em um worker local do Mac.

A capacidade de definir grupos de ações também ajuda a aliviar o uso de mnemônicos de ação como um substituto para especificar ações. Não há garantia de que os mnemônicos sejam únicos e eles só podem referenciar uma única ação. Isso é especialmente útil para alocar recursos extras para ações específicas de memória e processamento como a vinculação em builds C++ sem alocar demais para tarefas menos exigentes.

Como definir grupos de execução

Durante a definição de regras, os autores podem declarar um conjunto de grupos de execução. Em cada grupo de execução, o autor da regra pode especificar tudo o que for necessário para selecionar uma plataforma de execução para esse grupo, ou seja, qualquer restrição usando exec_compatible_with e tipos de conjunto de ferramentas usando toolchain.

# foo.bzl
my_rule = rule(
    _impl,
    exec_groups = {
        link: exec_group(
            exec_compatible_with = [ "@platforms//os:linux" ]
            toolchains = ["//foo:toolchain_type"],
        ),
        test: exec_group(
            toolchains = ["//foo_tools:toolchain_type"],
        ),
    },
    attrs = {
        "_compiler": attr.label(cfg = config.exec("link"))
    },
)

No snippet de código acima, é possível ver que as dependências de ferramentas também podem especificar a transição de um grupo de execução usando o parâmetro de atributo cfg e o módulo config. O módulo expõe uma função exec que usa um único parâmetro de string, que é o nome do grupo de execução para o qual a dependência precisa ser criada.

Como nas regras nativas, o grupo de execução test está presente por padrão nas regras de teste do Starlark.

Acessar grupos de execução

Na implementação da regra, é possível declarar que as ações precisam ser executadas na plataforma de execução de um grupo de execução. Para isso, use o parâmetro exec_group de métodos de geração de ações, especificamente ctx.actions.run e ctx.actions.run_shell.

# foo.bzl
def _impl(ctx):
  ctx.actions.run(
     inputs = [ctx.attr._some_tool, ctx.srcs[0]]
     exec_group = "compile",
     # ...
  )

Os autores de regras também poderão acessar as toolchains resolvidas dos grupos de execução, de forma semelhante a como você pode acessar a toolchain resolvida de um destino:

# foo.bzl
def _impl(ctx):
  foo_info = ctx.exec_groups["link"].toolchains["//foo:toolchain_type"].fooinfo
  ctx.actions.run(
     inputs = [foo_info, ctx.srcs[0]]
     exec_group = "link",
     # ...
  )

Grupos de execução padrão

Os seguintes grupos de execução são predefinidos:

  • test: ações do Test Runner, disponíveis em todas as regras de teste.
  • cpp_link: ações de vinculação do C++.

Como usar grupos de execução para definir propriedades de execução

Os grupos de execução são integrados ao atributo exec_properties que existe em todas as regras e permite que o gravador de destino especifique um dicionário de string de propriedades que é transmitido para a máquina de execução. Por exemplo, se você quiser definir alguma propriedade, como memória, para o destino e atribuir a algumas ações uma alocação de memória maior, grave uma entrada exec_properties com uma chave de execução ampliada, como:

# BUILD
my_rule(
    name = 'my_target',
    exec_properties = {
        'mem': '12g',
        'link.mem': '16g'
    }
    
)

Todas as ações com exec_group = "link" mostrariam o dicionário de propriedades de execução como {"mem": "16g"}. Como você pode ver aqui, as configurações no nível do grupo de execução substituem as configurações no nível da segmentação.

Usar grupos de execução para definir restrições de plataforma

Os grupos de execução também são integrados aos atributos exec_compatible_with e exec_group_compatible_with que existem em cada regra e permitem que o gravador de destino especifique outras restrições que precisam ser atendidas pelas plataformas de execução selecionadas para as ações do destino.

Por exemplo, se a regra my_test definir o grupo de execução link, além do padrão e do grupo de execução test, o uso desses atributos vai executar ações no grupo de execução padrão em uma plataforma com um grande número de CPUs, a ação de teste no Linux e a ação de link na plataforma de execução padrão:

# BUILD
constraint_setting(name = "cpu")
constraint_value(name = "high_cpu", constraint_setting = ":cpu")

platform(
  name = "high_cpu_platform",
  constraint_values = [":high_cpu"],
  exec_properties = {
    "cpu": "256",
  },
)

my_test(
    name = "my_test",
    exec_compatible_with = ["//constraints:high_cpu"],
    exec_group_compatible_with = {
        "test": ["@platforms//os:linux"],
    },
    ...
)

Grupos de execução e propriedades de execução da plataforma

É possível definir exec_properties para grupos de execução arbitrários em destinos de plataforma. Ao contrário de exec_properties definido diretamente em um destino, em que as propriedades de grupos de execução desconhecidos são rejeitadas. Em seguida, os alvos herdam o exec_properties da plataforma de execução que afeta o grupo de execução padrão e outros grupos de execução relevantes.

Por exemplo, suponha que a execução de testes na plataforma de execução exija que algum recurso esteja disponível, mas não seja necessário para compilação e vinculação. Isso pode ser modelado da seguinte maneira:

# BUILD
platform(
    name = "exec_platform",
    exec_properties = {
        "test.resource": "...",
    },
)

cc_test(
    name = "my_test",
    srcs = ["my_test.cc"],
)

O exec_properties definido diretamente nos destinos tem precedência sobre os que são herdados da plataforma de execução.