Multi-plataforma multi-threading: Quais são os desafios reais?

21

Embora uma biblioteca como SDL forneça uma API de wrapper de plataforma cruzada para threading, acho que seria ingênuo supor que isso leva diretamente ao fácil desenvolvimento de jogos em plataformas muito diferentes (desktop / celular).

Qual é a melhor maneira de enfrentar o desenvolvimento dessa maneira (considerando qualquer API de encadeamento de plataforma cruzada), considerando o seguinte:

  • diferentes números de núcleos
  • capacidades de processamento muito diferentes por núcleo
  • Uma arquitetura de sistemas geralmente diferente com, por exemplo. latências diferentes para acesso a cache, RAM e E / S

Tenho a sensação de que a única maneira de fazer isso é avaliar quantos threads podem ser executados por cada dispositivo que você pretende oferecer suporte e descobrir qual é o menor denominador comum. No entanto, isso ainda me deixa no escuro quanto à quantidade total de taxa de transferência de processamento disponível. Estou certo ao supor que a única maneira de fazer isso efetivamente é desenvolver ativamente o dispositivo móvel de menor especificação que pretendo oferecer suporte ao longo do desenvolvimento? - ou seja, o menor denominador comum? Se isto aproximadamente ser suficiente? Ou há mais do que isso?

Edição: Por favor, outras pessoas poderiam oferecer mais experiência sobre isso, pois eu não acho que minha pergunta tenha sido respondida completamente ainda.

Engenheiro
fonte
Como minha resposta não responde totalmente à sua pergunta, você pode detalhar o que está faltando / o que você quer saber? Posso não ser um grande escritor, mas lidei com esse tipo de problema mais de uma vez.
Valmond
Você realmente não respondeu à pergunta, que tratava de dificuldades de multithreading e como superá-las ao desenvolver para plataformas com diferentes recursos de threading . Veja meu parágrafo abaixo dos pontos de bala. Você fala sobre tamanhos e resoluções de tela - eles não têm nada a ver com a minha pergunta - leia o título.
Engenheiro
1
Eu acho que a dificuldade vem do que você deseja usar os tópicos. Uma coisa é ter um encadeamento auxiliar fazendo algo ao lado, e completamente outro para tentar extrair os últimos bits de desempenho de uma máquina com 8 núcleos. Na minha opinião, os encadeamentos SDL destinam-se principalmente ao primeiro, não o último.
Jari Komppa

Respostas:

11

Você fala sobre "dificuldades de multithreading", mas de quais dificuldades você está realmente falando? De certa forma, você está citando um problema fantasma que pode até nem existir. O verdadeiro desafio que você faz para si mesmo - se você está absolutamente determinado a obter toda a última gota de energia de um pedaço de hardware, isso envolve o uso do hardware para obter o melhor efeito, mas também amplia a brecha entre a máquina mais poderosa e o menos poderoso. A implicação disso é que, se você tem um jogo que realmente aproveita ao máximo um PS3 (por exemplo), não é possível executá-lo em um celular barato de qualquer maneira, então seu problema não é mais "como posso obter um programa?" para trabalhar com hardware muito diferente ", mas torna-se" como posso implementar uma ideia de jogo de várias maneiras diferentes, para que funcione em hardware com alimentação diferente ".

Embora uma biblioteca como SDL forneça uma API de wrapper de plataforma cruzada para threading, acho que seria ingênuo supor que isso leva diretamente ao fácil desenvolvimento de jogos em plataformas muito diferentes (desktop / celular).

Fácil desenvolvimento de jogos - com certeza. Multithreading ideal, não. Mas você não precisa de multithreading para criar jogos. Para criar peças de alto desempenho, certamente ajuda. Mas muitos jogos excelentes rodam em um único segmento.

Qual é a melhor maneira de enfrentar o desenvolvimento dessa maneira (considerando qualquer API de encadeamento de plataforma cruzada), considerando o seguinte:

  • diferentes números de núcleos
  • capacidades de processamento muito diferentes por núcleo
  • Uma arquitetura de sistemas geralmente diferente com, por exemplo. latências diferentes para acesso a cache, RAM e E / S

Em vez de tentar atribuir sistemas a threads, atribua tarefas a threads. Forneça a cada tarefa os dados necessários para executar e faça o farm das tarefas para o hardware disponível. Normalmente, você terá algum tipo de conjunto de encadeamentos para abstrair os vários núcleos ou processadores, e um gerenciador de tarefas que possui uma fila de tarefas e os produz até os vários encadeamentos quando o encadeamento sinaliza que concluiu a tarefa anterior e está pronto para um novo. O hardware com mais núcleos obviamente concluirá as tarefas mais rapidamente e poderá renderizar mais rapidamente. A especialização desse sistema para funcionar de maneira ideal em sistemas com características diferentes torna-se um problema de otimização avançado, mas pode ser baseado em certas heurísticas (por exemplo, uma tarefa que não é necessária).

No entanto, a decomposição dos recursos do jogo em tarefas discretas é um assunto bastante complexo e geralmente não vale a pena, a menos que você tenha certeza de que precisa do desempenho, para que a maioria nem tente.

Algumas leituras adicionais:

http://www.gamasutra.com/view/feature/1830/multithreaded_game_engine_.php - consulte a seção 'paralelo de dados'. Com esse modelo, os dados são divididos em várias tarefas idênticas e gerados em threads individuais.

http://software.intel.com/en-us/articles/designing-the-framework-of-a-parallel-game-engine/ - bastante denso, descreve as coisas no nível do sistema operacional e não no nível do jogo.

http://drdobbs.com/high-performance-computing/216500409 - não específico do jogo, mas completamente relevante em termos de como você precisa dividir as tarefas.

http://www.itfgaming.com/news/tech-focus-crysis-2-and-the-future-of-cryengine-3 - no meio desta entrevista, há uma anedota sobre como eles migraram para um sistema baseado em tarefas .

Kylotan
fonte
Muito bons pontos. E verdade, usei a palavra "dificuldades" quando "desafios" seriam mais precisos. Você disse: "A decomposição dos recursos do jogo em tarefas discretas é uma questão bastante complexa e geralmente não vale a pena, a menos que você tenha certeza de que precisa do desempenho, para que a maioria nem tente". Você pode elaborar sobre isso? Fornecer fontes? É um pouco vago, mas eu diria que você está chegando ao cerne da questão.
Engenheiro
Desculpe, pensei que esse tipo de abordagem era bem conhecido. Vou elaborar a resposta.
Kylotan
4

Quando eu fiz jogos para dispositivos móveis, desenvolvemos uma versão 'ouro' (ou seja, um jogo totalmente funcional) e depois a dividimos em três versões principais (tela grande, tela média e tela pequena). Estes foram posteriormente convertidos em 11 versões: gráficos exigentes (a leitura requer muita memória / CPU) versus baixo perfil etc. (havia também algumas versões especiais da plataforma).

O maior problema foi (esse era o meu trabalho, entre outros) isolar as plataformas necessárias e determinar essas versões e como criá-las (por exemplo: tela grande, mas baixo perfil deve ser uma versão desclassificada de tela grande / oi perfil ou deve ser tela de tamanho médio / lo perfil feito tela grande?).

É claro que codificamos com isso em mente, de modo que os jogos eram muito pouco atrelados ao tamanho da tela.

HTH

[editar] O que eu quis dizer foi que você precisa dividir suas plataformas de destino em diferentes qualidades (por exemplo, 1 núcleo, 2 núcleos, 1 núcleo, mas duas vezes mais rápido ...) Depois, decida quantos destinos virtuais você deseja (por exemplo " only one "or" Low, Mid, Hi ") Em seguida, coloque todas as plataformas em sua respectiva 'qualidade' e para Cada qualidade, pegue o menor denominador e 'port' o código para que atenda a esses requisitos (ou seja, funciona e é rápido suficiente).

Pode parecer que você deve fazer isso com muita adivinhação, mas já pode encontrar a pior qualidade com a pior plataforma. Eu escolheria cada próxima qualidade pelo menos "duas vezes melhor" que a anterior, isso provavelmente não geraria mais do que dizer 3-4 "qualidades". Se o código for portado a partir de uma versão gold, qualquer plataforma que não tenha um desempenho bom o suficiente poderá ser retrograda para uma "qualidade" mais baixa para acelerar. Qualquer nova plataforma também pode ser facilmente colocada na qualidade certa.

Valmond
fonte
Em primeiro lugar, quanto tempo você diria que o projeto teve nas fases de design e desenvolvimento para acomodar uma versão multiplataforma como esta? Apenas uma média aproximada ajudaria.
Engenheiro
1
Bem, como fizemos em vários idiomas (inglês, francês, espanhol, português, alemão e italiano em um pacote + qualquer idioma necessário por dia, taiwanês, turco, russo ...) e tínhamos novas plataformas para "portar" todos os nossos jogos a cada poucos meses (leia uma nova classe de celulares), na verdade teríamos perdido muito tempo não indo dessa maneira, seria realmente impossível na verdade sem um tempo realmente grande. O design da 'estrutura' foi executado rapidamente, enquanto eu aprendia sobre diferentes celulares e chegava à maturidade depois de talvez 3-4 anos. Um investimento que vale a pena.
Valmond
1

Tenho a sensação de que a única maneira de fazer isso é avaliar quantos threads podem ser executados por cada dispositivo que você pretende oferecer suporte e descobrir qual é o menor denominador comum.

Não necessariamente - pode haver esperança de uma solução mais dinâmica, mas isso depende do problema real que você está tentando resolver (se houver). Você é um pouco vago em sua pergunta, então minha resposta também deve ser vaga.

Se o agrupamento de plataformas em que você pretende executar tiver a capacidade de enumeração de hardware por meio de uma API, você poderá usar essa interface para detectar o número máximo de encadeamentos que o sistema pode manipular e usá-lo como base para quantos encadeamentos seu aplicativo deve criar. O único desafio aqui é encontrar essas APIs; se você acessa ou não o nível do sistema operacional, procura uma biblioteca de terceiros ou um SDK / API de plataforma cruzada, depende de você e depende das plataformas que você está tentando oferecer suporte.

Qual é a melhor maneira de lidar com o desenvolvimento dessa maneira (considerando qualquer API de segmentação de plataforma cruzada), considerando o seguinte:

different numbers of cores
vastly different processing capabilities per core
A generally different systems architecture with eg. different

latências para acesso a cache, RAM e E / S

Na minha opinião, nenhuma dessas coisas deveria ser sua preocupação. Sua preocupação deve estar construindo seu jogo. Se você encontrar um gargalo e decidir que seria melhor gerar um encadeamento separado para uma tarefa específica de uso intensivo do processador, crie o encadeamento e deixe o SO e outro software de nível inferior decidir como manipular o hardware para lidar com o encadeamento.

Cifra
fonte