RESPOSTA: Por que o depurador não respeita meu breakpoint?

Em um post anterior, questionei o porquê do depurador, no código indicado na figura que segue, em Release, não estar respeitando um breakpoint.

IMPORTANTE: O modo release não é indicado para depuração. Em modo Release, o compilador implementa otimizações (eliminação de código inútil, inlining, etc..) que impedem, em muitos cenários, a correlação entre o código que está rodando e o código que escrevemos.

A resposta simples e direta para o “problema”, no meu caso, foi  uma otimização implementada pelo JIT chamada inlining.

IMPORTANTE: O comportamento que observei pode variar em diferentes ambientes operacionais, configurações no Visual Studio e versões do .NET.

O que é Inlining?

Trazendo a resposta da Wikipedia:

In computinginline expansion, or inlining, is a manual or compiler optimization that replaces a function call site with the body of the called function. […]

Inlining is an important optimization, but has complicated effects on performance.[1] As a rule of thumb, some inlining will improve speed at very minor cost of space, but excess inlining will hurt speed, due to inlined code consuming too much of the instruction cache, and also cost significant space.

Em .NET, o JIT aplica inlining em determinados cenários com vistas a melhorar a performance, quando o código assembly é gerado. Ou seja, não ocorre quando o IL é gerado, mas somente no tempo de execução.

Relação de Inlining com o “problema”

Em minha ambiente, o JIT havia optado por fazer inlining de um dos meus métodos, mas não de outro. Daí o motivo de não haver a parada em um dos métodos – o “método” não existia no assembly.

Como “recomendar” ou negar inlining ao JIT

Em .NET, podemos “sugerir” ao JIT sobre fazer inlining, ou não, de nosso código.

using System;
using System.Runtime.CompilerServices;

public class Program
{
    public static void Main()
    {
        string s = "Elemar Jr";
        PrintAllChars(s);
        PrintAllChars_(s);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static void PrintAllChars(string s)
    {
        foreach (var c in s)
        {
            Console.WriteLine(c);
        }
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static void PrintAllChars_(string s)
    {
        for (int i = 0; i < s.Length; i++)
        {
            Console.WriteLine(s[i]);
        }
    }
}

A utilização do atributo MethodImpl com o parâmetro AggressiveInlining sugere fortemente ao compilador que ele deve implementar Inlining. Por outro lado, o parâmetro NoInlining garante que o JIT não execute a otimização.

Geralmente, não é necessário que influenciemos o JIT nesse aspecto. Entretanto, em cenários críticos, indicar inlining pode ter impacto crítico na performance.

Medindo impacto de inlining na performance

O código que segue mostra uma comparação entre métodos onde ocorre inlining e onde não ocorre.

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Runtime.CompilerServices;

public class Program
{
    static void Main()
    {
        BenchmarkRunner.Run<Program>();
    }

    [Benchmark]
    public int Inlining()
    {
        return WithInlining(2) + WithInlining(3);
    }

    [Benchmark]
    public int Calc_Mixed()
    {
        return WithInlining(2) + WithoutInling(3);
    }

    [Benchmark]
    public int NoInlining()
    {
        return WithoutInling(2) + WithoutInling(3);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static int WithInlining(int value)
    {
        return value;
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private static int WithoutInling(int value)
    {
        return value;
    }
}

Resultados:

No exemplo, o método que usou apenas métodos forçando Inlining foi muito mais rápido. Isso pode ser facilmente entendido olhando o assembly gerado para ele:

mov eax, 5
ret

Não há chamada para método algum. Além disso, o JIT também é inteligente o suficiente para eliminar a adição. Afinal, são duas contantes.

O método que chama um método com inlining e outro sem inlining tem alguma penalidade de performance.

sub         rsp,28h
mov         ecx,3
call        00007FFCF2F310C0
add         eax,2
add         rsp,28h
ret

Repare que o método é mais lento porque precisa criar um registro na stack, executar a chamada, e restaurar a stack. Além disso, agora, a remoção da operação de adição não foi possível.

Por fim, o método que chama dois métodos sem fazer inlining é o mais lento.

sub         esp,20h
mov         ecx,2
call        00007FFCF2F010C0
mov         esi,eax
mov         ecx,3
call        00007FFCF2F010C0
add         eax,esi
add         rsp,20h
pop         rsi
ret

O motivo, agora, é evidente. Há o overhead de duas chamadas e, no final, a execução da operação de adição.

IMPORTANTE: Tentar influenciar na decisão do compilador sobre fazer, ou não, inlining é um tipo de “micro-otimização”. Exceto em cenários extremos, você não deveria se preocupar com isso.

Concluindo

O JIT consegue implementar, automaticamente, otimizações fantásticas em nossos códigos. Inlining é apenas uma delas.

Boa parte das otimizações implementadas pelo JIT não deveriam ser “preocupação” para o desenvolvedor, exceto em cenários extremos.

Depurar em Release não é coerente. Se, mesmo assim, você resolver fazer isso, entenda que comportamentos “estranhos” do Visual Studio não indicam “problemas” no ambiente.

Dúvidas? Sugestões? Compartilhe suas impressões nos comentários.

Compartilhe este insight:

Comentários

Participe deixando seu comentário sobre este artigo a seguir:

Subscribe
Notify of
guest
1 Comentário
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Marcio Silveira
Marcio Silveira
4 anos atrás

Tens como você fazer um post explicando uma boa prática para disponibilizarmos os PDBs em release, talvez usando um Symbol Server. Isso visando análise futura de DUMPs ou mesmo debug/profiler em produção.
Parabéns pelos ótimos POSTs Elemar.

AUTOR

Elemar Júnior
Fundador e CEO da EximiaCo atua como tech trusted advisor ajudando empresas e profissionais a gerar mais resultados através da tecnologia.

NOVOS HORIZONTES PARA O SEU NEGÓCIO

Nosso time está preparado para superar junto com você grandes desafios tecnológicos.

Entre em contato e vamos juntos utilizar a tecnologia do jeito certo para gerar mais resultados.

Insights EximiaCo

Confira os conteúdos de negócios e tecnologia desenvolvidos pelos nossos consultores:

Arquivo

Pós-pandemia, trabalho remoto e a retenção dos profissionais de TI

CTO Consulting e Especialista em Execução em TI
EximiaCo 2024 - Todos os direitos reservados
1
0
Queremos saber a sua opinião, deixe seu comentáriox
()
x

Muito obrigado!

Deu tudo certo com seu envio!
Logo entraremos em contato

RESPOSTA: Por que o depurador não respeita meu breakpoint?

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

RESPOSTA: Por que o depurador não respeita meu breakpoint?

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Condição especial de pré-venda: R$ 14.000,00 - contratando a mentoria até até 31/01/2023 e R$ 15.000,00 - contratando a mentoria a partir de 01/02/2023, em até 12x com taxas.

Tenho interesse nessa capacitação

Para solicitar mais informações sobre essa capacitação para a sua empresa, preencha o formulário a seguir:

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

O seu insight foi excluído com sucesso!

O seu insight foi excluído e não está mais disponível.

O seu insight foi salvo com sucesso!

Ele está na fila de espera, aguardando ser revisado para ter sua publicação programada.

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse nessa solução

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse neste serviço

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

× Precisa de ajuda?