Evaluación comparativa de ORM utilizada al crear aplicaciones de Android

Hola Habr! Mi nombre es Artyom Dobrovinsky y soy desarrollador de Android en FINCH .


Una vez, envolviéndome en el humo de un cigarro matutino, estudié el código fuente de un ORM para Android. Al ver allí, un paquete llamado benchmarks inmediatamente miró allí, y me sorprendió que todas las evaluaciones se hicieran usando Log.d(System.nanoTime()) . Esta no es la primera vez que veo esto. Para ser honesto, incluso vi puntos de referencia realizados con System.currentTimeMillis() . El colapso de la conciencia de que algo debe cambiarse me obligó a dejar a un lado un vaso de whisky y sentarme al teclado.


¿Por qué está escrito este artículo?


La situación con la comprensión de cómo medir el rendimiento del código en Android es triste.
No hable de los perfiladores, pero en 2019 alguien sigue confiando en que la JVM hace todo lo que escribió el desarrollador y en el orden exacto en que se escribe el código. En realidad, no hay nada más lejos de la verdad.


De hecho, la desafortunada máquina virtual lucha contra un billón de lectores de botones descuidados que escriben su propio código, sin tener que preocuparse de cómo funcionará el procesador con todo esto. Esta batalla ha estado sucediendo durante varios años, y ella tiene un millón de optimizaciones difíciles en su manga que (si se ignoran) convertirán cualquier medición del rendimiento del programa en una pérdida de tiempo.


Es decir, los desarrolladores a veces no consideran necesario medir el rendimiento del código, y aún más a menudo no saben cómo. La dificultad radica en el hecho de que para realizar una evaluación del desempeño, es necesario crear las condiciones más similares e ideales para todos los casos; esta es la única forma de obtener información útil. Estas condiciones son creadas por soluciones no escritas en la rodilla.


Si necesita argumentos sobre si usar marcos de terceros para medir el rendimiento, siempre puede leer Alexei Shipilev y maravillarse con la profundidad del problema. Todo está en el artículo por referencia: por qué se necesita calentamiento antes de realizar el punto de referencia, por qué no se puede confiar en System.currentTimeMillis() al contar el tiempo transcurrido, y bromas por 300. Excelente lectura.


¿Por qué puedo hablar de esto?

El hecho es que soy un desarrollador completamente desarrollado: no solo soy dueño del SDK de Android como si fuera mi proyecto favorito, sino que durante otro mes escribí el código para el backend.


Cuando traje mi primer microservicio a la revisión, y no había ninguna evaluación comparativa en README , me miró con un malentendido. Recordé esto y nunca más volví a repetir este error. Porque se fue en una semana.


Vamos


¿Qué estamos midiendo?


Como parte del caso de las bases de datos de referencia para Android, decidí medir la velocidad de inicialización y la velocidad de escritura / lectura para ORM como Paper, Hawk, Realm y Room.
Sí, mido en una prueba NoSQL y una base de datos relacional: ¿cuál es la siguiente pregunta?


De lo que medimos


Parece que si estamos hablando de la JVM, entonces la elección es obvia: hay una JMH glorificada , perfecta e impecablemente documentada . Pero no, no inicia las pruebas de instrumentación para Android.


Google Calipher los sigue, con el mismo resultado.


Hay una bifurcación de Calipher llamada Spanner , que durante muchos años ha sido zeppercay y fomenta el uso de Androidx Benchmark .


Centrémonos en lo último. Si solo porque no teníamos otra opción.


Al igual que todo lo que se agregó a Jetpack y no se repensó al migrar desde la Biblioteca de soporte, Androidx Benchmark se ve y se comporta como si estuviera escrito en una semana y media como una tarea de prueba, y nadie más lo tocará. Además, esta biblioteca está un poco pasada, porque es más para evaluar las pruebas de IU. Pero por falta de lo mejor, puedes trabajar con ella. Esto nos salvará al menos de errores obvios y también ayudará con el calentamiento.


Para reducir la ridiculez de los resultados, haré todas las pruebas 10 veces y calcularé el promedio.


Dispositivo de prueba: Xiaomi A1. No es el más débil del mercado, Android "limpio".


Conectar una biblioteca a un proyecto


Hay excelentes instrucciones para conectar Andoridx Benchmark a un proyecto. Le recomiendo encarecidamente que no sea flojo y que conecte un módulo separado para realizar mediciones.


Progreso del experimento


Todos nuestros puntos de referencia se ejecutarán en el siguiente orden:


  1. Primero, iniciamos la base de datos en el cuerpo de prueba.
  2. Luego, en el bloque benchmarkRule.scope.runWithTimingDisabled , generamos datos que alimentamos a la base de datos. El código colocado en este circuito no se tendrá en cuenta en la evaluación.
  3. En el mismo cierre agregamos la lógica de borrar la base de datos; asegúrese de que la base de datos esté vacía antes de escribir.
  4. La siguiente es la lógica de la escritura y la lectura. Asegúrese de inicializar la variable con el resultado de la lectura para que la JVM no elimine esta lógica del recuento de ejecución como no utilizada.
  5. Medimos el rendimiento de la inicialización de la base de datos en una función separada.
  6. Nos sentimos como un hombre de ciencia.

El código se puede encontrar aquí . Si tiene pereza para caminar, la función de medición para PaperDb se ve así:


 @Test fun paperdbInsertReadTest() = benchmarkRule.measureRepeated { //   (     ) benchmarkRule.scope.runWithTimingDisabled { Paper.book().destroy() if (Paper.book().allKeys.isNotEmpty()) throw RuntimeException() } //    repository.store(persons, { list -> Paper.book().write(KEY_CONTACTS, list) }) val persons = repository.read { Paper.book().read<List<Person>>(KEY_CONTACTS, emptyList()) } } 

Los puntos de referencia para el resto de ORM se parecen.


Resultados


Inicialización

nombre de pruebamalvado1234 45 56 67 789 910
HawkInitTest49_51249_28250_02149_11950_14549_97050_04746_64950_23049_86349_794
PaperdbInitTest224223223223233223223223223223223
RealmInitTest218217217217217217217217227217217
RoomInitTest61_695.563_45059_71458_52759_17563_54462_98063_25259_67063_86862_775

El ganador es Realm, en segundo lugar es Paper. Lo que está haciendo Room, todavía puede imaginar que Hawk hace casi la misma cantidad de tiempo, es completamente incomprensible.


Escritura y lectura

nombre de pruebamalvado1234 45 56 67 789 910
HawkInsertReadTest278_736_469.2278_098_654283_956_846276_748_308282_447_384272_609_500284_699_653271_869_770278_719_693278_836_115279_378_769
PaperdbInsertReadTest173_519_957.3172_953_347174_702_000169_740_846174_401_192173_930_037174_179_616173_937_460173_739_115176_215_038171_400_922
RealmInsertReadTest111_644_042.3108_501_578110_616_078102_056_461112_946_577111_701_231114_922_962106_198_000118_742_498120_888_230109_866_808
RoomInsertReadTest1_863_499_483.3187_250_36141_837_078_6141_872_482_5381_827_338_4601_869_147_9991_857_126_2291_842_427_5371_870_630_6521_878_862_5381_907_396_652

Aquí nuevamente el ganador de Realm, pero en estos resultados huele a fracaso.


La diferencia de cuatro veces entre las dos bases de datos "más lentas" y las dieciséis veces entre las "más rápidas" y las "más lentas" es muy sospechosa. Incluso teniendo en cuenta el hecho de que la diferencia es estable.


Conclusión


Medir el rendimiento de su código es al menos por curiosidad. Incluso si hablamos de los casos más lanzados por la industria (como la evaluación de pruebas instrumentales para Android).


Hay muchas razones para usar marcos de terceros para este negocio (en lugar de escribir el suyo propio con el tiempo y las animadoras).


La situación en las bases de código es tal que todos están tratando de escribir en una arquitectura limpia, para la mayoría, el módulo con lógica de negocios es un módulo java, para conectar un módulo con JMH cercano y verificar el código para detectar cuellos de botella, funciona por un día. Y los beneficios, durante muchos años por venir.


¡Feliz codificación!


PD: Si un lector atento conoce el marco para realizar pruebas comparativas de pruebas instrumentales para Android, que no figuran en el artículo, por favor comparta en los comentarios.


PPS: el repositorio de prueba está abierto para solicitudes de extracción.

Source: https://habr.com/ru/post/477940/


All Articles