Depurando Aplicações ANSI C Multicore com LabWindows™/CVI

Visão geral


Multicore Programming Fundamentals White Paper Series


O advento dos processadores multicore proporcionou significantes benefícios com relação à arquitetura de processadores tradicionais de um único núcleo, incluindo o aumento da taxa de transferência e do desempenho, poder de processamento mais econômico e baixo consumo de potência – que atualmente são fatores críticos para todos os sistemas de teste e dispositivos embarcados. Juntamente com esses benefícios, a complexidade do hardware aumenta significativamente os novos desafios para o desenvolvimento de software. Executar tarefas em paralelo frequentemente revela falhas no projeto que passaram despercebidas em aplicações single-thread (de uma única thread) – especialmente quando o funcionamento correto da aplicação depende do tempo preciso de execução, acesso à memória e da comunicação entre múltiplas tarefas. O LabWindows/CVI não fornece apenas funções simplificadas para sincronização e otimização das threads ANSI C para atender a esses desafios, mas também contém várias funcionalidades avançadas que simplificam a solução de problemas e a otimização de projetos em sistemas multicore (processadores contendo múltiplos núcleos). Este artigo oferece um resumo das ferramentas do LabWindows/CVI para depuração de aplicações multicore.

Conteúdo

Introdução ao Multithread no LabWindows/CVI

Desde meados dos anos 90, o NI LabWindows/CVI é compatível com aplicações multithread. Agora, com a grande oferta de processadores multicore, você pode utilizar o LabWindows/CVI para tirar total proveito das funcionalidades da tecnologia multithread.

A Biblioteca Multithreading do LabWindows/CVI fornece as seguintes otimizações de múltiplo desempenho sobre o padrão Windows SDK threading APIs:

  • Thread pools - auxilia no agendamento de funções para execução em diferentes threads. Com esse recurso permite maior controle das threads, minimizando a sobrecarga associada à criação e a destruição de threads.
  • Thread-safe queues - abstrai a transferência de dados entre threads. Uma thread pode ler de uma queue (fila), ao mesmo tempo em que outra thread escreve na queue.
  • Thread-safe variables - combina de maneira eficaz uma seção crítica e um tipo de dado arbitrário. Você pode chamar uma única função para adquirir a seção crítica, configurar o valor da variável e liberar a seção.
  • Thread locks – simplificam a utilização de uma seção crítica ou mutex (mutuamente exclusivo) para providenciar uma API consistente e para automaticamente escolher o mecanismo apropriado, quando necessário. Por exemplo, o LabWindows/CVI automaticamente usa um mutex, se o recurso precisar ser compartilhado entre processos ou se a thread precisar processar mensagens enquanto estiver esperando pelo recurso. A seção critica é usada em outros casos porque é mais eficiente.
  • Thread-local variables - fornece instâncias de variáveis para threads. O sistema operacional coloca um limite no número de thread-local variables disponível para cada processo. A implementação do LabWindows/CVI consolida as thread-local variables, usando apenas um processo de thread-local variables para todas as thread-local variables no seu programa.

Você pode encontrar todas as funções multithreading na Biblioteca do LabWindows/CVI através do menu Library»Utility»Multithreading.

Saiba Mais:

Artigo Multithreading in LabWindows/CVI In-Depth

 

Funcionamento do Depurador Run-Time

Tal como acontece com as aplicações single-thread, ter uma visão do funcionamento de sua aplicação enquanto ela estiver em execução é crucial. Quando são criadas aplicações multithread é importante acompanhar a execução não de apenas uma thread, mas de todas as threads que funcionam em paralelo. As ferramentas de depuração, tais como o watch statements, breakpoints e o stack traces estão disponíveis quando se está depurando aplicações multithreading.

Em particular, você pode usar a janela Threads do LabWindows/CVI para ver detalhadamente a informação de depuração dividida por thread. A janela Threads lista todas as threads no programa que estão sendo depuradas.

 

Figura 1 – Com a janela Threads do LabWindows/CVI você pode facilmente mudar entre as threads que estejam sendo depurados no ambiente

Você pode usar esta caixa de diálogo para selecionar as threads cujas variáveis locais e as chamadas stack que você quer ver. Quando você seleciona uma thread a partir desta caixa de diálogo e clica em View, o LabWindows/CVI mostra as variáveis locais da thread selecionada na janela Variables e mostra a posição atual da thread na janela Source. Os comandos Up Call Stack, Down Call Stack e Call Trace no menu Run  mostram informações sobre a thread selecionado.

Figura 2 – O LabWindows/CVI mostra as variáveis locais para a thread selecionada na janela Variáveis e mostra a posição atual da thread na janela Source

Introdução ao NI Real-Time Execution Trace Toolkit 2.0

O acesso à informação de execução de baixo nível é crítico para a otimização e depuração de aplicações de tempo real (real-time) porque você pode facilmente identificar a origem do jitter (variação de tempo de execução) tal como a atribuição do processador, alocações de memória, herança de prioridades ou as condições de concorrência. Se você está desenvolvendo uma aplicação de tempo real, a melhor maneira de monitorar detalhadamente a utilização da CPU, o tempo de execução e outros eventos é capturando traces de execução dos equipamentos de tempo real. Com o Real-Time Execution Trace Toolkit 2.0, compatível com ambos os módulos, LabWindows/CVI Reat-Time e LabVIEW Real-Time, você pode visualizar e analisar os traces de execução das funções incluídas nas tarefas do real-time e os threads do sistema operacional em sistemas single-core e multicore. Com o resultado dos traces, você pode encontrar problemas em seu código e detectar funcionamentos indesejáveis tais como a contenção de recurso, thread starvation (quando um thread nunca é executado por falta de tempo disponível do processador), alocações de memória e inversão de prioridade, enquanto verifica o comportamento desejado da temporização do código e monitora a utilização da CPU. A partir da versão 8.5 o LabWindows/CVI Real-Time inclui 30 dias grátis para avaliação do Real-Time Execution Trace Toolkit. Selecione Tools>>Real-Time Execution Trace Tool para testar o toolkit.

O Real-Time Execution Trace Toolkit é formado por duas partes: As funções Execution Trace, encontradas na Biblioteca de Utilidade do LabWindows/CVI Real-Time e o Trace Viewing Utility. Você pode adiconar as funções Execution Trace nas partes do código dos quais você gostaria de analisar sua execução e usar o Trace Viewing Utility para capturar os traces de execução.

 

Figura 3 – Encontre as funções Execution Trace na Biblioteca de Utilidades do LabWindows/CVI Real-Time

Figura 4 – Você pode localizar não apenas as funções definidas pelo usuário, mas também as funções da Biblioteca LabWindows/CVI que você chama em sua aplicação. Habilite essas configurações no menu Build Options.

Leia Mais:

Vídeos e Tutoriais sobre o NI Real-Time Execution Trace Toolkit

Verificação do Comportamento da Temporização e Prioridades das Threads

Com o Real-Time Execution Trace Toolkit, você pode visualizar o comportamento da aplicação nos níveis de thread e de função. O Real-Time Execution Trace Toolkit mostra todos os dados de funções de eventos e threads executadas em dispositivos de tempo real com respectivo tempo. O Real-Time Execution Trace Toolkit mostra uma escala de tempo para a exibição atual, que ajuda na compreensão de como as threads interagem. Além disso, a função e a atividade da thread são identificadas por diferentes cores para distinguir a prioridade de execução de cada evento. Com a habilidade do zoom in e zoom out das áreas específicas, você pode detectar o local exato dos problemas de desempenho em sua aplicação.

Figura 5 – A função view displays detalha o tempo de execução e  informa a prioridade  para cada função definida pelo usuário

Indentificando Recursos Compartilhados e Alocação de Memória

Usando os recursos compartilhados na thread de tempo crítico (time-critical – que é uma thread que  necessita executar em um período de tempo determinístico) pode-se introduzir jitter extra em sua aplicação de tempo real. Eventos de sistema específicos, tais como o sleep, chamadas do gerenciador de memória e recursos mutex, podem introduzir jitter, mas o Real-Time Execution Trace Toolkit detecta esses eventos e mostra um flag (bandeira) seguido pela linha tracejada no Threads view para indicar o tempo decorrido para a ocorrência do evento de sistema.

O Real-Time Execution Trace Toolkit pode detectar os seguintes eventos de sistema:

  • Sleep  – Ocorre quando a thread entra em pausa para permitir a execução de uma  thread de prioridade menor.
  • Wait For Object – Ocorre quando a thread espera por um recurso de nível baixo, tais como um evento ou um mutex, antes de executar.
  • Wait For Memory – Ocorre quando a thread direciona qualquer operação de gerenciamento de memória. O span é o tempo que esse gerenciamento leva para ser executado. Por padrão, o Real-Time Execution Trace Toolkit mostra o intervalo de tempo do Wait For Memory usando um flag na cor verde.

Priority Inheritance – Ocorre quando a thread herda a prioridade de uma thread de alta prioridade porque a thread de baixa prioridade trava um recurso compartilhado necessário à thread de alta prioridade (também conhecido como inversão de prioridade).

Figura 6 – Os eventos de sistema são marcados com flags coloridos

Por exemplo, quando um loop (estrutura de repetição) de prioridade normal está em posse do recurso compartilhado, tal como a thread lock, outras threads, incluindo threads de tempo crítico, que tentam adquirir o recurso, devem esperar até que o recurso compartilhado se torne disponível. Nesse caso o jitter é inevitavelmente introduzido na thread de tempo crítico. Para previnir tais situações, a National Instruments recomenda evitar o uso dos recursos compartilhados em loops de tempo crítico.

O código a seguir cria uma thread de alta prioridade e uma de prioridade normal. A thread de prioridade normal adquire um recurso antes da thread de alta prioridade. Quando a thread de alta prioridade tenta adquirir o recurso, este é forçado a esperar até que a thread de prioridade normal libere-o.

RTMain

 __declspec (dllexport) void CVIFUNC_C RTmain (void)
{


CmtNewLock (NULL, OPT_TL_PROCESS_EVENTS_WHILE_WAITING, &lock);

            /* schedule the thread functions */
            CmtScheduleThreadPoolFunctionAdv (pool, NormalPriorityLoop, NULL,
                                    THREAD_PRIORITY_NORMAL, NULL, 0, NULL, 0, &functions[0]);

           CmtScheduleThreadPoolFunctionAdv (pool, TimeCriticalLoop, NULL,
                                    THREAD_PRIORITY_TIME_CRITICAL, NULL, 0, NULL, 0, &functions[1]);

}


NormalPriorityLoop

  static int CVICALLBACK NormalPriorityLoop (void *functionData)
{
            CmtGetLock(lock);
            Sleep(3);
            CmtReleaseLock(lock);
            return 0;
}


TimeCriticalLoop

   static int CVICALLBACK NormalPriorityLoop (void *functionData)
{
            Sleep(1);
            CmtGetLock(lock);
            Sleep(3);
            CmtReleaseLock(lock);
            return 0;
}

O Real-Time Execution Trace Toolkit mostra a thread de tempo crítico  (4: LabWindows/CVI Thread Pool Thread 3) esperando pela thread de baixa prioridade (1: LabWindows/CVI Thread Pool Thread 3) para liberar o recurso, desta maneira resultando potencialmente na redução do determinismo.

Figura 7 – Como indicado pela área destacada, o Real-Time Execution Trace Toolkit mostra a thread de tempo crítico esperando pela thread de prioridade normal  liberar o recurso compartilhado.

Visualizando a Atribuição do Processador e o Monitor Multicore Interaction

De acordo com a pesquisa realizada pela Virtutech junto aos participantes da Embedded Systems Conference 2007 (San Jose, California), 59% dos entrevistados disseram que suas ferramentas de depuração não suportam multicore ou desenvolvimento em multiprocessadores. Por outro lado, O Real-Time Execution Trace Toolkit inclui a opção de Highlight CPU Mode capaz de destacar todas as atividades das threads que são executadas em um CPU específico. Com isso, é possível descobrir o caminho de cada execução da CPU no sistema para determinar se as threads foram executados como se pretendia. Também, ao ver a utilização do processador na ferramenta trace, você pode conhecer o desempenho de diferentes projetos, baseado na atribuição de várias partes do seu código em determinados processadores.

Figura 8 – Selecione uma determinada CPU a partir das opções do Highlight CPU Mode para destacar todas as atividades das threads executados nessa CPU

Veja Também:

Processamento Simétrico em Sistema Operacional de Tempo Real e Windows utilizando o LabWindows/CVI

Mais Recursos na Depuração e na Programação ANSI C Multicore

O LabWindows/CVI contém vários aspectos que simplificam a depuração de aplicações multicore. Você pode usar o Threads view, o Watch window e o Variable window para monitorar visualmente as funções sendo executadas em diferentes núcleos. Além disso, o Real-Time Execution Trace Toolkit pode facilitar a transição para processadores multicore em aplicações de tempo real através da simplificação da resolução de problemas e otimização de projetos. Explore estes recursos para aprender mais sobre a criação de aplicações multithread ANSI C que aproveitam as vantagens das arquiteturas multicore no LabWindows/CVI.

Was this information helpful?

Yes

No