আমরা এমন একটি প্রোগ্রাম বিকাশ করছি যা এই বার্তাগুলির অস্থায়ী ইতিহাস রাখার সময় "বার্তাগুলি" গ্রহণ এবং ফরোয়ার্ড করে, যাতে এটি যদি অনুরোধ করা হয় তবে আপনাকে বার্তার ইতিহাস বলতে পারে। বার্তাগুলি সংখ্যাগতভাবে চিহ্নিত করা হয়, সাধারণত প্রায় 1 কিলোবাইট আকারের হয় এবং আমাদের লক্ষ লক্ষ হাজার বার্তা রাখতে হবে।
আমরা এই প্রোগ্রামটি বিলম্বের জন্য অনুকূল করতে চাই: একটি বার্তা প্রেরণ এবং গ্রহণের মধ্যে সময়টি 10 মিলিসেকেন্ডের নীচে হওয়া আবশ্যক।
প্রোগ্রামটি হাস্কেল-এ লেখা এবং জিএইচসির সাথে সংকলিত। তবে আমরা দেখতে পেয়েছি যে আবর্জনা সংগ্রহের বিরতি আমাদের বিলম্বিত প্রয়োজনীয়তার জন্য অনেক দীর্ঘ: আমাদের বাস্তব-বিশ্ব প্রোগ্রামে 100 মিলিসেকেন্ডেরও বেশি।
নিম্নলিখিত প্রোগ্রামটি আমাদের আবেদনের একটি সহজ সংস্করণ ified এটি Data.Map.Strict
বার্তা সংরক্ষণের জন্য একটি ব্যবহার করে। বার্তা ByteString
একটি দ্বারা সনাক্ত করা হয় Int
। সংখ্যা ক্রমবর্ধমান মধ্যে 1,000,000 বার্তা সন্নিবেশ করা হয়, এবং সর্বোচ্চ 200,000 বার্তায় ইতিহাস রাখার জন্য পুরানো বার্তাগুলি ক্রমাগত সরানো হয়।
module Main (main) where
import qualified Control.Exception as Exception
import qualified Control.Monad as Monad
import qualified Data.ByteString as ByteString
import qualified Data.Map.Strict as Map
data Msg = Msg !Int !ByteString.ByteString
type Chan = Map.Map Int ByteString.ByteString
message :: Int -> Msg
message n = Msg n (ByteString.replicate 1024 (fromIntegral n))
pushMsg :: Chan -> Msg -> IO Chan
pushMsg chan (Msg msgId msgContent) =
Exception.evaluate $
let
inserted = Map.insert msgId msgContent chan
in
if 200000 < Map.size inserted
then Map.deleteMin inserted
else inserted
main :: IO ()
main = Monad.foldM_ pushMsg Map.empty (map message [1..1000000])
আমরা এই প্রোগ্রামটি ব্যবহার করে সংকলন ও পরিচালনা করেছি:
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.10.3
$ ghc -O2 -optc-O3 Main.hs
$ ./Main +RTS -s
3,116,460,096 bytes allocated in the heap
385,101,600 bytes copied during GC
235,234,800 bytes maximum residency (14 sample(s))
124,137,808 bytes maximum slop
600 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 6558 colls, 0 par 0.238s 0.280s 0.0000s 0.0012s
Gen 1 14 colls, 0 par 0.179s 0.250s 0.0179s 0.0515s
INIT time 0.000s ( 0.000s elapsed)
MUT time 0.652s ( 0.745s elapsed)
GC time 0.417s ( 0.530s elapsed)
EXIT time 0.010s ( 0.052s elapsed)
Total time 1.079s ( 1.326s elapsed)
%GC time 38.6% (40.0% elapsed)
Alloc rate 4,780,213,353 bytes per MUT second
Productivity 61.4% of total user, 49.9% of total elapsed
এখানে গুরুত্বপূর্ণ মেট্রিকটি 0.0515s বা 51 মিলিসেকেন্ডের "সর্বাধিক বিরতি"। আমরা কমপক্ষে একটি প্রস্থের অর্ডার দ্বারা এটি হ্রাস করতে চাই।
পরীক্ষায় দেখা যায় যে একটি জিসি বিরতির দৈর্ঘ্য ইতিহাসের বার্তাগুলির সংখ্যা দ্বারা নির্ধারিত হয়। সম্পর্কটি মোটামুটি লিনিয়ার, বা সম্ভবত সুপার-লিনিয়ার। নিম্নলিখিত সম্পর্কটি এই সম্পর্কটি দেখায়। ( আপনি আমাদের বেঞ্চমার্কিং পরীক্ষাগুলি এখানে এবং কিছু চার্ট দেখতে পারেন ))
msgs history length max GC pause (ms)
=================== =================
12500 3
25000 6
50000 13
100000 30
200000 56
400000 104
800000 199
1600000 487
3200000 1957
6400000 5378
তারা এই বিলম্বকে কমিয়ে দিতে পারে কিনা সেগুলির জন্য আমরা আরও বেশ কয়েকটি ভেরিয়েবলের সাথে পরীক্ষা-নিরীক্ষা করেছি, যার কোনওটিতেই খুব বড় পার্থক্য নেই। এই গুরুত্বহীন পরিবর্তনশীলগুলির মধ্যে রয়েছে: অপ্টিমাইজেশন ( -O
, -O2
); আরটিএস জিসি অপশন ( -G
, -H
, -A
, -c
), কোর (সংখ্যা -N
), বিভিন্ন ডাটা স্ট্রাকচার ( Data.Sequence
), বার্তা মাপ, এবং উত্পন্ন স্বল্পস্থায়ী আবর্জনা পরিমাণ। অপ্রতিরোধ্য নির্ধারণকারী ফ্যাক্টর হ'ল ইতিহাসের বার্তাগুলির সংখ্যা।
আমাদের কাজের তত্ত্বটি হ'ল বিরতি দেওয়া বার্তাগুলির সংখ্যার ক্ষেত্রে লিনিয়ার কারণ প্রতিটি জিসি চক্রটি সমস্ত কার্যক্ষম অ্যাক্সেসযোগ্য মেমরির উপর দিয়ে যেতে হয় এবং এটি অনুলিপি করতে হয়, যা স্পষ্টতই রৈখিক ক্রিয়াকলাপ are
প্রশ্নাবলী:
- এই লিনিয়ার-সময় তত্ত্বটি কি সঠিক? জিসি বিরতির দৈর্ঘ্য কি এই সহজ উপায়ে প্রকাশ করা যেতে পারে, বা বাস্তবতা আরও জটিল?
- জিসি বিরতি যদি ওয়ার্কিং মেমোরিতে লিনিয়ার হয়, তবে জড়িত ধ্রুবক উপাদানগুলি হ্রাস করার কোনও উপায় আছে কি?
- ইনক্রিমেন্টাল জিসির জন্য কোনও বিকল্প আছে, বা এর মতো কিছু? আমরা কেবল গবেষণামূলক কাগজপত্র দেখতে পারি। আমরা কম বিলম্বের জন্য থ্রুপুট বাণিজ্য করতে খুব আগ্রহী।
- একাধিক প্রক্রিয়াতে বিভক্ত হওয়া ছাড়াও ছোট, জিসি চক্রগুলির জন্য "পার্টিশন" মেমরির কোনও উপায় আছে কি?
COntrol.Concurrent.Chan
উদাহরণস্বরূপ ব্যবহার করছেন না ? পরিবর্তনীয় অবজেক্টগুলি সমীকরণ পরিবর্তন করে)? আপনি কোন আবর্জনা তৈরি করছেন তা নিশ্চিত করে এবং যতটা সম্ভব কম পরিমাণে তৈরি করে তা নিশ্চিত করে শুরু করার পরামর্শ দেব (উদাহরণস্বরূপ, ফিউশনটি ঘটেছে তা নিশ্চিত করুন, চেষ্টা করুন -funbox-strict
)। সম্ভবত একটি স্ট্রিমিং লিব (আইওস্ট্রিমস, পাইপস, কন্ডুইট, স্ট্রিমিং) এবং performGC
আরও ঘন ঘন বিরতিতে সরাসরি কল করার চেষ্টা করুন calling
MutableByteArray