O Android 6.0 (API de nível 23) ou mais recentes oferece suporte para uma API de rastreamento nativa, trace.h
,
para registrar eventos de rastreamento no buffer do sistema que podem ser analisados usando o
Perfetto ou o Systrace. Casos de uso comuns para essa API incluem observar o tempo
que um determinado bloco de código leva para executar e associar um bloco
com comportamento de sistema indesejado.
Observação: em dispositivos e emuladores com API de nível 27 e versões anteriores, se não
houver memória suficiente disponível ou se a memória estiver muito fragmentada, você receberá a
seguinte mensagem: Atrace could not allocate enough memory to record a trace
.
Se isso acontecer e a captura não tiver um conjunto completo de dados, feche
os processos em segundo plano ou reinicie o dispositivo ou emulador.
Para definir eventos personalizados que ocorrem no código nativo do seu app ou jogo, siga as etapas a seguir:
Defina os ponteiros de função para as funções ATrace usadas para capturar eventos personalizados no app ou jogo, conforme apresentado no snippet de código a seguir:
#include <android/trace.h> #include <dlfcn.h> void *(*ATrace_beginSection) (const char* sectionName); void *(*ATrace_endSection) (void); typedef void *(*fp_ATrace_beginSection) (const char* sectionName); typedef void *(*fp_ATrace_endSection) (void);
Carregue os símbolos ATrace no tempo de execução, conforme mostrado no snippet de código a seguir. Normalmente, esse processo é executado em um construtor de objeto.
// Retrieve a handle to libandroid. void *lib = dlopen("libandroid.so", RTLD_NOW | RTLD_LOCAL); // Access the native tracing functions. if (lib != NULL) { // Use dlsym() to prevent crashes on devices running Android 5.1 // (API level 22) or lower. ATrace_beginSection = reinterpret_cast<fp_ATrace_beginSection>( dlsym(lib, "ATrace_beginSection")); ATrace_endSection = reinterpret_cast<fp_ATrace_endSection>( dlsym(lib, "ATrace_endSection")); }
Cuidado: por motivos de segurança, só inclua chamadas
dlopen()
na versão de depuração do seu app ou jogo.Observação: para oferecer compatibilidade de rastreamento até o Android 4.3 (API de nível 18), é possível usar o JNI para chamar os métodos no código gerenciado ao redor do código mostrado no snippet anterior.
Chame
ATrace_beginSection()
eATrace_endSection()
no início e no fim do seu evento personalizado, respectivamente:#include <android/trace.h> char *customEventName = new char[32]; sprintf(customEventName, "User tapped %s button", buttonName); ATrace_beginSection(customEventName); // Your app or game's response to the button being pressed. ATrace_endSection();
Observação: quando
ATrace_beginSection()
é chamado várias vezes, chamarATrace_endSection()
encerra apenas o métodoATrace_beginSection()
chamado mais recentemente. Por esse motivo, combine corretamente cada chamada deATrace_beginSection()
com uma chamada deATrace_endSection()
para chamadas aninhadas, como as do snippet a seguir.Além disso, não é possível chamar
ATrace_beginSection()
em uma linha de execução e depois encerrá-la em outra. É preciso chamar as duas funções na mesma linha de execução.
Dicas para sua conveniência
As dicas a seguir são opcionais, mas podem facilitar a análise do seu código nativo.
Rastrear uma função inteira
Ao instrumentar a pilha de chamadas ou o tempo da função, pode ser útil
rastrear funções inteiras. É possível usar a macro ATRACE_CALL()
para facilitar esse
tipo de rastreamento. Além disso, essa macro permite pular
a criação de blocos try
e catch
para casos em que a função rastreada pode
gerar uma exceção ou chamar return
antecipadamente.
Para criar uma macro para rastrear uma função inteira, siga estas etapas:
Defina a macro:
#define ATRACE_NAME(name) ScopedTrace ___tracer(name) // ATRACE_CALL is an ATRACE_NAME that uses the current function name. #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__) class ScopedTrace { public: inline ScopedTrace(const char *name) { ATrace_beginSection(name); } inline ~ScopedTrace() { ATrace_endSection(); } };
Chame a macro na função que você quer rastrear:
void myExpensiveFunction() { ATRACE_CALL(); // Code that you want to trace. }
Nomeie suas linhas de execução
Você pode dar um nome para cada linha de execução em que os eventos ocorrem, conforme demonstrado no snippet de código a seguir. Esta etapa facilita a identificação das linhas de execução que pertencem a ações específicas no seu jogo.
#include <pthread.h> static void *render_scene(void *parm) { // Code for preparing your app or game's visual components. } static void *load_main_menu(void *parm) { // Code that executes your app or game's main logic. } void init_threads() { pthread_t render_thread, main_thread; pthread_create(&render_thread, NULL, render_scene, NULL); pthread_create(&main_thread, NULL, load_main_menu, NULL); pthread_setname_np(render_thread, "MyRenderer"); pthread_setname_np(main_thread, "MyMainMenu"); }
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Práticas recomendadas para a performance do SQLite
- Criar e medir perfis de referência sem a Macrobenchmark