Instrumentos personalizados: cuando la señalización no es suficiente

Instrumentos para Xcode de Apple es una herramienta para analizar el rendimiento de una aplicación iOS. Se utilizan para recopilar y mostrar datos que se necesitan en la depuración de código. El año pasado, Apple presentó Custom Instruments. Esta es una oportunidad para ampliar el conjunto estándar de herramientas para la creación de perfiles de aplicaciones. Cuando las herramientas existentes no son suficientes, puede crear otras nuevas usted mismo: recopilarán, analizarán y mostrarán los datos según lo necesite.

Ha pasado un año y casi no hay nuevas herramientas públicas e información sobre su creación en la red. Entonces decidimos corregir la situación y compartir cómo creamos nuestro propio Instrumento personalizado, que determina la razón del débil aislamiento de las pruebas unitarias. Se basa en la tecnología de señalización (escribimos sobre ello en el artículo anterior ) y le permite determinar de forma rápida y precisa dónde parpadea la prueba.



Mínimo teórico


Para crear una nueva herramienta para Xcode, necesita comprender dos bloques teóricos. Para aquellos que quieran resolverlo por su cuenta, les daremos de inmediato los enlaces necesarios:


Por lo demás, a continuación se incluye un breve resumen de los temas necesarios.

Primero seleccione Archivo -> Nuevo -> Proyecto -> Categoría macOS -> Paquete de instrumentos. El proyecto creado incluye un archivo con la extensión .instrpkg, en el que una nueva herramienta se declara declarativamente en formato xml. Conozcamos los elementos de marcado:

QueAtributosDescripción
Esquemas de datos
esquema de intervalos, esquema de puntos, etc.
Describe la estructura de datos como una tabla como esquemas sql. Los esquemas se utilizan en otros elementos de marcado para determinar el tipo de datos en la entrada y salida del modelo, por ejemplo, al describir una asignación (IU).
Importar esquemas de datos
esquema de importación
Importar esquemas confeccionados. Le permite utilizar estructuras de datos definidas por Apple.
Modelo de herramienta
modelador
Asocia la herramienta con un archivo .clp, en el que se define la lógica de la herramienta, y anuncia el esquema de datos esperado en la entrada y salida del modelo.
Descripción de la herramienta
instrumento
Describe el modelo de datos y determina cómo se mostrarán los eventos en la interfaz de usuario. El modelo de datos se describe utilizando los atributos create-table, create-parameter, etc. Los cuadros de herramientas se definen por atributos gráficos, y la tabla de partes se define por lista, narrativa, etc.

Si queremos complementar la lógica de la nueva herramienta, cree un archivo .clp con código CLIPS. Entidades básicas del lenguaje:

  • "Hecho" es un evento determinado registrado en el sistema que utiliza el comando afirmar;
  • La "regla" es un bloque if con una sintaxis específica que contiene una condición bajo la cual se realiza un conjunto de acciones.

El CLIPS determina qué reglas y en qué secuencia se activarán según los hechos entrantes, las prioridades de las reglas y el mecanismo de resolución de conflictos.

El lenguaje admite la creación de tipos de datos basados ​​en primitivas, el uso de operaciones y funciones aritméticas, lógicas. Así como programación orientada a objetos (OOP) completa con la definición de clases, envío de mensajes, herencia múltiple.

Considere la sintaxis básica de un lenguaje que le permite crear lógica para herramientas personalizadas.

1. Para crear un fact , use la construcción de assert :

 CLIPS> (assert (duck)) 

Por lo tanto, obtenemos la entrada del duck en la tabla de hechos, que se puede ver usando el comando de facts :

 CLIPS> (facts) 

Para eliminar el hecho, use el comando retract : (retract duck)

2. Para crear una rule , use la construcción defrule :

 CLIPS> (defrule duck) —     duck (animal-is duck)</i> —  animal-is duck     => (assert (sound-is quack))) —     sound-is quack 

3. Para crear y usar variables, se utiliza la siguiente sintaxis (antes del nombre de la variable hay un signo obligatorio "?"):

 ?<variable-name> 

4. Puede crear nuevos tipos de datos usando:

 CLIPS> (deftemplate prospect (slot name (type STRING) (default ?DERIVE)) (slot assets (type SYMBOL) (default rich)) (slot age (type NUMBER) (default 80))) 

Entonces, definimos una estructura con el nombre prospecto y el nombre de tres atributos, los activos y la edad del tipo correspondiente y un valor predeterminado.

5. Las operaciones aritméticas y lógicas tienen sintaxis de prefijo. Es decir, para agregar 2 y 3, debe usar la siguiente construcción:

 CLIPS> (+ 2 3) 

O para comparar dos variables x e y:

 CLIPS> (> ?x ?y) 

Ejemplo práctico


En nuestro proyecto, usamos la biblioteca OCMock para crear objetos de código auxiliar. Sin embargo, hay situaciones en las que un mok vive más tiempo que la prueba para la que fue creado y afecta el aislamiento de otras pruebas. Como resultado, esto lleva al "parpadeo" (inestabilidad) de las pruebas unitarias. Para realizar un seguimiento de la vida útil de las pruebas y simulacros, crearemos nuestra propia herramienta. El siguiente es un algoritmo de acciones.

Paso 1. Hacer marcado para eventos de señalización


Para detectar mox problemáticos, se necesitan dos categorías de eventos de intervalo: el tiempo de creación y destrucción del moxa, el tiempo de inicio y finalización de la prueba. Para obtener estos eventos, vaya a la biblioteca OCMock y OCMock con el signpost en los métodos init y stopMocking de la clase stopMocking .





A continuación, vaya al proyecto en estudio, realice el marcado en las pruebas unitarias, los tearDown setUp y tearDown :



Paso 2. Cree una nueva herramienta a partir de la plantilla del paquete de instrumentos




Primero, determinamos el tipo de datos de la entrada. Para hacer esto, importamos el esquema de signpost en el signpost . Ahora los eventos creados por signpost caerán en la herramienta:



A continuación, determinamos el tipo de datos en la salida. En este ejemplo, mostraremos eventos simultáneos. Cada evento tendrá un tiempo y una descripción. Para hacer esto, declare el esquema:



Paso 3. Describimos la lógica de la herramienta.


Creamos un archivo separado con la extensión .clp , en el que establecemos las reglas usando el lenguaje CLIPS. Para que la nueva herramienta sepa en qué archivo está definida la lógica, agregue el bloque modeler :



En este bloque, utilizando el atributo del production-system , especifique la ruta relativa al archivo con la lógica. En los atributos de output y required-input definimos los esquemas de datos para entrada y salida, respectivamente.



Paso 4. Describimos los detalles de la presentación de la herramienta (UI)


En el archivo .instrpkg , queda por describir la herramienta en sí, es decir, mostrar los resultados. Cree una tabla para los datos en el atributo create-table utilizando el schema-ref detected-mocks-narrative previamente schema-ref en el atributo schema-ref . Y configure el tipo de salida de información - narrativa (descriptiva):



Paso 5. Escribimos el código lógico


Pasemos al archivo .clp , en el que se define la lógica del sistema experto. La lógica será la siguiente: si el tiempo de inicio de la prueba se superpone con el intervalo de la vida del moka, entonces creemos que este mok "vino" de otra prueba, lo que viola el aislamiento de la prueba unitaria actual. Para crear un evento con información de interés, debe seguir los siguientes pasos:

1. Defina las estructuras simuladas y unitTest con campos: la hora del evento, el identificador del evento, el nombre de la prueba y la clase del mok.



2. Definimos las reglas que crearán hechos con los tipos mock y unitTest función de los eventos entrantes de signpost :



Puede leer estas reglas de la siguiente manera: si en la entrada obtenemos un hecho del tipo os-signpost con el subsystem deseado, category , name y event-type , luego cree un nuevo hecho con el tipo que se definió anteriormente (unitTest o simulacro) y complételo con valores. Es importante recordar aquí: CLIPS es un lenguaje que distingue entre mayúsculas y minúsculas y los valores de subsistema, categoría, nombre y tipo de evento deben coincidir con lo que se utilizó en el código del proyecto en estudio.



Las variables de los eventos de señalización se pasan de la siguiente manera:



3. Definimos las reglas que liberan eventos completados (son redundantes, ya que no afectan el resultado).



Paso 6. Defina la regla que generará los resultados.


Puedes leer la regla así.

Si

1) hay unitTest y simulacro;

2) en este caso, el comienzo de la prueba ocurre más tarde que el moka existente;

3) hay una tabla para almacenar resultados con el esquema narrativo simulado detectado;

entonces

4) crear un nuevo registro;

5) completar con tiempo;

6) ... y una descripción.



Como resultado, vemos la siguiente imagen al usar la nueva herramienta:



El código fuente del instrumento personalizado y un proyecto de muestra para usar el instrumento se pueden ver en GitHub .

Depuración de herramientas


El depurador se utiliza para depurar herramientas personalizadas.



El permite

1. Vea el código compilado basado en la descripción en instrpkg.
2. Vea información detallada sobre lo que le sucede a la herramienta en tiempo de ejecución.



3. Visualice una lista completa y una descripción de los esquemas de datos del sistema que se pueden utilizar como entrada en nuevas herramientas.



4. Ejecute comandos arbitrarios en la consola. Por ejemplo, muestre una lista de reglas con el comando list-defrules o hechos con el comando hechos



Configuración en el servidor CI


Puede ejecutar herramientas desde la línea de comandos para perfilar la aplicación durante la ejecución de pruebas unitarias o de UI en el servidor CI. Esto permitirá, por ejemplo, detectar una pérdida de memoria lo antes posible. Para perfilar pruebas en la tubería, use los siguientes comandos:

1. Ejecución de herramientas con atributos:

 xcrun instruments -t <template_name> -l <average_duration_ms> -w <device_udid> 

  • donde template_name es la ruta a la plantilla con herramientas o el nombre de la plantilla. Puede obtener el comando xcrun instruments -s ;
  • average_duration_ms : el tiempo de grabación en milisegundos debe ser mayor o igual que el tiempo de ejecución de la prueba;
  • device_udid : identificador del simulador. Puede obtener el comando xcrun instruments -s. Debe coincidir con el identificador del simulador en el que se ejecutarán las pruebas.

2. Ejecutando pruebas en el mismo simulador con el comando:

 xcodebuild -workspace <path_to_workspace>-scheme <scheme_with_tests> -destination <device> test-without-building 

  • donde path_to_workspace es la ruta al espacio de trabajo de Xcode;
  • scheme_with_tests - esquema con pruebas;
  • device - identificador del simulador.

Como resultado, se creará un informe con la extensión .trace en el directorio de trabajo, que puede abrir la aplicación Instrumentos o haciendo clic derecho en el archivo y seleccionando Mostrar contenido del paquete.

Conclusiones


Examinamos un ejemplo de actualización de la señal a una herramienta completa y explicamos cómo aplicarla automáticamente en las "ejecuciones" del servidor de CI y usarla para resolver el problema de las pruebas de "parpadeo" (inestable).

A medida que profundice en las posibilidades de los instrumentos personalizados, comprenderá mejor en qué otros casos puede usar los instrumentos. Por ejemplo, también nos ayudan a comprender los problemas de subprocesamiento múltiple: dónde y cuándo usar el acceso a datos seguro para subprocesos.
Crear una nueva herramienta fue bastante simple. Pero lo principal es que después de pasar varios días estudiando la mecánica y la documentación para crearlo hoy, podrá evitar varias noches de insomnio en los intentos de corregir errores.

Fuentes



El artículo fue escrito con @regno , Anton Vlasov, un desarrollador de iOS.

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


All Articles