Jenis Stabil dengan Snoopompile.jl dan Cthulhu.jl untuk Julia Kinerja Tinggi

 – Beragampengetahuan
11 mins read

Jenis Stabil dengan Snoopompile.jl dan Cthulhu.jl untuk Julia Kinerja Tinggi – Beragampengetahuan

Oleh: Big Lake Consulting

Re -Post dari:

Posting ini ditulis oleh Steven Whitaker.

Bahasa pemrograman Julia tingkat tinggi dengan bangga dapat mencapai kecepatan yang sama dengan C.Julia dapat berjalan cepat, meskipun menjadi bahasa yang dinamis, karena dihitung dan memiliki inferensi yang cerdas.

Jenis penalaran adalah proses komilrasing Julia tentang jenis objek, yang memungkinkan kompilasi untuk membuat kode mesin yang efektif untuk semua jenis di tangan.

Namun, kode Julia dapat ditulis dengan cara yang mencegah pengurangan konkret, dengan menulis fungsi yang tidak terjadi. (Saya akan menjelaskan nanti.

Untungnya, ada alat yang dapat digunakan pengembang Julia yang membuat kode membuat kode tidak berhasil.

Dalam posting ini, kita akan belajar tentang stabilitas jenis dan bagaimana pengaruhnya terhadap kinerja. Kami kemudian akan melihat cara menggunakan reapsnooppile.jl dan cthulhu.jlto memposisikan dan menyelesaikan opsi.

Salah satu fungsi adalah tipe format jika jenis output dari fungsi dapat ditentukan secara khusus jenis input untuk fungsi, tanpa waktu berjalan.

Untuk mengilustrasikan, pertimbangkan metode fungsional berikut:

f(x::Int) = "stable"f(x::Float64) = rand(Bool) ? 1 : 2.0

Dalam contoh ini, jika kita menelepon f(x) Di mana x adalah satu IntKompiler dapat mengetahui bahwa output akan menjadi satu Stringtanpa mengetahui nilainya x,Karena itu f(x::Int) adalah tipe yang stabil. Dengan kata lain, itu tidak masalah x Menjadi 1Kemudian -1atau 176859431; Nilai pengembalian akan selalu menjadi satu StringJika x adalah satu Int.

Di sisi lain, jika kita menelepon f(x) Di mana x adalah a Float64Kompiler tidak tahu bahwa output akan Int atau a Float64Karena itu tergantung pada hasilnya rand(Bool)Dihitung pada saat berlari. Karena itu,f(x::Float64) Tidak mungkin.

Berikut adalah contoh yang lebih canggih dari kemampuan untuk mengetik:

function g(x)    if x < 0        return 0    else        return x    endend

Dalam contoh ini,g(x) Adalah yang tidak dapat dibatalkan karena output akan menjadi satu Intatau apa pun x adalah, dan semuanya tergantung pada nilai xtanpa diketahui pada saat kompilasi. (Namun, perhatikan itu g(x) Menjadi StabilisatorJika x adalah satu IntKarena kedua cabangnya if Pernyataan Tipe yang sama.)

Dan kadang-kadang fungsi yang dapat terlihat gaya gaya akan dihilangkan untuk tidak digunakan pada input. Contoh: Contoh:

h(x::Array) = x[1] + 1

Dalam hal ini,h([1]) adalah tipe yang stabil, tapi h(Any[1]) Bukan kenapa? Karena dengan h([1])Kemudianx adalah a Vector{Int}Jadi kompiler tahu jenisnya x[1] Akan menjadi IntDi sisi lain, dengan h(Any[1])Kemudianx adalah a Vector{Any}Jadi pemikiran kompilerx[1] Bisa menjadi bagian dari jenis apa pun.

Untuk mengulangi: Fungsi adalah format tipe, kompiler dapat menemukan jenis spesifik dari nilai pengembalian hanya input, tanpa waktu menjalankan waktu.

Aspek lain dari tipe inferensial sangat berguna untuk dipahami saat menerjemahkan (termasuk inferensi tipe) terjadi.

Dalam bahasa statis seperti C, seluruh program dikompilasi sebelum dijalankan. Ini mungkin karena jenis semua variabel diketahui, sehingga kode mesin khusus untuk tycescan yang dibuat terlebih dahulu.

Dalam bahasa yang dijelaskan seperti Python, tidak ada kode yang dihitung sebagai fluktuasi dinamis, yang berarti bahwa tipe mereka tidak benar -benar diketahui digunakan (yaitu selama waktu berjalan).

Program Julia bisa banyak terletak di mana saja di mana C dan Python’s Betwensethe dan Python, dan tempat itu, ada dalam jenis stabilitas.

Dalam bahasa yang diterjemahkan hanya dalam waktu (JIT) seperti Julia, terjemahan terjadi begitu tipe diketahui.

  • Jika program Julia benar -benar stabil, pikirkan jenis yang dapat menemukan jenis semua variabel dalam programSebelum menjalankan kode apapunAkibatnya, seluruh program dapat diterjemahkan jika ditulis dalam bahasa statis. Inilah yang memungkinkan Julia mencapai kecepatan yang sama dengan C.
  • Program Julia sepenuhnya tidak dapat menghilangkan, semua fungsi harus diterjemahkan secara individual. Dalam hal ini, kompilasi terjadi pada saat fungsi yang disebut karena waktu berjalan dari semua jenis kepala di final, harus mampu. Bahasa yang dijelaskan.

Jalankan program Julia dengan pencetakan seperti mengemudi di jalan dan memukul semua lampu merah. Julia akan menyusun semua kode untuk jenis keberhasilan dan kemudian mulai berjalan. Terus melakukannya, seperti cara mobil dapat terus mendorong cahaya ke hijau.

Seperti yang disiratkan kesamaan ini, dan seperti yang telah saya nyatakan sebelumnya, stabilitas tipe ini menyiratkan kinerja. Kemungkinan dapat menyebabkan penurunan kinerja yang berbeda, termasuk:

  • Dinamis (juga dikenal sebagai waktu berjalan).Jika kompiler mengetahui jenis input untuk suatu fungsi, kode mesin dibuat dapat menyertakan metode spesifik dari metode tertentu yang ditentukan oleh tipe -tipe tersebut. Tetapi jika kompiler tidak tahu tipe -tipe itu, kode mesin harus menyertakan instruksi untuk mengimplementasikan pengiriman dinamis.
  • Tingkatkan alokasi memori.Jika kompiler tidak tahu jenis apa puna yang akan dimiliki, tidak mungkin untuk memasukkannya ke dalam register bahkan mengalokasikan ruang tumpukan untuk itu. Akibatnya, itu harus diperlakukan dengan koleksi sampah.
  • Kode umum di bawah level optimal.Bayangkan sintesis isi array dalam satu loop. Jika kompiler tahu array hanya berisi Float64S, dapat dioptimalkan untuk menghitung SUMA seefektif mungkin, misalnya, menggunakan instruksi CPU khusus. Optimalisasi tidak terjadi jika kompiler tidak tahu data mana yang berfungsi.

Berikut adalah contoh (terinspirasi oleh jawaban tumpukan overflow ini) untuk menggambarkan stabilitas ImpactType mungkin memiliki kinerja:

x = 0f() = [i + x for i = 1:10^6]const y = 0g() = [i + y for i = 1:10^6]using BenchmarkTools@btime f() @btime g() 

Perhatikan bahwa versi tidak dapat mengecualikan dua lebih lambat!

Sekarang pertanyaannya adalah, bagaimana kita tahu apakah atau di mana kode kita tidak dapat dihapus?

Mari kita gunakan contoh untuk menggambarkan cara menggunakan snoopCompile.jl.first, kode yang ingin kami analisis:

module Originalstruct Alg1 endstruct Alg2 endfunction process(alg::String)    if alg == "alg1"        a = Alg1()    elseif alg == "alg2"        a = Alg2()    end    data = get_data(a)    result = _process(a, data)    return resultendget_data(::Alg1) = (1, 1.0, 0x00, 1.0f0, "hi", [0.0], (1, 2.0))function _process(::Alg1, data)    val = data[1]    if val < 0        val = -val    end    result = map(data) do d        process_item(d, val)    end    return resultendprocess_item(d::Int, val) = d + valprocess_item(d::AbstractFloat, val) = d * valprocess_item(d::Unsigned, val) = d - valprocess_item(d::String, val) = d * string(val)process_item(d::Array, val) = d .+ valprocess_item(d::Tuple, val) = d .- valget_data(::Alg2) = rand(5)_process(::Alg2, data) = error("not implemented")end

Kami akan menggunakan @snoop_inference MacRoto menganalisis kode ini. Menyadari bahwa makro ini harus digunakan dalam sesi Julia baru (setelah mengunduh kode akan dianalisis, tetapi sebelum menjalankan apa pun) untuk hasil analisis yang paling akurat.

julia> using SnoopCompileCorejulia> tinf = @snoop_inference Original.process("alg1");julia> using SnoopCompilejulia> tinfInferenceTimingNode: 0.144601/0.247183 on Core.Compiler.Timings.ROOT() with 8 direct children

Anda dapat merujuk ke dokumen snoopCompile.jl informasi lebih lanjut tentang apa yang baru saja kami lakukan, tetapi sekarang, tolong perhatikan tinf Mengungkapkan 8 anak secara langsung. Itu berarti sintesis terjadi 8 kali saat berlari Original.process("alg1"). Jika fungsi ini benar -benar stabil,@snoop_inference Hanya akan melaporkan satu anak secara langsung, jadi kita tahu ada jenis interaksi di suatu tempat.

Masing -masing dari 8 anak secara langsung, proses aktivasi aktif, yang berarti memanggil metode spesifik selama kompilasi aktivasi inferensi terjadi. Kita dapat mengumpulkan aktivasi inferensi:

julia> itrigs = inference_triggers(tinf) Inference triggered to call process(::String) from eval (./boot.jl:430) inlined into REPL.eval_user_input(::Any, ::REPL.REPLBackend, ::Module) (/cache/build/tester-amdci5-12/julialang/julia-release-1-dot-11/usr/share/julia/stdlib/v1.11/REPL/src/REPL.jl:261) Inference triggered to call process_item(::Int64, ::Int64) from  Inference triggered to call process_item(::Float64, ::Int64) from  Inference triggered to call process_item(::UInt8, ::Int64) from  Inference triggered to call process_item(::Float32, ::Int64) from  Inference triggered to call process_item(::String, ::Int64) from  Inference triggered to call process_item(::Vector{Float64}, ::Int64) from  Inference triggered to call process_item(::Tuple{Int64, Float64}, ::Int64) from 

Proses aktivasi deduksi pertama untuk kompilasi tertinggi process Fungsi ini disebut (ini adalah aktivasi yang selalu kami harapkan untuk dilihat). Tapi kemudian sepertinya Julia harus berhenti jogging process_item.

Proses yang diaktifkan memberi tahu kami bahwa jenis jenis ada ketika memanggil fungsi yang diberikan, tetapi yang benar -benar ingin kami ketahui adalah tempat pengucilan ini berasal. from <calling function>(Perhatikan itu from #1 Dalam contoh di atas process_item Dipanggil dari fungsi anonim.)

Kita bisa menggunakannya accumulate_by_sourceUntuk mendapatkan mode tampilan sintetis, fungsi telah melakukan panggilan melalui Dynamic Depatch:

julia> mtrigs = accumulate_by_source(Method, itrigs)2-element Vector{SnoopCompile.TaggedTriggers{Method}}: eval_user_input(ast, backend::REPL.REPLBackend, mod::Module) @ REPL ~/.julia/juliaup/julia-1.11.5+0.x64.linux.gnu/share/julia/stdlib/v1.11/REPL/src/REPL.jl:247 (1 callees from 1 callers) (::var"#1#2")(d) @ Main REPL[1]:30 (7 callees from 7 callers)

Dari sini, kita dapat melihat bahwa misalnya, Cerberaililly hanya memiliki satu masalah: fungsi anonim var"#1#2".

Sekarang kita memiliki ide awal dari mana semua jenis dapat berasal, kita bisa masuk ke dalam penentuan yang benar dari penyebab yang tepat dengan cthulhu.jl. Kita bisa menggunakannya ascend FUNGSIon A Deduction Activation mulai menyelidiki:

julia> using Cthulhujulia> ascend(itrigs[2]) 

ascend Berikan menu tampilan process_itemdan fungsi anonim. Pilih fungsi anonim dan tekan ENTER. Tangkapan layar output cthulhu:

Output cthulhu

Baca output cthulhu.jltakes untuk sementara waktu untuk membiasakan diri (terutama ketika tidak dapat menampilkan kode sumber, seperti dalam contoh ini), tetapi hal utama yang perlu diingat bahwa merah itu buruk. Lihat cthulhu.jl Readme untuk informasi lebih lanjut.

Dalam contoh ini, asal semua jenis cukup mudah untuk ditentukan Core.Box itu. Ini selalu jelek; Pada dasarnya, mereka adalah containerThat yang dapat menjaga nilai dari jenis apa pun, sehingga jenisnya dapat muncul saat mengakses konten. Dalam kasus khusus ini,Core.getfield(#self#, :val) indikatorval Variabel ditangkap oleh fungsi anonim.

Ketika kami menentukan penyebab perubahan, solusi berubah dalam setiap kasus tertentu. Solusi potensial mungkin termasuk:

Kami akan menggunakan solusi akhir ini dalam contoh kami. Fungsi anonim dalam pertanyaan ditentukan oleh do mencegat _process.So, mari kita perbaiki masalah variabel penangkapan val:

module Correctedfunction _process(::Alg1, data)    val = data[1]    if val < 0        val = -val    end    f = let val = val        d -> process_item(d, val)    end    result = map(f, data)    return resultendend

Sekarang mari kita lihat apa @snoop_inference berbicara:

julia> using SnoopCompileCorejulia> tinf = @snoop_inference Corrected.process("alg1");julia> using SnoopCompilejulia> tinfInferenceTimingNode: 0.113669/0.183888 on Core.Compiler.Timings.ROOT() with 1 direct children

Hanya ada satu anak secara langsung. Tipe, tipe stabil!

Lihat Cara Membandingkan Kinerja:

julia> using BenchmarkToolsjulia> @btime Original.process("alg1");  220.506 ns (16 allocations: 496 bytes)julia> @btime Corrected.process("alg1");  51.104 ns (8 allocations: 288 bytes)

Hebat, kode perbaikan ~ 4 kali lebih cepat!

Dalam posting ini, kami telah belajar tentang stabilitas dan bagaimana jenis mempengaruhi sintesis kinerja dan waktu berjalan. Kami juga menjalani tes yang membuktikan cara menggunakan snoopCompile.jl dan cthulhu.jlto untuk mengidentifikasi sumber berita untuk program ini. SnoopCompile.jl dan cthulhu.jlforum Tambahkan contoh berikutnya untuk memperkuat pemahaman Anda.

Bisakah Anda memiliki interaksi yang menyebabkan kode Julia Anda? Hubungi kami dan kami dapat membantu Anda!

]>>

Contents

Software Terbaru Saat Ini



Aplikasi yang sedang trend saat ini

object oriented programming, programming language, programming adalah, web programming, belajar programming, tournament software, software, software adalah, contoh software, apa itu software, pengertian software, aplikasi, aplikasi penghasil uang, aplikasi bokep, aplikasi video, programming

#Jenis #Stabil #dengan #Snoopompile.jl #dan #Cthulhu.jl #untuk #Julia #Kinerja #Tinggi

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *