Introduccion
La mayoría de los desarrolladores han escuchado claramente sobre algunos desarrollos de código abierto bastante significativos, como el sistema LLVM y el compilador clang. Sin embargo, LLVM ahora no es solo el sistema en sí mismo para crear compiladores, sino también un gran ecosistema que incluye muchos proyectos para resolver diversos problemas que surgen durante cualquier etapa de la creación del compilador (generalmente cada proyecto tiene su propio repositorio separado). Parte de la infraestructura incluye naturalmente herramientas de prueba y evaluación comparativa, como Cuando se desarrolla un compilador, su efectividad es un indicador muy importante. Uno de estos proyectos individuales de infraestructura de prueba LLVM es el conjunto de pruebas (
documentación oficial ).
Conjunto de pruebas LLVM
A primera vista en el repositorio del conjunto de pruebas, parece que esto es solo un conjunto de puntos de referencia en C / C ++, pero esto no es del todo cierto. Además del código fuente de los programas en los que se realizarán las mediciones de rendimiento, test-suite incluye una infraestructura flexible para construir, ejecutar y recopilar métricas. De manera predeterminada, recopila las siguientes métricas: tiempo de compilación, tiempo de ejecución, tiempo de enlace, tamaño del código (en secciones).
Test-suite es naturalmente útil para probar y comparar compiladores, pero también se puede utilizar para otras tareas de investigación en las que se necesita una base de código C / C ++. Los que alguna vez intentaron hacer algo en el campo del análisis de datos, creo, se enfrentaron al problema de la falta y la fragmentación de los datos de origen. Un conjunto de pruebas, aunque no consta de una gran cantidad de aplicaciones, pero tiene un mecanismo unificado de recopilación de datos. Agregar sus propias aplicaciones a la colección, recopilar las métricas necesarias para su tarea particular es muy simple. Por lo tanto, en mi opinión, test-suite (además de las tareas principales de prueba y evaluación comparativa) es una buena opción para un proyecto básico, sobre la base de la cual puede construir su recopilación de datos para tareas en las que necesita analizar algunas características del código del programa o algunas características de los programas.
Estructura del conjunto de pruebas LLVM
test-suite |----CMakeLists.txt // CMake , , | // .. | |---- cmake | |---- .modules // , | // API | |---- litsupport // Python, test-suite, | // lit ( LLVM) | |---- tools // : | // ( | // ), .. | | // | |---- SingleSource // , | // . . | |---- MultiSource // , | // . | // . | |---- MicroBenchmarks // , google-benchmark. | // , , | // | |---- External // , test-suite, | // , ( ) | // -
La estructura es simple y directa.
Principio de funcionamiento
Como puede ver, CMake y un formato especial de prueba de iluminación son responsables de todo el trabajo para describir el ensamblaje, el lanzamiento y la recopilación de métricas.
Si lo consideramos de una manera muy abstracta, está claro que el proceso de evaluación comparativa con este sistema parece simple y muy predecible:

¿Cómo se ve esto con más detalle? En este artículo, me gustaría analizar exactamente qué papel juega CMake en todo el sistema y cuál es el único archivo que debe escribir si desea agregar algo a este sistema.
1. Creación de aplicaciones de prueba.Como sistema de compilación, se ha convertido en el estándar de facto para los programas C / C ++ CMake. CMake configura el proyecto y genera archivos make, ninja, etc., según las preferencias del usuario. Para construcción directa.
Sin embargo, en el conjunto de pruebas, CMake genera no solo reglas sobre cómo crear aplicaciones, sino que también configura las propias pruebas.
Después de iniciar CMake, se escribirán otros archivos (con la extensión .test) en el directorio de compilación con una descripción de cómo se debe ejecutar la aplicación y verificar que sea correcta.
Ejemplo del archivo .test más estándar
RUN: cd <some_path_to_build_directory>/MultiSource/Benchmarks/Prolangs-C/football ; <some_path_to_build_directory>/MultiSource/Benchmarks/Prolangs-C/football/football VERIFY: cd <some_path_to_build_directory>/MultiSource/Benchmarks/Prolangs-C/football ; <some_path_to_build_directory>/tools/fpcmp %o football.reference_output
El archivo con la extensión .test puede contener las siguientes secciones:
- PREPARE: describe las acciones que deben realizarse antes de iniciar la aplicación, muy similar al método Before existente en diferentes marcos de prueba de unidades;
- EJECUTAR: describe cómo ejecutar la aplicación;
- VERIFICAR: describe cómo verificar el funcionamiento correcto de la aplicación;
- Métrica: describe las métricas que deben recopilarse adicionalmente en las estándar.
Cualquiera de estas secciones puede omitirse.
Pero dado que este archivo se genera automáticamente, está en el archivo CMake para el punto de referencia que describe: cómo obtener los archivos de objetos, cómo ensamblarlos en la aplicación y luego qué se debe hacer con esta aplicación.
Para una mejor comprensión del comportamiento predeterminado y cómo se describe, considere un ejemplo de algunos CMakeLists.txt
list(APPEND CFLAGS -DBREAK_HANDLER -DUNICODE-pthread)
Las banderas se pueden configurar según la plataforma, el archivo DetectArchitecture se incluye en los módulos cmake de la suite de pruebas, que determina la plataforma de destino en la que se ejecutan los puntos de referencia, por lo que simplemente puede usar los datos ya recopilados. También hay otros datos disponibles: sistema operativo, orden de bytes, etc.
if(TARGET_OS STREQUAL "Linux") list(APPEND CPPFLAGS -DC_LINUX) endif() if(NOT ARCH STREQUAL "ARM") if(ENDIAN STREQUAL "little") list(APPEND CPPFLAGS -DFPU_WORDS_BIGENDIAN=0) endif() if(ENDIAN STREQUAL "big") list(APPEND CPPFLAGS -DFPU_WORDS_BIGENDIAN=1) endif() endif()
En principio, esta parte no debería ser nada nuevo para las personas que al menos una vez vieron o escribieron un archivo CMake simple. Naturalmente, puede usar las bibliotecas, construirlas usted mismo, en general, usar cualquier medio proporcionado por CMake para describir el proceso de construcción de su aplicación.
Y luego debe garantizar la generación del archivo .test. ¿Qué herramientas proporciona la interfaz tets-suite para esto?
Hay 2 macros básicas
llvm_multisource y
llvm_singlesource , que son suficientes para la mayoría de los casos triviales.
- llvm_multisource se usa si la aplicación consta de varios archivos. Si no pasa los archivos de código fuente como parámetros al llamar a esta macro en su CMake, todos los archivos de código fuente ubicados en el directorio actual se utilizarán como base para la construcción. De hecho, actualmente se están realizando cambios en la interfaz de esta macro en el conjunto de pruebas, y el método descrito para transferir archivos de origen como parámetros de macro es la versión actual ubicada en la rama maestra. Anteriormente, había otro sistema: los archivos con código fuente tenían que escribirse en la variable Fuente (como estaba en la versión 7.0), y la macro no aceptaba ningún parámetro. Pero la lógica básica de implementación se ha mantenido igual.
- llvm_singlesource considera que cada archivo .c / .cpp es un punto de referencia separado y para cada uno recopila un archivo ejecutable separado.
De forma predeterminada, las dos macros descritas anteriormente para iniciar una aplicación integrada generan un comando que simplemente llama a esta aplicación. Y la comprobación de corrección se produce debido a la comparación con la salida esperada ubicada en el archivo con la extensión .reference_output (también con posibles sufijos .reference_output.little-endian, .reference_output.big-endian).
Si esto le conviene, es genial, una línea adicional (llamar a llvm_multisource o llvm_singlesource) es suficiente para que pueda iniciar la aplicación y obtener las siguientes métricas: tamaño del código (en secciones), tiempo de compilación, tiempo de enlace, tiempo de ejecución.
Pero, por supuesto, rara vez sucede tan suavemente. Es posible que deba cambiar una o más etapas. Y esto también es posible con la ayuda de acciones simples. Lo único que debe recordar es que si redefine una determinada etapa, debe describir todas las demás (incluso si se cumple el algoritmo predeterminado de su trabajo, lo que, por supuesto, es un poco molesto).
Hay macros en la API para describir acciones en cada etapa.
No hay mucho que escribir sobre la macro
llvm_test_prepare para la etapa preparatoria, los comandos que necesita ejecutar simplemente se pasan allí como un parámetro.
¿Qué se puede necesitar en la sección de lanzamiento? El caso más predecible es que la aplicación acepta algunos argumentos, archivos de entrada. Para esto, existe la macro
llvm_test_run , que acepta solo los argumentos de inicio de la aplicación (sin el nombre del archivo ejecutable) como parámetros.
llvm_test_run(--fixed 400 --cpu 1 --num 200000 --seed 1158818515 run.hmm)
Para cambiar las acciones en la etapa de validación, se
utiliza la macro
llvm_test_verify , que acepta cualquier comando como parámetro. Por supuesto, para verificar la corrección, es mejor usar las herramientas incluidas en la carpeta de herramientas. Proporcionan buenas oportunidades para comparar la salida generada con la esperada (hay un procesamiento separado para comparar números reales con algún error, etc.). Pero puede hacerlo en algún lugar y simplemente verificar que la solicitud se haya completado con éxito, etc.
llvm_test_verify("cat %o | grep -q 'exit 0'")
Pero, ¿qué pasa si es necesario recopilar algunas métricas adicionales? Hay una macro
llvm_test_metric para
esto .
llvm_test_metric(METRIC < > <, >)
Por ejemplo, para dhrystone, se puede obtener una métrica específica.
llvm_test_metric(METRIC dhry_score grep 'Dhrystones per Second' %o | awk '{print $4}')
Por supuesto, si necesita recopilar métricas adicionales para todas las pruebas, este método es algo inconveniente. O necesita agregar la llamada llvm_test_metric a las macros de nivel superior proporcionadas por la interfaz, o puede usar TEST_SUITE_RUN_UNDER (la variable CMake) y un script específico para recopilar métricas. La variable TEST_SUITE_RUN_UNDER es bastante útil y puede usarse, por ejemplo, para ejecutarse en simuladores, etc. De hecho, se escribe un comando que aceptará la aplicación con sus argumentos como entrada.
Como resultado, obtenemos algunos CMakeLists.txt del formulario
La integración no requiere esfuerzos adicionales, si la aplicación ya está construida usando CMake, entonces en CMakeList.txt en el conjunto de pruebas puede incluir el CMake existente para ensamblar y agregar algunas llamadas macro simples.
2. Ejecutando pruebasComo resultado de su trabajo, CMake generó un archivo de prueba especial de acuerdo con la descripción especificada. Pero, ¿cómo se ejecuta este archivo?
lit siempre usa algún archivo de configuración lit.cfg, que, en consecuencia, existe en el conjunto de pruebas. En este archivo de configuración, se indican varias configuraciones para ejecutar pruebas, incluido el formato de las pruebas ejecutables. Test-suite utiliza su propio formato, que se encuentra en la carpeta litsupport.
config.test_format = litsupport.test.TestSuiteTest()
Este formato se describe como una clase de prueba heredada de la prueba iluminada estándar y anulando el método principal de la interfaz de ejecución. También componentes importantes de litsupport es una clase con una descripción del plan de ejecución de prueba TestPlan, que almacena todos los comandos que deben ejecutarse en diferentes etapas y conocer el orden de las etapas. Para proporcionar la flexibilidad necesaria, también se introdujeron módulos en la arquitectura que debería proporcionar el método mutatePlan, dentro del cual pueden cambiar el plan de prueba, simplemente introduciendo una descripción de la recopilación de las métricas necesarias, agregando comandos adicionales para medir el tiempo de lanzamiento de la aplicación, etc. Debido a esta solución, la arquitectura se está expandiendo bien.

A continuación se presenta un ejemplo de la operación de prueba test-suite (con la excepción de los detalles en forma de clases TestContext, varias configuraciones iluminadas y las propias pruebas, etc.).

Encendido hace que se ejecute el tipo de prueba especificado en el archivo de configuración. TestSuiteTest analiza el archivo de prueba CMake generado y recibe una descripción de las etapas principales. Luego, todos los módulos encontrados son llamados para cambiar el plan de prueba actual, el lanzamiento está instrumentado. Luego se ejecuta el plan de prueba recibido: se llevan a cabo en el orden de la etapa de preparación, lanzamiento y validación. Si es necesario, se puede realizar el perfilado (agregado por uno de los módulos, si se configuró una variable durante la configuración que indica la necesidad de perfilar). El siguiente paso es recopilar métricas, las funciones para recopilar que se agregaron mediante módulos estándar en el campo metric_collectors en TestPlan, y luego se recopilan métricas adicionales descritas por el usuario en CMake.
3. Ejecutando test-suiteHay dos formas de ejecutar test-suite:
El resultado de cada prueba se muestra como
PASS: test-suite :: MultiSource/Benchmarks/Prolangs-C/football/football.test (m of n) ********** TEST 'test-suite :: MultiSource/Benchmarks/Prolangs-C/football/football.test' RESULTS ********** compile_time: 1.1120 exec_time: 0.0014 hash: "38254c7947642d1adb9d2f1200dbddf7" link_time: 0.0240 size: 59784 size..bss: 99800 … size..text: 37778 **********
Los resultados de diferentes lanzamientos se pueden comparar sin LNT (aunque este marco ofrece grandes oportunidades para analizar información utilizando diferentes herramientas, pero necesita una revisión por separado), utilizando el script incluido en el conjunto de pruebas
test-suite/utils/compare.py results_a.json results_b.json
Un ejemplo de comparación del tamaño del código de uno y el mismo punto de referencia de dos lanzamientos: con los indicadores -O3 y -Os
test-suite/utils/compare.py -m size SANDBOX1/build/O3.json SANDBOX/build/Os.json Tests: 1 Metric: size Program O3 Os diff test-suite...langs-C/football/football.test 59784 47496 -20.6%
Conclusión
La infraestructura para describir y ejecutar los puntos de referencia implementados en el conjunto de pruebas es fácil de usar y compatible, se adapta bien y, en principio, en mi opinión, utiliza soluciones bastante elegantes en su arquitectura, lo que, por supuesto, hace que el conjunto de pruebas sea una herramienta muy útil para los desarrolladores Los compiladores, así como este sistema, pueden modificarse para su uso en algunas tareas de análisis de datos.