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:
Que | Atributos | Descripció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í.
Si1) 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;
entonces4) 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.