গতি এবং অপ্টিমাইজেশন অধ্যয়ন করার সময়, বন্যভাবে ভুল ফলাফল পাওয়া খুব সহজ । বিশেষত, আপনি সত্যিই বলতে পারবেন না যে আপনার বেঞ্চমার্কিং সেটআপটির সংকলক সংস্করণ এবং অপ্টিমাইজেশন মোডের উল্লেখ না করেই একটি বৈকল্পিক অন্যটির চেয়ে দ্রুত। তারপরেও আধুনিক প্রসেসরগুলি এতটাই পরিশীলিত যে নিউরাল নেটওয়ার্ক ভিত্তিক শাখার ভবিষ্যদ্বাণীকারীদের বৈশিষ্ট্যযুক্ত, সমস্ত ধরণের ক্যাশে উল্লেখ না করে, তাই, সতর্কতার সাথে সেট আপ করা সত্ত্বেও, বেঞ্চমার্কিং ফলাফল ঝাপসা হয়ে যাবে।
বলা হচ্ছে যে...
বেঞ্চমার্কিং আমাদের বন্ধু।
criterionএকটি প্যাকেজ যা উন্নত বেঞ্চমার্কিং সরঞ্জাম সরবরাহ করে। আমি দ্রুত এটির মতো একটি মাপদণ্ড তৈরি করেছি:
module Main where
import Criterion
import Criterion.Main
-- slow
myButLast :: [a] -> a
myButLast [x, y] = x
myButLast (x : xs) = myButLast xs
myButLast _ = error "List too short"
-- decent
myButLast' :: [a] -> a
myButLast' = (!! 1) . reverse
-- fast
myButLast'' :: [a] -> a
myButLast'' = last . init
butLast2 :: [a] -> a
butLast2 (x : _ : [ ] ) = x
butLast2 (_ : xs@(_ : _ ) ) = butLast2 xs
butLast2 _ = error "List too short"
setupEnv = do
let xs = [1 .. 10^7] :: [Int]
return xs
benches xs =
[ bench "slow?" $ nf myButLast xs
, bench "decent?" $ nf myButLast' xs
, bench "fast?" $ nf myButLast'' xs
, bench "match2" $ nf butLast2 xs
]
main = defaultMain
[ env setupEnv $ \ xs -> bgroup "main" $ let bs = benches xs in bs ++ reverse bs ]
আপনি দেখতে হিসাবে, আমি রূপটি যুক্ত করেছি যা স্পষ্টতই দুটি উপাদানের সাথে একবারে মেলে, তবে অন্যথায় এটি একই কোড ভার্ভ্যাটিম। আমি বিপরীতেও মাপদণ্ড চালাই, যাতে ক্যাশে হওয়ার কারণে পক্ষপাত সম্পর্কে সচেতন হতে পারি। সুতরাং, চলুন এবং দেখুন!
% ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.6.5
% ghc -O2 -package criterion A.hs && ./A
benchmarking main/slow?
time 54.83 ms (54.75 ms .. 54.90 ms)
1.000 R² (1.000 R² .. 1.000 R²)
mean 54.86 ms (54.82 ms .. 54.93 ms)
std dev 94.77 μs (54.95 μs .. 146.6 μs)
benchmarking main/decent?
time 794.3 ms (32.56 ms .. 1.293 s)
0.907 R² (0.689 R² .. 1.000 R²)
mean 617.2 ms (422.7 ms .. 744.8 ms)
std dev 201.3 ms (105.5 ms .. 283.3 ms)
variance introduced by outliers: 73% (severely inflated)
benchmarking main/fast?
time 84.60 ms (84.37 ms .. 84.95 ms)
1.000 R² (1.000 R² .. 1.000 R²)
mean 84.46 ms (84.25 ms .. 84.77 ms)
std dev 435.1 μs (239.0 μs .. 681.4 μs)
benchmarking main/match2
time 54.87 ms (54.81 ms .. 54.95 ms)
1.000 R² (1.000 R² .. 1.000 R²)
mean 54.85 ms (54.81 ms .. 54.92 ms)
std dev 104.9 μs (57.03 μs .. 178.7 μs)
benchmarking main/match2
time 50.60 ms (47.17 ms .. 53.01 ms)
0.993 R² (0.981 R² .. 0.999 R²)
mean 60.74 ms (56.57 ms .. 67.03 ms)
std dev 9.362 ms (6.074 ms .. 10.95 ms)
variance introduced by outliers: 56% (severely inflated)
benchmarking main/fast?
time 69.38 ms (56.64 ms .. 78.73 ms)
0.948 R² (0.835 R² .. 0.994 R²)
mean 108.2 ms (92.40 ms .. 129.5 ms)
std dev 30.75 ms (19.08 ms .. 37.64 ms)
variance introduced by outliers: 76% (severely inflated)
benchmarking main/decent?
time 770.8 ms (345.9 ms .. 1.004 s)
0.967 R² (0.894 R² .. 1.000 R²)
mean 593.4 ms (422.8 ms .. 691.4 ms)
std dev 167.0 ms (50.32 ms .. 226.1 ms)
variance introduced by outliers: 72% (severely inflated)
benchmarking main/slow?
time 54.87 ms (54.77 ms .. 55.00 ms)
1.000 R² (1.000 R² .. 1.000 R²)
mean 54.95 ms (54.88 ms .. 55.10 ms)
std dev 185.3 μs (54.54 μs .. 251.8 μs)
দেখে মনে হচ্ছে আমাদের "ধীর" সংস্করণটি মোটেও ধীর নয়! এবং প্যাটার্ন মিলের জটিলতা কিছু যোগ করে না। (আমি সামান্য গতি বাড়িয়ে দেখি যে match2আমি টানা দুটি রান চালানোর মধ্য দিয়ে আমি ক্যাশিংয়ের প্রভাবকে সম্মত করি ))
আরও "বৈজ্ঞানিক" ডেটা পাওয়ার একটি উপায় রয়েছে : আমরা -ddump-simplসংকলকটি আমাদের কোডটি কীভাবে দেখে and
মধ্যবর্তী কাঠামো পরিদর্শন আমাদের বন্ধু।
"কোর" জিএইচসির অভ্যন্তরীণ ভাষা। রান টাইম সিস্টেমটি কার্যকর করার জন্য প্রতিটি হাস্কেল উত্স ফাইলটি চূড়ান্ত কার্যকরী গ্রাফে রূপান্তরিত হওয়ার আগে কোরে সরল করা হয়। আমরা যদি এই মধ্যবর্তী পর্যায়ের দিকে লক্ষ্য করি তবে এটি আমাদেরকে বলবে myButLastএবং butLast2এটি সমতুল্য। এটি দেখার দরকার নেই, যেহেতু, নামকরণের পর্যায়ে, আমাদের সমস্ত সুন্দর শনাক্তকারী এলোমেলোভাবে ম্যাঙ্গেলড।
% for i in `seq 1 4`; do echo; cat A$i.hs; ghc -O2 -ddump-simpl A$i.hs > A$i.simpl; done
module A1 where
-- slow
myButLast :: [a] -> a
myButLast [x, y] = x
myButLast (x : xs) = myButLast xs
myButLast _ = error "List too short"
module A2 where
-- decent
myButLast' :: [a] -> a
myButLast' = (!! 1) . reverse
module A3 where
-- fast
myButLast'' :: [a] -> a
myButLast'' = last . init
module A4 where
butLast2 :: [a] -> a
butLast2 (x : _ : [ ] ) = x
butLast2 (_ : xs@(_ : _ ) ) = butLast2 xs
butLast2 _ = error "List too short"
% ./EditDistance.hs *.simpl
(("A1.simpl","A2.simpl"),3866)
(("A1.simpl","A3.simpl"),3794)
(("A2.simpl","A3.simpl"),663)
(("A1.simpl","A4.simpl"),607)
(("A2.simpl","A4.simpl"),4188)
(("A3.simpl","A4.simpl"),4113)
মনে হচ্ছে যে A1ও A4সবচেয়ে অনুরূপ। পুরো পরিদর্শনটি দেখায় যে প্রকৃতপক্ষে কোডের কাঠামোটি অভিন্ন A1এবং A4একই রকম। যে A2এবং A3একইভাবে যেহেতু দুই ফাংশন একটি রচনা হিসাবে সংজ্ঞায়িত করা হয় এছাড়াও যুক্তিসঙ্গত।
আপনি যদি coreআউটপুটটি ব্যাপকভাবে পরীক্ষা করতে যাচ্ছেন তবে এটি এবং এর মতো পতাকা সরবরাহ করাও বোধগম্য । তারা এটি পড়া এত সহজ করে তোলে।-dsuppress-module-prefixes-dsuppress-uniques
আমাদের শত্রুদের একটি সংক্ষিপ্ত তালিকাও।
সুতরাং, বেঞ্চমার্কিং এবং অপ্টিমাইজেশনের সাথে কী ভুল হতে পারে?
ghciইন্টারেক্টিভ প্লে এবং দ্রুত পুনরাবৃত্তির জন্য ডিজাইন করা হচ্ছে, হাস্কেল উত্সকে চূড়ান্ত সম্পাদনযোগ্য না হয়ে বাইট কোডের একটি নির্দিষ্ট স্বাদে সংকলন করে এবং দ্রুত পুনরায় লোডের পক্ষে ব্যয়বহুল অপ্টিমাইজেশনকে সরিয়ে দেয়।
- প্রোফাইলিং পৃথক বিট এবং কোনও জটিল প্রোগ্রামের টুকরোগুলির পারফরম্যান্স সন্ধানের জন্য দুর্দান্ত সরঞ্জামের মতো বলে মনে হচ্ছে তবে এটি কম্পাইলার অপটিমাইজেশনকে খুব খারাপভাবে নষ্ট করতে পারে, ফলাফলগুলি বেজ অফ অফ বেইজিংয়ের আদেশ হবে।
- আপনার সেফগার্ডটি হ'ল প্রতিটি ক্ষুদ্র বিটের কোডকে তার নিজস্ব বেঞ্চমার্ক রানার সহ একটি পৃথক এক্সিকিউটেবল হিসাবে প্রোফাইল করা।
- আবর্জনা সংগ্রহ করা সার্থক able ঠিক আজই একটি নতুন বড় বৈশিষ্ট্য প্রকাশিত হয়েছে। আবর্জনা সংগ্রহের বিলম্ব এমন উপায়ে পারফরম্যান্সকে প্রভাব ফেলবে যা পূর্বাভাস দেওয়া সহজ নয় ward
- যেমনটি আমি উল্লেখ করেছি, বিভিন্ন সংকলক সংস্করণগুলি বিভিন্ন পারফরম্যান্সের সাথে বিভিন্ন কোড তৈরি করবে, সুতরাং আপনার কোড ব্যবহারকারীর সম্ভবত এটি তৈরি করতে কোন সংস্করণ ব্যবহার করা হবে এবং আপনার কোনও প্রতিশ্রুতি দেওয়ার আগে সেই সাথে মানদণ্ডে চিহ্নিত করতে হবে।
এটি দু: খজনক লাগতে পারে। তবে এটি হ্যাশেল প্রোগ্রামারকে বেশিরভাগ সময় উদ্বেগ করা উচিত নয়। আসল কাহিনী: আমার এক বন্ধু আছে যা সম্প্রতি হাস্কেল শিখতে শুরু করেছিল। তারা সংখ্যার একীকরণের জন্য একটি প্রোগ্রাম লিখেছিলেন, এবং এটি কচ্ছপ ধীর ছিল। সুতরাং আমরা একসাথে বসে ডায়াগ্রাম এবং স্টাফ সহ অ্যালগরিদমের একটি শ্রেণিবদ্ধ বিবরণ লিখেছিলাম । যখন তারা বিমূর্ত বর্ণনার সাথে সারিবদ্ধ হওয়ার জন্য কোডটি পুনরায় লিখেছিলেন, তখন এটি যাদুকরভাবে হয়ে উঠল, চিতা দ্রুত এবং স্মৃতিতেও স্লিম। আমরা গণনা করেছি no কোন সময় নেই। গল্পের শিক্ষা? নিখুঁত বিমূর্ত কাঠামো, এবং আপনার কোড নিজেই অপ্টিমাইজ করবে।
initতালিকাটিকে একাধিকবার "প্যাক করা" এড়াতে অনুকূলিত করা হয়েছে।