Android 6.0 (API-Level 23) und höher unterstützen eine native Tracing API, trace.h
,
um Trace-Ereignisse in den Systempuffer zu schreiben, den Sie dann mit
Perfetto oder systrace. Häufige Anwendungsfälle für diese API sind die Beobachtung der Zeit
die ein bestimmter Codeblock zum Ausführen benötigt und
mit unerwünschtem Systemverhalten.
Hinweis:Auf Geräten und Emulatoren mit API-Level 27 und niedriger, falls vorhanden
nicht genügend Arbeitsspeicher verfügbar ist oder der Speicher zu fragmentiert ist,
folgende Nachricht: Atrace could not allocate enough memory to record a trace
.
Wenn dies passiert und Ihre Erfassung keinen vollständigen Datensatz hat,
Hintergrundprozesse schließen oder das Gerät oder den Emulator neu starten.
Um benutzerdefinierte Ereignisse zu definieren, die im nativen Code Ihrer App oder Ihres Spiels auftreten, führen Sie die folgenden Schritte aus:
Definieren Sie Funktionszeiger für die ATrace-Funktionen, mit denen Sie benutzerdefinierte Ereignisse in Ihrer App oder Ihrem Spiel erfassen, wie im folgenden Code gezeigt: snippet:
#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);
Lädt die ATrace-Symbole zur Laufzeit, wie im folgenden Code gezeigt: Snippet. Normalerweise führen Sie diesen Vorgang in einem Objektkonstruktor aus.
// 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")); }
Achtung : Aus Sicherheitsgründen sollten Sie Aufrufe von
dlopen()
nur in der Debug-Version deiner App oder deines Spiels.Hinweis : Wenn Sie Tracing-Unterstützung auch nach der Unter Android 4.3 (API-Level 18) können Sie mit JNI die Methoden in verwalteten Code um den im vorige Snippets.
ATrace_beginSection()
anrufen undATrace_endSection()
am Anfang bzw. Ende von Ihr benutzerdefiniertes Ereignis:#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();
Hinweis : Wenn Sie
ATrace_beginSection()
mehrere Mal, wirdATrace_endSection()
nur am häufigsten beendet. mit der kürzlich aufgerufenenATrace_beginSection()
-Methode. Bei verschachtelten -Aufrufen, stellen Sie sicher, dass Sie jeden AufrufATrace_beginSection()
mit einem Anruf beiATrace_endSection()
.Außerdem können Sie
ATrace_beginSection()
nicht auf einem Gerät aufrufen. und beenden sie in einem anderen Thread. Beide Funktionen müssen vom selben Diskussions-Thread.
Praktische Tipps
Die folgenden Tipps sind optional, helfen Ihnen aber möglicherweise bei der Analyse Ihrer nativen Anzeigen. Code.
Gesamte Funktion verfolgen
Wenn Sie Ihren Aufrufstack oder das Timing von Funktionen instrumentieren, kann es nützlich sein,
um ganze Funktionen nachzuverfolgen. Mit dem Makro ATRACE_CALL()
können Sie
Tracing-Typ einfacher einzurichten. Außerdem können Sie mit einem solchen Makro
Erstellen von try
- und catch
-Blöcken für Fälle, in denen die Traced-Funktion
eine Ausnahme auslösen oder return
vorzeitig aufrufen.
Führen Sie die folgenden Schritte aus, um ein Makro für das Tracing einer gesamten Funktion zu erstellen:
Definieren Sie das Makro:
#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(); } };
Rufen Sie das Makro innerhalb der Funktion auf, die Sie verfolgen möchten:
void myExpensiveFunction() { ATRACE_CALL(); // Code that you want to trace. }
Threads benennen
Sie können jeden Thread, in dem Ihre Ereignisse auftreten, benennen, wie gezeigt im folgenden Code-Snippet auf. Mit diesem Schritt können Sie die Threads leichter identifizieren die zu bestimmten Aktionen in deinem Spiel gehören.
#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"); }
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Best Practices für SQLite-Leistung
- Baseline-Profile ohne MacroBenchmark erstellen und messen