Sistem yang fleksibel untuk menguji dan mengumpulkan metrik program menggunakan LLVM test-suite sebagai contoh

Pendahuluan


Sebagian besar pengembang jelas telah mendengar tentang beberapa perkembangan open-source yang cukup signifikan seperti sistem LLVM dan compiler dentang. Namun, LLVM sekarang tidak hanya sistem itu sendiri untuk membuat kompiler, tetapi juga ekosistem besar yang mencakup banyak proyek untuk menyelesaikan berbagai masalah yang muncul selama tahap pembuatan kompiler (biasanya setiap proyek tersebut memiliki repositori terpisah sendiri). Bagian dari infrastruktur secara alami termasuk alat pengujian dan benchmarking, seperti ketika mengembangkan kompiler, efektivitasnya adalah indikator yang sangat penting. Salah satu proyek infrastruktur uji LLVM individual ini adalah test-suite ( dokumentasi resmi ).

Suite uji LLVM


Sepintas pada repositori test-suite, tampaknya ini hanya seperangkat tolok ukur dalam C / C ++, tetapi ini tidak sepenuhnya benar. Selain kode sumber program tempat pengukuran kinerja akan dilakukan, uji-suite mencakup infrastruktur yang fleksibel untuk membangun, menjalankan, dan mengumpulkan metrik. Secara default, ia mengumpulkan metrik berikut: waktu kompilasi, waktu eksekusi, waktu tautan, ukuran kode (dalam bagian).

Test-suite secara alami berguna untuk pengujian dan penyusun benchmarking, tetapi juga dapat digunakan untuk beberapa tugas penelitian lainnya di mana beberapa basis kode C / C ++ diperlukan. Mereka yang pernah melakukan upaya untuk melakukan sesuatu di bidang analisis data, saya pikir, dihadapkan dengan masalah kekurangan dan fragmentasi sumber data. Suite uji, meskipun tidak terdiri dari sejumlah besar aplikasi, tetapi memiliki mekanisme pengumpulan data terpadu. Menambahkan aplikasi Anda sendiri ke koleksi, mengumpulkan metrik yang diperlukan untuk tugas khusus Anda sangat sederhana. Oleh karena itu, menurut pendapat saya, test-suite (selain tugas-tugas utama pengujian dan benchmarking) adalah pilihan yang baik untuk proyek dasar, di mana Anda dapat membangun pengumpulan data untuk tugas-tugas di mana Anda perlu menganalisis beberapa fitur dari kode program atau beberapa karakteristik dari program.

Struktur suite uji LLVM


test-suite |----CMakeLists.txt //  CMake ,   ,  | //   .. | |---- cmake | |---- .modules //        , | //   API    | |---- litsupport //  Python,      test-suite, | //    lit (  LLVM) | |---- tools //   :    | //     (    | // ),    .. | | //     | |---- SingleSource //   ,       | // .        . | |---- MultiSource //   ,      | //  .        | //  . | |---- MicroBenchmarks // ,   google-benchmark.   | //  ,    ,  | //       | |---- External //    ,     test-suite,  | // ,     (  ) | // -    

Strukturnya sederhana dan mudah.

Prinsip kerja


Seperti yang Anda lihat, CMake dan format uji lit khusus bertanggung jawab untuk semua pekerjaan mendeskripsikan perakitan, peluncuran, dan pengumpulan metrik.

Jika kami mempertimbangkannya dengan cara yang sangat abstrak, jelas bahwa proses pembandingan menggunakan sistem ini terlihat sederhana dan sangat dapat diprediksi:


Bagaimana ini terlihat lebih detail? Pada artikel ini, saya ingin membahas peran CMake dalam seluruh sistem dan apa satu-satunya file yang harus Anda tulis jika Anda ingin menambahkan sesuatu ke sistem ini.

1. Membangun aplikasi uji.

Sebagai sistem build, ini telah menjadi standar de facto untuk program C / C ++ CMake. CMake mengkonfigurasi proyek dan menghasilkan file make, ninja, dll. Tergantung pada preferensi pengguna. untuk konstruksi langsung.
Namun, dalam test-suite CMake menghasilkan tidak hanya aturan tentang cara membangun aplikasi, tetapi juga mengkonfigurasi tes itu sendiri.

Setelah memulai CMake, file lain (dengan ekstensi .test) akan ditulis ke direktori build dengan deskripsi bagaimana aplikasi harus dijalankan dan diperiksa kebenarannya.

Contoh file .test paling standar

 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 

File dengan ekstensi .test dapat berisi bagian-bagian berikut:

  • SIAPKAN - menjelaskan tindakan apa pun yang harus dilakukan sebelum meluncurkan aplikasi, sangat mirip dengan metode Sebelum yang ada dalam kerangka kerja unit pengujian yang berbeda;
  • RUN - menjelaskan cara menjalankan aplikasi;
  • VERIFIKASI - menjelaskan cara memeriksa operasi aplikasi yang benar;
  • METRIC - menjelaskan metrik yang perlu dikumpulkan tambahan dalam standar.

Bagian mana pun dari ini dapat dihilangkan.

Tetapi karena file ini dihasilkan secara otomatis, file CMake untuk benchmark yang menjelaskan: cara mendapatkan file objek, cara merakitnya ke dalam aplikasi, dan kemudian apa yang harus dilakukan dengan aplikasi ini.

Untuk pemahaman yang lebih baik tentang perilaku default dan bagaimana ini dijelaskan, pertimbangkan contoh beberapa CMakeLists.txt

 list(APPEND CFLAGS -DBREAK_HANDLER -DUNICODE-pthread) #      (         ..     CMak,       ) list(APPEND LDFLAGS -lstdc++ -pthread) #       

Bendera dapat diatur tergantung pada platform, file DetectArchitecture disertakan dalam modul cmake suite-uji, yang menentukan platform target tempat benchmark dijalankan, sehingga Anda dapat menggunakan data yang sudah dikumpulkan. Data lain juga tersedia: sistem operasi, urutan byte, dll.

 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() 

Pada prinsipnya, bagian ini seharusnya tidak menjadi sesuatu yang baru bagi orang-orang yang setidaknya pernah melihat atau menulis file CMake sederhana. Secara alami, Anda dapat menggunakan perpustakaan, membangunnya sendiri, secara umum, menggunakan segala cara yang disediakan oleh CMake untuk menggambarkan proses membangun aplikasi Anda.

Dan kemudian Anda perlu menyediakan pembuatan file .test. Alat apa yang disediakan antarmuka tets-suite untuk ini?

Ada 2 makro dasar llvm_multisource dan llvm_singlesource , yang cukup untuk sebagian besar kasus sepele.

  • llvm_multisource digunakan jika aplikasi terdiri dari beberapa file. Jika Anda tidak meneruskan file kode sumber sebagai parameter saat memanggil makro ini di CMake Anda, maka semua file kode sumber yang terletak di direktori saat ini akan digunakan sebagai dasar untuk membangun. Bahkan, perubahan saat ini sedang terjadi di antarmuka makro ini di test-suite, dan metode yang dijelaskan untuk mentransfer file sumber sebagai parameter makro adalah versi saat ini yang terletak di cabang utama. Sebelumnya, ada sistem lain: file dengan kode sumber harus ditulis ke variabel Sumber (seperti pada rilis 7.0), dan makro tidak menerima parameter apa pun. Tetapi logika dasar implementasi tetap sama.
  • llvm_singlesource menganggap bahwa setiap file .c / .cpp adalah patokan terpisah dan untuk masing-masing mengumpulkan file yang dapat dieksekusi terpisah.

Secara default, kedua makro yang dijelaskan di atas untuk meluncurkan aplikasi yang dibangun menghasilkan perintah yang hanya memanggil aplikasi ini. Dan pemeriksaan kebenaran terjadi karena perbandingan dengan output yang diharapkan terletak di file dengan ekstensi .reference_output (juga dengan kemungkinan suffix .reference_output.little-endian, .reference_output.big-endian).

Jika ini cocok untuk Anda, itu bagus, satu baris tambahan (memanggil llvm_multisource atau llvm_singlesource) sudah cukup bagi Anda untuk memulai aplikasi dan mendapatkan metrik berikut: ukuran kode (dalam beberapa bagian), waktu kompilasi, waktu tautan, waktu eksekusi.

Tapi, tentu saja, itu jarang terjadi dengan lancar. Anda mungkin perlu mengubah satu atau beberapa tahapan. Dan ini juga dimungkinkan dengan bantuan tindakan sederhana. Satu-satunya hal yang perlu Anda ingat adalah bahwa jika Anda mendefinisikan ulang beberapa tahap, Anda perlu menggambarkan semua yang lain (bahkan jika algoritma default dari pakaian kerja mereka, yang, tentu saja, sedikit mengecewakan).

Ada makro di API untuk menjelaskan tindakan di setiap tahap.

Tidak ada banyak yang harus ditulis tentang makro llvm_test_prepare untuk tahap persiapan, perintah yang perlu Anda jalankan hanya diteruskan ke sana sebagai parameter.

Apa yang mungkin diperlukan di bagian peluncuran? Kasus yang paling dapat diprediksi adalah bahwa aplikasi menerima beberapa argumen, memasukkan file. Untuk ini, ada makro llvm_test_run , yang hanya menerima argumen startup aplikasi (tanpa nama file yang dapat dieksekusi) sebagai parameter.

 llvm_test_run(--fixed 400 --cpu 1 --num 200000 --seed 1158818515 run.hmm) 

Untuk mengubah tindakan pada tahap validasi, makro llvm_test_verify digunakan , yang menerima perintah apa pun sebagai parameter. Tentu saja, untuk memverifikasi kebenarannya, lebih baik menggunakan alat yang termasuk dalam folder alat. Mereka memberikan peluang bagus untuk membandingkan output yang dihasilkan dengan yang diharapkan (ada proses terpisah untuk membandingkan bilangan real dengan beberapa kesalahan, dll.). Tetapi Anda bisa di suatu tempat dan hanya memeriksa bahwa aplikasi selesai dengan sukses, dll.

 llvm_test_verify("cat %o | grep -q 'exit 0'") # %o -   placeholder   ,   lit.          lit,    ,    .    lit (  ,   LLVM)      (   <a href="https://llvm.org/docs/CommandGuide/lit.html"> </a>) 

Tetapi bagaimana jika ada kebutuhan untuk mengumpulkan beberapa metrik tambahan? Ada makro llvm_test_metric untuk ini .

 llvm_test_metric(METRIC < > <,   >) 

Misalnya, untuk dhrystone, metrik khusus untuknya dapat diperoleh.

 llvm_test_metric(METRIC dhry_score grep 'Dhrystones per Second' %o | awk '{print $4}') 

Tentu saja, jika Anda perlu mengumpulkan metrik tambahan untuk semua tes, metode ini agak tidak nyaman. Anda harus menambahkan panggilan llvm_test_metric ke makro tingkat lebih tinggi yang disediakan oleh antarmuka, atau Anda dapat menggunakan TEST_SUITE_RUN_UNDER (variabel CMake) dan skrip khusus untuk mengumpulkan metrik. Variabel TEST_SUITE_RUN_UNDER cukup berguna, dan dapat digunakan, misalnya, untuk berjalan di simulator, dll. Bahkan, sebuah perintah ditulis ke dalamnya yang akan menerima aplikasi dengan argumennya sebagai input.

Sebagai hasilnya, kami mendapatkan beberapa formulir CMakeLists.txt

 #       llvm_test_run(--fixed 400 --cpu 1 --num 200000 --seed 1158818515 run.hmm) llvm_test_verify("cat %o | grep -q 'exit 0'") llvm_test_metric(METRIC score grep 'Score' %o | awk '{print $4}') llvm_multisource() # llvm_multisource(my_application)    

Integrasi tidak memerlukan upaya tambahan, jika aplikasi sudah dibangun menggunakan CMake, maka dalam CMakeList.txt dalam test-suite Anda dapat menyertakan CMake yang ada untuk perakitan dan menambahkan beberapa panggilan makro sederhana.

2. Menjalankan tes

Sebagai hasil dari kerjanya, CMake menghasilkan file tes khusus sesuai dengan deskripsi yang ditentukan. Tetapi bagaimana file ini dijalankan?

lit selalu menggunakan beberapa file konfigurasi lit.cfg, yang, sesuai dengan itu, ada di dalam test-suite. Dalam file konfigurasi ini, berbagai pengaturan untuk menjalankan tes ditunjukkan, termasuk format tes yang dapat dieksekusi. Test-suite menggunakan formatnya sendiri, yang terletak di folder litsupport.

 config.test_format = litsupport.test.TestSuiteTest() 

Format ini dideskripsikan sebagai kelas uji yang diwarisi dari uji standar menyala dan menimpa metode utama dari antarmuka eksekusi. Juga komponen penting dari litsupport adalah kelas dengan deskripsi rencana eksekusi tes TestPlan, yang menyimpan semua perintah yang harus dieksekusi pada tahapan yang berbeda dan mengetahui urutan tahapan. Untuk memberikan fleksibilitas yang diperlukan, modul juga diperkenalkan ke dalam arsitektur yang harus menyediakan metode mutatePlan, di mana mereka dapat mengubah rencana pengujian, hanya memperkenalkan deskripsi kumpulan metrik yang diperlukan, menambahkan perintah tambahan untuk mengukur waktu untuk meluncurkan aplikasi, dll. Karena solusi ini, arsitekturnya berkembang dengan baik.



Contoh dari operasi uji test-suite (dengan pengecualian rincian dalam bentuk kelas TestContext, berbagai konfigurasi yang menyala dan tes itu sendiri, dll.) Disajikan di bawah ini.



Lit menyebabkan tipe tes yang ditentukan dalam file konfigurasi dieksekusi. TestSuiteTest mem-parsing file uji CMake yang dihasilkan, menerima deskripsi tahapan utama. Kemudian, semua modul yang ditemukan dipanggil untuk mengubah rencana pengujian saat ini, peluncurannya diinstrumentasi. Kemudian rencana pengujian yang diterima dijalankan: semuanya dilakukan sesuai dengan tahapan persiapan, peluncuran, dan validasi. Jika perlu, pembuatan profil dapat dilakukan (ditambahkan oleh salah satu modul, jika variabel diatur selama konfigurasi yang menunjukkan perlunya pembuatan profil). Langkah berikutnya adalah mengumpulkan metrik, fungsi untuk mengumpulkan yang ditambahkan oleh modul standar di bidang metric_collectors di TestPlan, dan kemudian metrik tambahan yang dijelaskan oleh pengguna di CMake dikumpulkan.

3. Menjalankan test-suite

Ada dua cara untuk menjalankan test-suite:

  • Manual, mis. doa perintah berurutan.
     cmake -DCMAKE_CXX_COMPILER:FILEPATH=clang++ -DCMAKE_C_COMPILER:FILEPATH=clang test-suite #  make #   llvm-lit . -o <output> #   
  • menggunakan LNT (sistem lain dari ekosistem LLVM yang memungkinkan Anda untuk menjalankan tolok ukur, menyimpan hasil ke database, menganalisis hasil di antarmuka web). LNT, dalam tim uji coba, melakukan langkah yang sama seperti pada paragraf sebelumnya.
     lnt runtest test-suite --sandbox SANDBOX --cc clang --cxx clang++ --test-suite test-suite 

Hasil untuk setiap tes ditampilkan sebagai

 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 ********** 

Hasil dari peluncuran yang berbeda dapat dibandingkan tanpa LNT (meskipun kerangka kerja ini memberikan peluang besar untuk menganalisis informasi menggunakan alat yang berbeda, tetapi perlu ditinjau secara terpisah), menggunakan skrip yang disertakan dalam test-suite

 test-suite/utils/compare.py results_a.json results_b.json 

Contoh membandingkan ukuran kode satu dan tolok ukur yang sama dari dua peluncuran: dengan flag -O3 dan -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% 

Kesimpulan


Infrastruktur untuk menggambarkan dan menjalankan tolok ukur yang diterapkan dalam test-suite mudah digunakan dan didukung, berskala dengan baik, dan pada prinsipnya, menurut saya, menggunakan solusi yang cukup elegan dalam arsitekturnya, yang, tentu saja, menjadikan test-suite alat yang sangat berguna bagi pengembang. kompiler, serta sistem ini dapat dimodifikasi untuk digunakan dalam beberapa tugas analisis data.

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


All Articles