Bagaimana saya bisa meningkatkan waktu startup meskipun banyak paket?

19

TL; DR Saya memiliki sejumlah besar paket yang mengganggu waktu startup saya. Jika Anda tidak percaya itu bisa terjadi, baca terus.


Waktu startup Emacs saya cukup kecil. Saya tidak menggunakan use-package, saya hanya mengatur banyak kait dan autoloads sehingga hampir semua kode ditangguhkan. Pada kenyataannya semuanya dimuat dalam biasanya kurang dari setengah detik, meskipun tampak seperti kekacauan gila.

Namun, seiring waktu saya melihat bahwa waktu startup saya mendapat teliti lebih lambat, entah kenapa. Ini akhirnya sampai pada titik di mana waktu startup adalah ≥ 1 detik. Saya akhirnya merasa cukup dan saya menggali akar masalahnya. Saya akhirnya berkomentar seluruh ~/.emacsfile saya dan menemukan bahwa waktu startup masih ≥ 1 detik. Bahkan, itu hanya mencukur ~ 0.2detik, terkadang bahkan kurang. Kemudian saya mencoba emacs -qdan menemukan bahwa waktu startup adalah ~ 0.1detik.

Setelah memeriksa bagian manual Elisp ini, saya mengetahui mengapa emacs -qbegitu banyak mengurangi waktu startup. Tampaknya emacs -qmenghentikan Emacs dari melakukan tiga hal saat startup:

  1. memuat file init Anda
  2. memuat default.elfile Anda
  3. panggilan package-initialize

Kami sudah mengesampingkan file init saya, karena mengomentari seluruh file saya ~/.emacshampir tidak ada. Saya tidak menggunakan default.elfile, jadi itu juga dikesampingkan. Yang meninggalkan package-initializesebagai biang keladi untuk kinerja hit.

Mengapa package-initializemenghabiskan banyak waktu startup? Itu adalah pertanyaan pertama yang saya tanyakan pada diri saya sendiri. Bukankah saya mengatur semuanya secara otomatis? Baiklah. Tapi itu justru masalah.

Saya menemukan posting ini yang menjelaskan bahwa "mengaktifkan" paket terdiri dari membaca file autoload dan mengatur path load. Ini jelas menimbulkan penalti I / O ketika Anda memiliki banyak paket karena Anda memiliki banyak file autoload untuk dibaca dan banyak jalur untuk ditetapkan. Sayangnya, tanpa ini, tugas mengelola pengisian otomatis jatuh ke tangan pengguna. Dengan kata lain, tanpa membiarkan package.elcrawl sistem file untuk file dan path autoload, saya harus mengelolanya sendiri yang bisa menjadi proses yang membosankan dan rawan kesalahan.

Saya lebih suka tidak menyusuri jalan itu. Saat ini saya memiliki 116 paket, dengan 107 di antaranya dari ELPA dan 25 di antaranya adalah dependensi. Saya yakin bahwa angka kekalahan ini adalah yang sangat merendahkan kinerja saya. Tapi saya dalam kesulitan karena saya tidak ingin menghapus paket saya.

Apakah ada obat dalam situasi seperti itu untuk mendapatkan waktu startup kilat saya kembali?


Memperbarui:

Kami telah memulai utas baru di emacs-develmilis tentang beberapa tambalan oleh Stefan Monnier (deskripsi tambalan ini ada di sini ) untuk menyelesaikan masalah ini. Siapa pun boleh mencoba tambalannya dan memberikan umpan balik.

Pembaruan lain:

Tampaknya Stefan Monnier tidak tertarik pada masalah ini lagi atau dia tidak menerima pesan saya. Saya cenderung percaya yang pertama, yang baik-baik saja, meskipun saya akan menghargai semacam respons dari dia jika itu masalahnya. Bagaimanapun, kode yang telah dia hasilkan untuk masalah ini sejauh ini bekerja dengan cukup baik. Tambalan terakhirnya dapat ditemukan di sini (untuk Emacs 25.3) dan di sini (untuk cabang utama Emacs).Saya telah melihat peningkatan yang baik pada waktu startup saya berkat tambalannya dan saya berada pada titik di mana saya merasa nyaman dengan waktu startup saya sedemikian rupa sehingga dapat dioptimalkan semaksimal mungkin tanpa memotong fitur kustomisasi saya. Saya berharap tambalan-tambalan ini akan membuatnya menjadi arus utama Emacs di beberapa titik, tapi saya kira saya (atau orang lain) harus mengambil obor untuk itu sekarang, bukan Stefan. Kami memiliki sedikit spar di milis tentang penugasan hak cipta dan lisensi. Awalnya saya merasa tidak nyaman melakukannya, tetapi karena beberapa komentar dari Richard Stallman dan yang lainnya, tugas hak cipta mungkin tidak seketat yang saya kira. Selain itu, mungkin bagi saya untuk melakukan karya saya ke domain publik sebagai alternatif penugasan hak cipta.

Bagaimanapun, terima kasih Stefan untuk tambalan sejauh ini! Saya harap Anda akan terus mengembangkan perubahan ini, tetapi jika tidak, tidak apa-apa dan saya dapat terus mengembangkannya di beberapa titik. Saya juga berterima kasih kepada semua orang yang menawarkan wawasan dan kontribusi untuk menyelesaikan masalah ini.

Namun pembaruan lainnya:

Wow, sepertinya fitur ini akhirnya mendarat dan akan ada di Emacs 27. Terima kasih kepada Stefan Monnier!

GDP2
sumber
Pertanyaan bagus
Drew
use-packageadalah cara untuk pergi untuk ini.
Dodgie
Tidak mencoba mengecilkan masalah (latensi startup penting!), Tetapi pertimbangkan menjalankan emacs sebagai daemon / server sehingga Anda hanya membayar biaya startup satu kali.
GManNickG
1
@ GMNickG Saya menjalankan Emacs sebagai server. Sayangnya, kadang-kadang saya mendorong Emacs terlalu keras atau mengotak-atik terlalu banyak dan restart adalah cara terbaik untuk membersihkan segalanya. Ketika itu terjadi, saya ingin waktu startup saya menjadi optimal.
GDP2

Jawaban:

13

Salah satu pilihan desain dalam package.el adalah mencoba dan membuat hal-hal "sederhana". Bagian dari ini adalah package-initializepencarian untuk semua paket yang diinstal, kemudian mencoba untuk mencari tahu mana dari mereka yang harus diaktifkan (sesuai dengan pinning, dan kemutakhiran versi jika ada beberapa versi dari paket yang sama tersedia), kemudian memuat masing-masing mengaktifkan <pkg>-autoloads.elfile paket .

Jadi untuk N paket yang diinstal, itu berarti pada dasarnya membaca <pkg>-pkg.elfile N-deskripsi paket dan <pkg>-autoloads.elfile N. Untuk Ns besar, itu bisa menjadi masalah serius. Masalah kinerja potensial lainnya adalah bahwa ia akan menambahkan elemen N ke load-path, jadi setiap kali Anda loadEmacs akan mencari melalui direktori N, sehingga masing load- masing diperlambat.

Ada berbagai cara yang dapat kita coba dan percepat:

  • Berikan beberapa cara untuk melakukan precompute ~/.emacs.d/elpa/package-initialize.el(c)file yang akan menjadi hasil penggabungan semua hak <pkg>-autoloads.eldalam urutan yang benar. Maka package-initializebisa saja memuat file ini ketika ada dan lewati yang lainnya. Anda kemudian perlu beberapa cara untuk menyegarkan / membersihkan package-initialize.el(c)file ketika paket ditambahkan / diperbarui / dihapus atau ketika Anda mengubah file package-pinned-packagesAnda package-load-list. Saya pikir ini dapat dilakukan dengan sedikit perubahan pada sistem (satu-satunya hal yang benar-benar perlu diubah saya pikir adalah package-initializeagar dapat dikatakan "hanya-aktifkan" tanpa memuat metadata tentang paket yang tersedia).

  • Berikan beberapa cara untuk membangun / memanipulasi paket super, yaitu paket yang menggabungkan beberapa paket menjadi satu (jadi hanya ada satu elemen yang ditambahkan load-path, satu <pkg>-pkg.eldan satu <pkg>-autoloads.eldimuat). Ini mungkin memberikan lebih sulit untuk dilakukan (karena Anda tidak dapat mengaktifkan hanya sebagian dari paket-paket yang terdapat dalam paket-super seperti itu, sehingga analisis dependensi / versi bisa rumit).

Opsi pertama di atas seharusnya cukup mudah diimplementasikan dan akan menjadi package-initialize jauh lebih cepat ketika Anda memiliki banyak paket yang diinstal. Jika Anda tertarik untuk mencoba ini, jangan ragu untuk meminta bantuan kepada saya.

FWIW, saya baru saja mencoba membuat file mega-autoloads "dengan tangan" pada pengaturan pengujian saya. Hasil: sementara package-initializememakan waktu sekitar 0,9 detik, memuat mega-autoloads.elfile membutuhkan 0,3 detik yang dapat saya bawa ke 0,2 detik dengan membiarkan-mengikat load-source-file-functionke nol, dan ke 0,1 detik dengan byte-mengkompilasi file. Saya berharap mempercepat, lebih jujur, tapi masih bermanfaat.

[EDIT] Pendekatan "mega autoloads" ini sekarang tersedia di cabang utama Emacs (untuk menjadi Emacs-27 di masa depan yang jauh). Itu dikendalikan oleh package-quickstartvariabel baru .

Stefan
sumber
Itulah beberapa ide yang sangat menarik. Yang pertama terdengar lebih sederhana dan tidak terlalu menantang. Yang kedua cukup menarik, tapi itu terdengar seperti pekerjaan untuk para package.elpengembang. Saran macam apa yang Anda miliki tentang memulai dengan opsi pertama itu? Saya ingin melihat apa yang bisa saya pecahkan dengan itu, karena tampaknya jauh lebih bisa diterapkan.
GDP2
el-get menggunakan pendekatan file autoloads tunggal, itu pada dasarnya bekerja sebagian besar waktu. Ada masalah dengan beberapa paket yang autoloadsnya bergantung pada lokasi di filesystem tempat mereka dievaluasi. Namun saya tidak mengikuti apa yang Anda maksud dengan "dalam urutan yang benar", mengapa pemesanan pemuatan otomatis menjadi masalah (saya tidak pikir itu bahkan deterministik untuk package.el saat ini)?
npostavs
@Stefan tolong bagikan solusinya di sini, jika memungkinkan.
Manuel Uberti
1
@npostavs: Sebagian besar <pkg>-autoloads.elfile hanya mengatur autoloads dan memang tidak peduli tentang pemesanan, tetapi tidak ada yang mencegah mereka melakukan hal-hal lain secara acak, dan package.el tidak menjamin bahwa paket yang <pkg>bergantung akan diaktifkan terlebih dahulu <pkg>.
Stefan
1
Pembaruan lain tentang masalah ini: kami telah memulai topik baru di milis di sini dan siapa pun bebas mengomentari atau menguji perubahan Stefan.
GDP2
6

Masalah yang Anda gambarkan tentang package-initializemengambil begitu banyak waktu untuk memuat adalah masalah yang sudah diketahui. Ini juga salah satu masalah yang coba dipecahkan oleh beberapa kerangka kerja emacs dengan memuat autoload secara manual.

Saya melihat dua solusi untuk masalah Anda.

  1. Tulis (atau ekstrak dari suatu kerangka kerja) fungsionalitas untuk mengatur jalur dan memuat autoload paket yang Anda minati.
  2. Gunakan kerangka kerja yang secara eksplisit menargetkan kecepatan. Saya pribadi merekomendasikan emacs DOOM . Dengan kerangka kerja ini, saya memuat lebih dari 200 paket dalam waktu sekitar 1 detik.

Salah satu resons utama untuk merekomendasikan emacs DOOM adalah bahwa kerangka kerja menempatkan manajemen paket di luar emacs. Jangan salah menafsirkan saya, masih emacs yang melakukan manajemen paket, hanya saja mengelola paket dilakukan di luar sesi pengguna standar. Filosofi di sini adalah: ketika biasanya memulai emacs, kita harus dapat mengasumsikan bahwa semua paket ada dan sudah dapat dimuat. Ini menghemat banyak waktu. DOOM emacs menyediakan semacam yang setara apt-getatau pacmanuntuk emacs. Setelah sebuah paket diinstal, setiap kali emacs dimulai itu diasumsikan sudah diinstal; tidak ada pertanyaan yang ditanyakan.

UndeadKernel
sumber
Fiuh, senang mengetahui bahwa masalah ini tidak hanya mempengaruhi saya. Terima kasih telah mengarahkan saya ke DOOM Emacs. Saya harus melihat lebih dekat dan melihat apa yang bisa saya sesuaikan dengan pengaturan saya sendiri.
GDP2
Saya telah bermain-main dengan DOOM emacs (dan berkontribusi ketika saya bisa) untuk beberapa waktu sekarang. Jika Anda mengalami masalah, jangan ragu untuk menghubungi saya.
UndeadKernel