¿Cuál es la causa de los picos de rendimiento periódicos que se ven al hacer el procesamiento de matriz de computación caro en el Nexus 4?
Soy nuevo en los hilos (no me mates para mi implementación a continuación 🙂 y tengo que hacer varios borrones de píxeles en un hilo separado (véase a continuación). No es la implementación más eficiente del desenfoque de la caja (es de Gaussian Filter sin usar ConvolveOp ), pero los picos de rendimiento no se producen en la tableta Nexus 7, pero sí ocurren en el teléfono Nexus 4.
He publicado mi muestra de prueba (en ejecución en Android 4.2 – ver más abajo).
- Compilar el proyecto de Android desde la línea de comandos es lento
- rendimiento u optimización en Android: variable local final vs variable local
- Android: nesting FrameLayouts - ¿cuál es la sobrecarga de rendimiento exacto?
- Java Android leer el archivo completo rápidamente
- Simula la memoria baja en el dispositivo real de Android
No creo que sea causado por el GC golpeando la memoria (no coincide con los picos).
Creo que podría ser algo que ver con la memoria caché localidad o la memoria del hardware thrashing – pero no estoy seguro.
¿Qué causaría los picos? A veces son de aparición repentina – por ejemplo, pico de 50%. A veces son de inicio lento – por ejemplo, picos de aumento / disminución monótona, con picos de la siguiente manera -> 5%, 10%, 20%, 10%, 5%.
¿Cómo podría evitar que se produzcan cuando se realiza el procesamiento de matrices pesadas?
Esto no ocurre en la tableta Nexus 7 que también he probado (ver los resultados a continuación)
Pregunta secundaria: ¿Cuál es la mejor manera de dormir y reiniciar mi hilo correctamente (nuevo en los hilos)?
MainActivity.java
package com.example.test; import android.os.Bundle; import android.app.Activity; public class MainActivity extends Activity { private MainThread thread; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); thread = new MainThread(); thread.setRunning(true); thread.start(); setContentView(R.layout.activity_main); } @Override protected void onResume() { super.onResume(); thread.setRunning(true); } @Override protected void onPause() { super.onPause(); thread.setRunning(false); } }
MainThread.java
package com.example.test; import android.util.Log; public class MainThread extends Thread { int[] pixels; int kernel_rows = 2; int kernel_cols = 2; int width = 512; int height = 512; @Override public void run() { while (running) { long start = System.currentTimeMillis(); for (int row = kernel_rows / 2; row < height - kernel_rows / 2; row++) { for (int col = kernel_cols / 2; col < width - kernel_cols / 2; col++) { float pixel = 0; // iterate over each pixel in the kernel for (int row_offset = 0; row_offset < kernel_rows; row_offset++) { for (int col_offset = 0; col_offset < kernel_cols; col_offset++) { // subtract by half the kernel size to center the // kernel // on the pixel in question final int row_index = row + row_offset - kernel_rows / 2; final int col_index = col + col_offset - kernel_cols / 2; pixel += pixels[row_index * width + col_index] * 1.0f / 4.0f; } } pixels[row * width + col] = (int) pixel; } } long stop = System.currentTimeMillis(); long delta = stop - start; Log.d("DELTA", Long.toString(delta)); } } private boolean running; public void setRunning(boolean running) { this.pixels = new int[512 * 512]; this.running = running; } }
Registros
Nexus 4 teléfono (ms):
01-13 10:56:05.663: D/DELTA(13507): 76 01-13 10:56:05.773: D/DELTA(13507): 107 01-13 10:56:05.843: D/DELTA(13507): 77 01-13 10:56:05.923: D/DELTA(13507): 75 01-13 10:56:06.053: D/DELTA(13507): 127 01-13 10:56:06.133: D/DELTA(13507): 78 01-13 10:56:06.213: D/DELTA(13507): 81 01-13 10:56:06.293: D/DELTA(13507): 80 01-13 10:56:06.353: D/DELTA(13507): 77 01-13 10:56:06.433: D/DELTA(13507): 79 01-13 10:56:06.513: D/DELTA(13507): 79 01-13 10:56:06.624: D/DELTA(13507): 106 01-13 10:56:06.694: D/DELTA(13507): 76
Nexus 7 comprimido (ms):
01-13 11:01:03.283: D/DELTA(3909): 84 01-13 11:01:03.373: D/DELTA(3909): 85 01-13 11:01:03.453: D/DELTA(3909): 85 01-13 11:01:03.543: D/DELTA(3909): 84 01-13 11:01:03.623: D/DELTA(3909): 85 01-13 11:01:03.703: D/DELTA(3909): 84 01-13 11:01:03.793: D/DELTA(3909): 85 01-13 11:01:03.873: D/DELTA(3909): 84 01-13 11:01:03.963: D/DELTA(3909): 85 01-13 11:01:04.043: D/DELTA(3909): 84
- Cómo dibujar una imagen de fondo grande con libgdx - las mejores prácticas?
- Android onClick en XML vs. OnClickListener
- En una aplicación para Android, ¿cuándo se cargan los recursos en la memoria?
- ¿Cuál es la tasa de bits de lectura NFC efectiva usando comandos de APDU?
- Los subprocesos predeterminados de Android y su uso
- Android: utiliza UUID como clave principal en SQLite
- Cómo dibujar varias líneas con el dedo? (Androide)
- ¿Es un RelativeLayout más caro que un LinearLayout?
Creo que puede haber mitigado un poco este efecto en el Nexus 4. Todavía hay cierta variabilidad en la consistencia del cálculo, pero es soportable – creo – no se pueden ver demasiados picos enormes – fuera del inicio / cierre del hilo. He hecho esto usando el NDK de Android y c p_threads para generar un hilo nativo que es en su mayoría abandonado por Java (o así me dicen) hasta que la aplicación de primer plano se cambia o se cierra.
Aquí está el código:
MainActivity.java
package com.example.test; import android.os.Bundle; import android.app.Activity; public class MainActivity extends Activity { static { System.loadLibrary("native"); } private native void init(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Initializes and spawns native thread init(); setContentView(R.layout.activity_main); } }
native.c
(que se debe poner en una carpeta jni en la raíz del proyecto de Android)
#include <time.h> #include <pthread.h> #include <jni.h> #include <android/log.h> #define APPNAME "DELTA" int* pixels; int kernel_rows = 2; int kernel_cols = 2; int width = 60; int height = 39; int running = 1; // from android samples /* return current time in milliseconds */ static double now_ms(void) { struct timespec res; clock_gettime(CLOCK_REALTIME, &res); return 1000.0 * res.tv_sec + (double) res.tv_nsec / 1e6; } // initialize thread/begin it jint Java_com_example_testa_MainActivity_init(JNIEnv* env, jobject javaThis) { int i1 = 1; pthread_t thread; void *run(); pthread_create(&thread, NULL, run, &i1); pthread_join(thread, NULL); return 0; } // thread function void *run(int *x) { // init pixels within thread pixels = (int*) malloc(sizeof(int) * width * height); // loop until stopped - java won't interfere // unless closed/switch application (or so I'm told) while (running) { double start = now_ms(); int row, col, row_offset, col_offset; for (row = kernel_rows / 2; row < height - kernel_rows / 2; row++) { for (col = kernel_cols / 2; col < width - kernel_cols / 2; col++) { float pixel = 0; // iterate over each pixel in the kernel for (row_offset = 0; row_offset < kernel_rows; row_offset++) { for (col_offset = 0; col_offset < kernel_cols; col_offset++) { // subtract by half the kernel size to center the // kernel // on the pixel in question int row_index = row + row_offset - kernel_rows / 2; int col_index = col + col_offset - kernel_cols / 2; pixel += pixels[row_index * width + col_index] * 1.0f / 4.0f; } } pixels[row * width + col] = (int) pixel; } } double end = now_ms(); double delta = end - start; __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "%f", delta); } pthread_exit(0); }
Android.mk
(que se debe poner en una carpeta jni en la raíz del proyecto de Android)
LOCAL_PATH := $(call my-dir) MY_PATH := $(LOCAL_PATH) include $(call all-subdir-makefiles) include $(CLEAR_VARS) LOCAL_PATH := $(MY_PATH) LOCAL_MODULE := native LOCAL_LDLIBS := -llog LOCAL_SRC_FILES := native.c include $(BUILD_SHARED_LIBRARY)
Resumen
Reducción del coste del código en ~ 20-30% y disminución de la variabilidad en un orden de magnitud.
El código se compila ejecutando el ndk-build
de la biblioteca NDK proporcionada por Android en la carpeta raíz (que se encuentra aquí: http://developer.android.com/tools/sdk/ndk/index.html ).
Resultados
Nexus 4 (ms):
01-14 13:41:21.132: V/DELTA(23679): 56.554199 01-14 13:41:21.192: V/DELTA(23679): 58.568604 01-14 13:41:21.252: V/DELTA(23679): 59.484131 01-14 13:41:21.302: V/DELTA(23679): 56.768066 01-14 13:41:21.362: V/DELTA(23679): 54.692383 01-14 13:41:21.412: V/DELTA(23679): 51.823730 01-14 13:41:21.472: V/DELTA(23679): 55.668945 01-14 13:41:21.522: V/DELTA(23679): 56.920654 01-14 13:41:21.582: V/DELTA(23679): 56.371094 01-14 13:41:21.642: V/DELTA(23679): 58.507568 01-14 13:41:21.702: V/DELTA(23679): 59.697754 01-14 13:41:21.752: V/DELTA(23679): 53.990723 01-14 13:41:21.812: V/DELTA(23679): 55.669189
Nexus 7 (ms):
01-14 13:41:25.685: V/DELTA(2916): 65.867920 01-14 13:41:25.745: V/DELTA(2916): 65.986816 01-14 13:41:25.815: V/DELTA(2916): 66.685059 01-14 13:41:25.885: V/DELTA(2916): 67.033936 01-14 13:41:25.945: V/DELTA(2916): 65.703857 01-14 13:41:26.015: V/DELTA(2916): 66.653076 01-14 13:41:26.085: V/DELTA(2916): 66.922119 01-14 13:41:26.145: V/DELTA(2916): 67.030029 01-14 13:41:26.215: V/DELTA(2916): 67.014893 01-14 13:41:26.285: V/DELTA(2916): 67.034912 01-14 13:41:26.345: V/DELTA(2916): 67.089844 01-14 13:41:26.415: V/DELTA(2916): 65.860107 01-14 13:41:26.485: V/DELTA(2916): 65.642090 01-14 13:41:26.545: V/DELTA(2916): 65.574951 01-14 13:41:26.615: V/DELTA(2916): 65.991943
- No se puede abrir el archivo keycharmap en android
- Proguard Error / Dalvik Error 1 al firmar la aplicación para Android