Sobre otimização em aplicações .Net – Parte 1

Bom, acredito que nunca tenha postado algo específico do meu trabalho.

Um dos motivos para isso seria que parte das coisas que faço são muito sensíveis para compartilhar.

Mas esse final de semana comecei um projeto do zero para identificar e otimizar o Kenshi Mod Manager (KMM) do jogo Kenshi, porque isso vai me deixar exercitar as tarefas que preciso em meu trabalho e o risco é mais controlado.

Resumidamente o gerenciador tem vários recursos, mas quando desenvolvi há cerca de um ano, haviam problemas sérios de performance, bom… não pro meu pc, mas pra quem utiliza.

Tenho cerca de 300+ mods, e indexar os conflitos nele causam ~1GBs e um tempo considerável pra apresentar as falhas

Como que comecei a análise

O KMM é um WPF em .Net Core 3.1 e eu acho realmente muito trabalhoso analisar cada parte do código sem ter uma ferramenta externa, já que o projeto já passou de 5K de linhas..

Então já que eu precisava estudar gRPC iniciei primeiro criando dois projetos, um server e um client.

sendo que o server está no KMM e o client em um console no MMDHelpers.

A alteração no KMM foi muito simples, bom … já que ele não era uma aplicação web, eu apenas subi o kestrel.

Uma observação, neste webserver que eu estou subindo, estou ignorando a parte de segurança completamente, já que irei identificar os problemas, remover o pacote e disponibilizar a nova versão.

Com o Client eu pude enviar comando para iniciar ou terminar as métricas no KMM

https://gist.github.com/millerscout/e9228ffe5f61edf9f151cab3aa61dbf7
Simples não?

o resultado foi este:

Eu consigo observar quantas coletas em Gen0-2, a quantidade de memória e o tempo que levou.

o tempo aqui não é meu foco ainda, mais para abaixo explico uma otimização para tempo (mas é tiro de canhão pra matar mosca)

Primeiro Passo

Particularmente eu tento quebrar os problemas mais complexos para o mais simples possível, e existe um item que não tinha nenhuma coleta no GC mas era o primeiro item que eu queria otimizar

Temos aqui o cenário:

https://gist.github.com/millerscout/a628f32fb4edd9d710c0fbb6c2b775ff

O código nem causa problema, afinal só estou usando o IO.Path.GetExtension e comparando se o arquivo está naquela extensão.

então tinha duas opções:

  • Usar String.EndsWith
  • Criar o meu EndsWith

Ainda estou encontrando formas de pegar o código base do c# pra remover alguns recursos que não preciso validar, ganhando tempo de processamento.

Em minha solução eu achei mais fácil iterar uma string do final pro começo, levando em conta que se qualquer char for diferente ele retorna false,

o código ficou desse jeito:

https://gist.github.com/millerscout/879956f6a0038330992827d09fedd429

A única coisa que faltou foi um benchmark certo?

então tá ai:

https://gist.github.com/millerscout/52f6e56a64faa3658e7e6958c1261b29

não apenas descartei o EndsWith de string, como percebi que minha versão é mais eficiente pro problema um ganho de 69% de performance, se este problema estivesse em um cenário de 4M de iterações o ganho seria de 195.16ms para 60.44ms, Bom depende muito do cenário né? mas… é algo á se pensar quando for otimizar, aqui nem usei o Princípio de Pareto, só foi pra brincar mesmo.


Pontos de atenção:
no meu cenário não preciso verificar se a string é case-sensitive ou possui acentos.

Segundo Passo


Fiz uma dúzia de alterações simples:

  • Parei de usar List para um array pequeno onde eu não precisava fazer nada apenas conter a lista.
  • Alterei algumas classes para structs pois as classes eram imutáveis e também não há risco de cópia em memória delas.
  • adicionei o capacity em algumas até o momento onde revisei

O que seria dar essa lista sem o commit não é mesmo? segue ai:

https://github.com/millerscout/Kenshi-Mod-Manager/commit/7f9ef386bdcb902ed3a168afac8eaaa23babf4c1

o resultado foi bem promissor:

Gen 0: 990 redução de 18% comparando com 1217 anteriormente
Gen 1: 284 redução de 31% comparando com 351 anteriormente
Gen 3: 28 aumento de 16% comparando com 24 anteriormente

Primeira parte encerrada aqui.

Você pode continuar lendo a Parte 2

Conclusão

Ainda há um longo caminho de aprendizado e técnicas para aprimorar minha capacidade de fine-tuning em .Net, mas acredito que o resultado mostra que não é rocket science, apenas precisamos nos policiar em coisas simples para trazer um ganho maior.

Créditos

Acredito que essa minha vontade de otimização não seriam possíveis caso as conversas com o @crocco @Massato não tivessem acontecido.

Eu tive também alguns materiais para me inspirar e aprender, bem como algumas referências, sendo elas:

o tio Scott, Elemar Jr. e Konrad Kokosa

Estive consumindo vários artigos da Eximia.Co, documentações da própria microsoft em momentos específicos os seguintes itens:

Sneak Peek

Próximo post gostaria de experimentar mais sobre sobre warmup em .Net, comecei ler algumas coisas, assim que tiver algo conclusivo trago para compartilhar 🙂

Enfim 30!

Estou aproveitando que amanhã é feriado (pra mim)

Bom, eu tentei dormir, mas estou há dois dias estive pensando nesse post, hoje eu consegui pegar o fio da meada enquanto estava olhando pra minha esposa toda linda dormindo.

eu não durmo mesmo, não tenho tanta necessidade. acredito que daqui uma hora (agora:00:25) eu vou ter sono, até lá tenho tempo pra escrever 😀

Pra mim é estranho, ontem eu estava brincando com meus brinquedos, pensando no futuro, imaginava como seria ter 30 anos, ser sábio ou algo assim.

Mais estranho ainda quando paro pra pensar quanta “sabedoria” eu já ouvi na vida, acho que deve ocorrer com todo mundo,
algumas dessas “sabedorias” me feriram, outras eu guardei na gaveta do coração,só pra poder fazer a pessoa engolir o que disse, outras eu simplesmente ignorei.

Alguns exemplos:

  • Você é fogo de palha, não foca em nada.
  • Você precisa tomar alguma ação, você só está esperando as coisas acontecerem.
  • Você não é programador, só altera variáveis.
  • Se eu te der R$ 10k, você não vai conseguir pagar um carro.
  • Tens de mudar de emprego, você tá perdendo seu tempo.
  • Deixar a faculdade foi o maior erro da sua vida.

Eu lembro que começei esboçar um planejamento lá pros meus 11-12 anos, quando eu começei brincar de “programar”,
eu tinha objetivos bem claros.

sempre que dava uma “merda” na vida eu me replanejava como podia, triste os adultos não conversarem disso com as crianças, meus pais não tiveram culpa, casaram muito jovens, iam ensinar o quê? nem eles sabiam o que estavam fazendo.

Como uma ótima pessoa introspectiva eu preferia não compartilhar meus objetivos… afinal eu já tinha ouvido tanto “você é fogo de palha”, que eu também achava que esse planejamento iria pras cucuias.

eu me planejei com poucas coisas até meus 30:

  • fazer faculdade.
    • eu iniciei, mas não tive dinheiro terminar, essa tem um post aparte…
  • ser um profissional único, pra poder ter e manter-me em um bom emprego ( acredito que ainda não escrevi o motivo, mas meus pais passaram muito aperto da vida, e eu não queria que minha família/filhos sofressem)
    • eu acho que não sou o melhor, mas percebo que mais resolvo problemas que causo, então tá bom..
  • conhecer alguém e morar junto com essa pessoa antes dos meus 30.
    • eu não conheci alguém, eu encontrei minha alma gêmea, é bem legal que eu encontrei alguém que não chega nem perto do que eu queria, mas é perfeita pra mim, uma pessoa amável, calma, sincera, emotiva, dedicada, empática e a lista não para…
  • ser independência, independência é muito abstrato, mas na minha visão era independência emotiva
    • essa eu aprendi cedo, desde quando minha mãe se divorciou eu comecei mais e mais calado, com objetivo em mente, eu já não precisava de “guia”
    • a vida me levou pra independência financeira também (não sou rico, mas se acabar ficando desempregado, dá tempo de procurar trabalho)
  • saber dirigir com meus 18
    • se eu não tinha dinheiro pra faculdade… se acha que eu tinha pra tirar habilitação?
  • sair da casa de meus pais assim que ter um emprego. (eu era muito inocente)…
    • eu conheci bem mais rápido que esperava, claro que tive alguns atalhos, mas consegui.

Por fim eu consegui cumprir com maior parte desse planejamento, parece que planejei minuciosamente tudo, na verdade não, mas fui me adaptando e errando menos conforme fui aprendendo mais da vida.

hoje, mais velho acho consigo responder cada uma das frases que ouvi, e a melhor parte?
eu não devo nada pra ninguém, conquistei aos poucos, sem pressa, e com total apoio de minha mãe,
tinha decisão que foi mais loucura que tudo, mas ela sempre deu apoio e dizendo: “vai, eu confio em você, não liga pros outros, de fome não morremos, mas se morrer estamos salvos pela graça, vamos pro céu”, essa frase dela pra mim é morbidamente boa,

Eis minhas respostas:

  • Você é fogo de palha, não foca em nada.
    • ainda bem… Eu aprendi tanta coisa e experimentei tanto, que aprender novas coisas e tomar decisões se tornaram triviais pra mim
  • Você precisa tomar alguma ação, você só está esperando as coisas acontecerem.
    • não, eu gosto de estar preparado pra quase todas as oportunidades que aparecem, enquanto elas não aparecem eu fico me preparando mais,
      eu não me frusto por estagnar por um tempo pra me preparar, mas eu fico muito mal caso apareça uma oportunidade e eu não estiver pronto.
  • Você não é programador, só altera variáveis.
    • essa eu nem respondo, só trás o problema, e vamos ver em quanto tempo eu resolvo :p
  • Se eu te der R$ 10k, você não vai conseguir pagar um carro.
    • (essa me doeu), o problema pra mim nunca foi a entrada do carro, sempre foi o “pós-venda”, comprar um carro não é só comprar um carro, é um filho, tem manutenção, revisão, seguro, combustível,
      eu aprendi o preço da falta de planejamento quando tive de deixar a faculdade, pra mim eu sou sozinho, não tenho ninguém pra me dar backup, na verdade eu sou o porto-seguro de algumas pessoas, por isso eu sou sozinho e tenho que me garantir,
      já que não tenho mamãe e papai, familiar pra me dar uma ajuda e nem fodendo eu pego empréstimo na minha vida exceto por falta de opção.
  • Tens de mudar de emprego, você tá perdendo seu tempo.
    • só porque passei 6 anos e 6 meses em uma empresa onde eu não recebia o merecido, não significa que estou perdendo meu tempo,
      na verdade eu considerei que estive fazendo faculdade nesse processo e ainda ganhava pelas merdas que eu fazia, o aprendizado foi tanto que eu sou um profissional fora da curva (segundo feedbacks)
  • Deixar a faculdade foi o maior erro da sua vida.
    • pode ter sido, mas faculdade é só um dos meios de abrir portas e adquirir conhecimento, e eu aprendi tanto com o que a faculdade ensina como também planejamento financeiro.

acho que está de bom tamanho essa foi a parte 1 O.o

vou acabar pegando esses meus posts e migrar pra um blog de capsula do tempo, eu gosto muito de ler eles depois de um tempo e perceber quanto minha forma de sintetizar um texto ou a forma que eu pensava mudou.

eu quase acertei (agora: 02:20) me deu sono, então depois eu reviso…

Leben – Day 36

Estive descansando um pouco do Leben, mas hoje tive vontade de voltar desenvolver.

Hoje estive adicionando um processo de propagação de arbustos, encontrei vários erros no Core do Leben que estavam ignorando o timer dos eventos, depois de corrigir todos, agora sei que é mais difícil ter um memory-leak tão rápido, mas ainda há muito trabalho nessa parte.

Primeiro porque um objeto está sendo Spawnado em cima de outro, e não existe um limite de Arbustos na região, então eles se propagam indefinidamente e isso é um problema, ainda não pensei em como limitar, talvez por nutrientes no solo… mas ainda não sei.

Como sempre um gif pra mostrar o comportamento.

Só pra manter o Blog ativo.

Bom, eu gosto de escrever pro meu blog,

Estou sem desenvolver no Leben, dá um pouco de preguiça e existe muitos projetos que quero fazer e ainda preciso me distrair pra manter a sanidade.

estive jogando Raft, mindustry, this war of mine e autonauts.

Mas principalmente estou dando suporte á minha ferramenta para gerenciar mods pro jogo Kenshi

Conforme ela está crescendo percebo como é legal ajudar outras pessoas gerenciar seus mods e melhorar a experiência de um jogo tão legal, por isso vou continuar melhorando ela.

bom era isso, só queria postar algo mesmo

:p

Leben – Day 35

Fiquei descansando um pouco do projeto, acabei Jogando Days gone, demorei um pouco mais pois acabei mudando de computador e instalar os requisitos para desenvolver no notebook.

Então agora que pude começar desenvolver um pouco com a AI.

mas não consegui produzir muito.

então é isso :p

Leben – Day 34

Como havia dito ontem precisava separar mais as responsabilidades da AI, estive com uma dificuldade enorme de conseguir compreender como fazer a AI, até que percebi que meu problema era tentar deixar complexo tarefas simples, assim que eu simplifiquei o meu pensamento e como efetivamente acontece as coisas consegui produzir, muito bem por sinal.

Ontem e hoje estive fazendo alguns exercícios mentais pra escrever o que precisava na AI, também mostrei pra minha esposa como estou fazendo isso, é bom ver que ela vem tentar entender essa loucura, ao explicar pra ela, entendo melhor o que devo fazer.

Bom é isso, sem prints ou gifs hoje.

That’s all Folks!

Leben – Day 33

Depois de pensar bastante na estrutura que tinha e separar algumas coisas.

Foi iniciado a parte de AI Muito básica ainda, mas já dá pra ver algo:

Explicando o que tem no vídeo.

primeiro o npc está aguardando “sentir” fome, procura um arbusto mais próximo, e fica tentando comer ele, é quando o arbusto começa dar fruto e ele finalmente “come”.

ainda preciso separar todas as sequências e estados de cada tarefa, mas já é um começo.

Leben – Day 32

Hoje não foi tão produtivo,

estou implementando a AI nos npcs, ainda estou absorvendo os postsde referência.

Bom em resumo eu havia feito um código lá em meados de 2016, que já tem alguma base da AI,

Que cada entidade possui uma Entidade, e dela uma lista de tarefas.

Hoje essa estrutura mudou.

E agora essas tarefas são na verdade eventos que são pré-configurados com timeout que quando invocados algo determinado acontece.

Algo como:

HungerTick (1seg) > evento de subtrair o valor da fome.
TirenessTick (1seg) > evento de subtrair o valor da Cansaço.
ThirstTick (1seg) > evento de subtrair o valor da Sede.

acredito que ainda vou ter de pensar em uma forma de integrar a inteligência artificial, para tomar uma decisão e deixar uma tasklist.

Penso em algo parecido como The Sims, acho muito agradável essa idéia.

mas por enquanto não é um roadmap, estou desenvolvendo e descobrindo o que é Leben.

Hoje não tem update do Leben :x

Também tenho outros projetos.

hoje recebi um comentário no meu youtube de um mod manager que eu havia feito, era uma pessoa com dificuldade, então enquanto estava respondendo ele de como fazer funcionar e percebi que havia outro vídeo explicando como minha ferramenta funcionava, fiquei bem feliz e orgulhoso.

Então parei um pouco pra dar um update no Leben, só pre adicionar alguns recursos no mod manager.

ah! o manager é pro jogo Kenshi, por enquanto parei um pouco de jogar, mas é muito bom, um dos jogos que mais joguei no Steam.

Leben – Day 31

Bom…

Li bastante conteúdo e não… eu não li o livro inteiro ou todo conteúdo que postei recentemente, pois estou procurando técnicas, mas achei outros conteúdos bem pertinentes.

Encontrei esse post: Coffee Brain Studios – Finite State Machine vs Behaviour Tree, A True Story.

o que me chamou atenção é: eu pensei usar Finite State Machine (FSM), mas Behaviour Tree (BT), mas quero deixar a AI Complexa, independente e Extensível, pra isso acredito que terei de tomar a mesma decisão, implementar minha própria Behaviour Tree.

Gostei bastante desta implementação: Libgdx-AI,A Conclusão é interessante, mas a explicação extensa é de grande valia pra mim.

continuarei pensando

inté.