Tentang pertanyaan kecepatan dan mengukurnya di Arduino



Masalah ini muncul dalam studi kinerja Arduino ketika menjalankan berbagai perintah (lebih lanjut tentang itu di pos terpisah). Dalam perjalanan studi, keraguan muncul tentang keteguhan waktu kerja perintah individu ketika nilai operan berubah (ternyata kemudian, tidak masuk akal) dan keputusan dibuat untuk mencoba memperkirakan waktu pelaksanaan perintah terpisah. Untuk ini, sebuah program kecil ditulis (yang mengatakan sketsa adalah meninggalkan kelas), yang, pada pandangan pertama, mengkonfirmasi hipotesis tersebut. Dalam kesimpulan, Anda dapat mengamati nilai 16 dan 20, tetapi kadang-kadang 28 dan bahkan 32 mikrodetik ditemukan. Jika kami mengalikan data yang diterima dengan 16 (frekuensi clock MK), kami mendapatkan waktu eksekusi dalam siklus MK (dari 256 menjadi 512). Sayangnya, proses berulang dari siklus program utama (dengan data awal yang sama), sambil mempertahankan gambaran keseluruhan, sudah memberikan distribusi waktu eksekusi yang berbeda, sehingga variasi waktu aktual tidak terkait dengan data awal. Hipotesis asli dibantah, tetapi menjadi menarik, dan apa sebenarnya yang terkait dengan sebaran yang begitu signifikan.

Catatan yang diperlukan - Saya mengerti betul bahwa program yang lebih canggih harus digunakan untuk mengukur waktu pelaksanaan perintah, tetapi untuk perkiraan kasar, yang akan ditunjukkan nanti sudah cukup.

Jadi, waktu berubah, dan sangat signifikan, kami mencari penyebab fenomena ini. Pertama-tama, kami memperhatikan banyaknya nilai yang diperoleh, lihat uraian pustaka kerja dari waktu ke waktu dan melihat bahwa 4ยตsec adalah kuantum pengukuran, jadi lebih baik pergi ke kuanta dan memahami bahwa kami mendapatkan 4 atau 5 (sangat sering) dan 6 atau 7 atau 8 unit (sangat jarang). Dengan babak pertama, semuanya mudah - jika nilai yang terukur terletak antara 4 dan 5 unit, maka hamburan menjadi tak terhindarkan. Selain itu, dengan mempertimbangkan sampel menjadi independen, kami dapat meningkatkan akurasi pengukuran dengan metode statistik, yang kami lakukan, memperoleh hasil yang dapat diterima.

Tetapi dengan babak kedua (6,7,8) segalanya menjadi lebih buruk. Kami menemukan bahwa pencar tidak berkorelasi dengan sumber data, yang berarti bahwa ini adalah manifestasi dari proses lain yang mempengaruhi waktu eksekusi perintah. Perlu dicatat bahwa emisi agak jarang dan tidak menunjukkan pengaruh yang signifikan terhadap nilai rata-rata yang dihitung. Akan mungkin untuk mengabaikan mereka sama sekali, tetapi ini bukan gaya kita. Secara umum, selama bertahun-tahun bekerja di bidang teknik, saya menyadari bahwa Anda tidak dapat meninggalkan kesalahpahaman, tidak peduli seberapa tidak penting tampaknya, karena mereka memiliki kemampuan menjijikkan untuk memukul di belakang (baik, atau di mana pun mereka mencapai) pada saat yang paling tidak tepat.

Kami mulai mengemukakan hipotesis 1 - yang paling nyaman (dalam kenyamanan dan fleksibilitas itu adalah yang kedua setelah intervensi langsung dari Pencipta) - gangguan perangkat lunak, tentu saja, bukan milik saya, program saya tidak pernah gagal, tetapi perpustakaan yang terhubung (kompiler, sistem operasi, browser, dll. - gantikan yang diperlukan). Selain itu, karena saya menjalankan program dalam emulator di www.tinkercad.com , Anda masih dapat merujuk ke bug emulator dan menutup topik, karena kode sumber tidak tersedia bagi kami. Kontra dari hipotesis ini:

  1. Dari siklus ke siklus, lokasi penyimpangan berubah, yang mengisyaratkan.
  2. Situs ini masih mendukung AutoDesk, meskipun argumennya agak lemah.
  3. "Kami menerima dalil bahwa apa yang terjadi bukanlah halusinasi, kalau tidak, itu tidak akan menarik."

Asumsi berikutnya adalah pengaruh dari beberapa proses latar belakang pada hasil pengukuran. Kami tampaknya tidak melakukan apa pun selain percaya, meskipun ... kami mengeluarkan hasilnya dalam Serial. Hipotesis 2 muncul - waktu output kadang-kadang (aneh seperti itu ... tapi itu terjadi) ditambahkan ke waktu eksekusi perintah. Meskipun meragukan berapa banyak output yang ada, tapi bagaimanapun - menambahkan Flush tidak membantu, menambahkan penundaan untuk menyelesaikan output dan tidak membantu, umumnya memindahkan output dari loop - lagi pula, waktu melonjak - ini jelas bukan Serial.

Nah, yang tersisa adalah pengaturan siklus itu sendiri (dari mana ketakutan untuk mengubah durasinya, tidak jelas) dan itu saja ... meskipun micros () tetap ada. Maksud saya waktu eksekusi panggilan pertama dari fungsi ini dan yang kedua adalah sama dan ketika mengurangi kedua nilai ini saya mendapatkan nol, tetapi jika asumsi ini salah?

Hipotesis 3 - kadang-kadang panggilan kedua dari penghitungan waktu memakan waktu lebih lama dari yang pertama, atau tindakan yang terkait dengan penghitungan waktu terkadang mempengaruhi hasilnya. Kami melihat kode sumber fungsi bekerja dengan waktu (arduino-1.8.4 \ hardware \ arduino \ avr \ cores \ arduino \ wiring.c - Saya telah berulang kali menyatakan sikap saya terhadap hal-hal seperti itu, saya tidak akan mengulangi sendiri) dan kami melihat bahwa 1 kali dari 256 siklus peningkatan perangkat keras bagian yang lebih muda dari penghitung terputus untuk meningkatkan bagian yang lebih tua dari penghitung.

Waktu eksekusi siklus kami adalah dari 4 hingga 5, sehingga kami dapat mengharapkan 170 * (4..5) / 256 = dari tiga hingga empat nilai anomali dalam segmen 170 pengukuran. Kami melihat - terlihat sangat mirip, sebenarnya ada 4 dari mereka. Untuk memisahkan alasan pertama dan kedua, kami membuat perhitungan dengan bagian kritis dengan gangguan terlarang. Hasilnya tidak banyak berubah, emisi masih ada tempatnya, yang berarti bahwa waktu ekstra dibawa oleh micros (). Di sini kita tidak dapat melakukan apa pun, meskipun kode sumber tersedia, kami tidak dapat mengubahnya - perpustakaan disertakan dalam binari. Tentu saja, kita dapat menulis fungsi kita sendiri bekerja dengan waktu dan mengamati perilaku mereka, tetapi ada cara yang lebih sederhana.

Karena pemrosesan "lama" dari interupsi adalah alasan yang mungkin untuk peningkatan durasi, kami mengecualikan kemungkinan terjadinya selama proses pengukuran. Untuk melakukan ini, tunggu manifestasinya dan baru kita melakukan siklus pengukuran. Karena gangguan terjadi jauh lebih jarang daripada siklus pengukuran kami berlangsung, kami dapat menjamin tidak adanya. Kami menulis fragmen yang sesuai dari program (menggunakan peretasan kotor dengan informasi yang diekstrak dari kode sumber) dan, "ini adalah sihir jalanan", semuanya menjadi normal - kami mengukur waktu eksekusi 4 dan 5 kuanta dengan nilai rata-rata waktu eksekusi operasi tambahan dengan PT dari siklus 166 jam, yang sesuai dengan nilai yang diukur sebelumnya. Hipotesis dapat dianggap dikonfirmasi.

Masih ada satu pertanyaan lagi - dan apa yang butuh begitu lama dalam interupsi, apa yang diperlukan
(7.8) - (5) ~ 2 quanta = * 4 = 8msec * 16 = 128 siklus prosesor? Kami beralih ke kode sumber (yaitu, ke kode assembler yang dihasilkan oleh kompiler di godbolt.com) dan kami melihat bahwa interupsi itu sendiri dijalankan kira-kira 70 siklus, 60 di antaranya terus-menerus, dan ketika membaca ada biaya tambahan 10 siklus, total 70 ketika mencapai interupsi - kurang dari yang diterima, tetapi cukup dekat. Kami mengaitkan perbedaan itu dengan perbedaan antara kompiler atau mode penggunaannya.

Nah, sekarang kita dapat mengukur waktu eksekusi sebenarnya dari perintah penambahan PT dengan berbagai argumen dan memastikan bahwa itu benar-benar banyak berubah ketika mengubah argumen: dari 136 langkah untuk 0,0 menjadi 190 untuk 0,63 (angka ajaib), dan ini hanya 162 untuk 10,63. Dengan probabilitas 99,9%, hal ini disebabkan oleh kebutuhan akan penyelarasan dan fitur implementasinya di perpustakaan khusus ini, tetapi penelitian ini jelas melampaui lingkup masalah yang dipertimbangkan.

Lampiran - teks program:
void setup() { Serial.begin(9600); } volatile float t; //   void loop() { int d[170]; unsigned long time,time1; float dt=1/170.; for (int i=0; i<170; ++i) { { //       time1=micros(); long time2; do { time2=micros(); } while ((time2 & ~0xFF) == (time1 & ~0xFF)); }; /**/ time1=micros(); //   /* cli(); //       -   */ t=10.63; //     t=t+dt; //   /* sei(); //    */ time = micros(); //   time1=time-time1; d[i]=time1/4; /* Serial.print(time1); //      Serial.flush(); //     Delay(20); //    */ }; //   ,     float sum=0; for (int i=0; i<170; ++i) { sum+=d[i]; Serial.println(d[i]); }; Serial.println((sum/170-2.11)*4*16); //2.11 โ€“     Serial.flush(); //    ,     } 

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


All Articles