স্কাইফ্রেম

Bazel এর সমান্তরাল মূল্যায়ন এবং বৃদ্ধির মডেল।

তথ্য মডেল

ডেটা মডেল নিম্নলিখিত আইটেম নিয়ে গঠিত:

  • SkyValue । নোডও বলা হয়। SkyValues ​​হল অপরিবর্তনীয় বস্তু যাতে বিল্ডের সময় এবং বিল্ডের ইনপুটগুলির উপর নির্মিত সমস্ত ডেটা থাকে। উদাহরণ হল: ইনপুট ফাইল, আউটপুট ফাইল, লক্ষ্য এবং কনফিগার করা লক্ষ্য।
  • SkyKey । একটি SkyValue উল্লেখ করার জন্য একটি সংক্ষিপ্ত অপরিবর্তনীয় নাম, উদাহরণস্বরূপ, FILECONTENTS FILECONTENTS:/tmp/foo বা PACKAGE://foo
  • SkyFunction । তাদের কী এবং নির্ভরশীল নোডের উপর ভিত্তি করে নোড তৈরি করে।
  • নোড গ্রাফ। নোডের মধ্যে নির্ভরতা সম্পর্ক ধারণকারী একটি ডেটা কাঠামো।
  • Skyframe । ক্রমবর্ধমান মূল্যায়ন কাঠামোর জন্য কোড নাম Bazel এর উপর ভিত্তি করে।

মূল্যায়ন

একটি বিল্ড নোডের মূল্যায়ন করে যা বিল্ড রিকোয়েস্টের প্রতিনিধিত্ব করে (এটি হল সেই অবস্থা যার জন্য আমরা চেষ্টা করছি, তবে অনেকগুলি লিগ্যাসি কোড রয়েছে)। প্রথমে এর SkyFunction খুঁজে পাওয়া যায় এবং শীর্ষ-স্তরের SkyKey এর কী দিয়ে কল করা হয়। তারপর ফাংশনটি নোডগুলির মূল্যায়নের জন্য অনুরোধ করে যা এটি শীর্ষ-স্তরের নোডের মূল্যায়নের জন্য প্রয়োজন, যার ফলস্বরূপ অন্যান্য ফাংশন আহ্বান করা হয়, এবং তাই, যতক্ষণ না লিফ নোডগুলি পৌঁছায় (যা সাধারণত নোডগুলি ফাইল সিস্টেমে ইনপুট ফাইলের প্রতিনিধিত্ব করে। ) অবশেষে, আমরা শীর্ষ-স্তরের SkyValue এর মান, কিছু পার্শ্ব প্রতিক্রিয়া (যেমন ফাইল সিস্টেমে আউটপুট ফাইল) এবং বিল্ডের সাথে জড়িত নোডগুলির মধ্যে নির্ভরতার একটি নির্দেশিত অ্যাসাইক্লিক গ্রাফের সাথে শেষ করি।

একটি SkyFunction একাধিক পাসে SkyKeys কে অনুরোধ করতে পারে যদি এটি তার কাজ করার জন্য প্রয়োজনীয় সমস্ত নোড আগে থেকে বলতে না পারে। একটি সাধারণ উদাহরণ হল একটি ইনপুট ফাইল নোডের মূল্যায়ন করা যা একটি সিমলিংক হিসাবে পরিণত হয়: ফাংশনটি ফাইলটি পড়ার চেষ্টা করে, বুঝতে পারে যে এটি একটি সিমলিংক, এবং এইভাবে সিমলিংকের লক্ষ্যকে প্রতিনিধিত্বকারী ফাইল সিস্টেম নোডটি নিয়ে আসে। কিন্তু এটি নিজেই একটি সিমলিঙ্ক হতে পারে, এই ক্ষেত্রে মূল ফাংশনটিকেও তার লক্ষ্য আনতে হবে।

ফাংশনগুলি SkyFunction ইন্টারফেস দ্বারা এবং SkyFunction.Environment নামক একটি ইন্টারফেস দ্বারা প্রদত্ত পরিষেবাগুলির দ্বারা উপস্থাপিত হয়। এই জিনিসগুলি ফাংশন করতে পারে:

  • env.getValue কল করার মাধ্যমে অন্য নোডের মূল্যায়নের জন্য অনুরোধ করুন। নোড উপলব্ধ থাকলে, এর মান ফেরত দেওয়া হয়, অন্যথায়, null ফেরত দেওয়া হয় এবং ফাংশনটি নিজেই null ফেরত দেবে বলে আশা করা হচ্ছে। পরবর্তী ক্ষেত্রে, নির্ভরশীল নোডটি মূল্যায়ন করা হয়, এবং তারপরে মূল নোড নির্মাতাকে আবার আহ্বান করা হয়, কিন্তু এবার একই env.getValue কলটি একটি নন- null মান প্রদান করবে।
  • env.getValues() কল করে একাধিক অন্যান্য নোডের মূল্যায়নের জন্য অনুরোধ করুন। এটি মূলত একই কাজ করে, ব্যতীত যে নির্ভরশীল নোডগুলি সমান্তরালভাবে মূল্যায়ন করা হয়।
  • তাদের আহ্বানের সময় গণনা করুন
  • পার্শ্ব প্রতিক্রিয়া আছে, উদাহরণস্বরূপ, ফাইল সিস্টেমে ফাইল লেখা। দুটি ভিন্ন ফাংশন যাতে একে অপরের পায়ের আঙ্গুলের উপর না পড়ে সেদিকে খেয়াল রাখতে হবে। সাধারণভাবে, পার্শ্বপ্রতিক্রিয়া লিখুন (যেখানে ডেটা Bazel থেকে বাইরের দিকে প্রবাহিত হয়) ঠিক আছে, পার্শ্ব প্রতিক্রিয়া পড়ুন (যেখানে নিবন্ধিত নির্ভরতা ছাড়াই Bazel-এ ডেটা প্রবাহিত হয়) তা নয়, কারণ এগুলি একটি অনিবন্ধিত নির্ভরতা এবং এর ফলে ভুল ক্রমবর্ধমান বিল্ড হতে পারে। .

SkyFunction বাস্তবায়ন নির্ভরতা (যেমন সরাসরি ফাইল সিস্টেম পড়ার মাধ্যমে) অনুরোধ করা ছাড়া অন্য কোনো উপায়ে ডেটা অ্যাক্সেস করা উচিত নয়, কারণ এর ফলে Bazel পড়া ফাইলের উপর ডেটা নির্ভরতা নিবন্ধন করে না, ফলে ভুল ক্রমবর্ধমান বিল্ড হয়।

একবার একটি ফাংশনের কাজ করার জন্য পর্যাপ্ত ডেটা পাওয়া গেলে, এটি সম্পূর্ণতা নির্দেশ করে একটি নন- null মান ফেরত দেবে।

এই মূল্যায়ন কৌশলটির বেশ কয়েকটি সুবিধা রয়েছে:

  • হারমেটিসিটি। যদি ফাংশনগুলি শুধুমাত্র অন্যান্য নোডের উপর নির্ভর করে ইনপুট ডেটার জন্য অনুরোধ করে, Bazel গ্যারান্টি দিতে পারে যে ইনপুট অবস্থা একই হলে, একই ডেটা ফেরত দেওয়া হবে। যদি সমস্ত আকাশ ফাংশন নির্ধারক হয়, তাহলে এর অর্থ হল পুরো বিল্ডটিও নির্ধারক হবে।
  • সঠিক এবং নিখুঁত বৃদ্ধিশীলতা. যদি সমস্ত ফাংশনের সমস্ত ইনপুট ডেটা রেকর্ড করা হয়, তবে Bazel শুধুমাত্র নোডগুলির সঠিক সেটগুলিকে বাতিল করতে পারে যেগুলি ইনপুট ডেটা পরিবর্তিত হলে অবৈধ করা দরকার৷
  • সমান্তরালতা। যেহেতু ফাংশনগুলি কেবলমাত্র নির্ভরতাগুলির অনুরোধের মাধ্যমে একে অপরের সাথে যোগাযোগ করতে পারে, তাই যে ফাংশনগুলি একে অপরের উপর নির্ভর করে না সেগুলি সমান্তরালভাবে চালানো যেতে পারে এবং বেজেল গ্যারান্টি দিতে পারে যে ফলাফলটি একই হবে যদি সেগুলি ধারাবাহিকভাবে চালানো হয়।

বৃদ্ধিশীলতা

যেহেতু ফাংশনগুলি শুধুমাত্র অন্যান্য নোডের উপর নির্ভর করে ইনপুট ডেটা অ্যাক্সেস করতে পারে, তাই ব্যাজেল ইনপুট ফাইল থেকে আউটপুট ফাইলগুলিতে একটি সম্পূর্ণ ডেটা ফ্লো গ্রাফ তৈরি করতে পারে এবং এই তথ্যটি শুধুমাত্র সেই নোডগুলিকে পুনর্নির্মাণ করতে ব্যবহার করতে পারে যেগুলি আসলে পুনর্নির্মাণ করা দরকার: বিপরীত ট্রানজিটিভ পরিবর্তিত ইনপুট ফাইলের সেট বন্ধ।

বিশেষ করে, দুটি সম্ভাব্য ক্রমবর্ধমান কৌশল বিদ্যমান: নীচে-উপরের একটি এবং শীর্ষ-নিচে একটি। কোনটি সর্বোত্তম তা নির্ভর করে নির্ভরতা গ্রাফটি কেমন দেখাচ্ছে তার উপর।

  • বটম-আপ অবৈধকরণের সময়, একটি গ্রাফ তৈরি হওয়ার পরে এবং পরিবর্তিত ইনপুটগুলির সেট জানার পরে, সমস্ত নোডগুলি অবৈধ হয়ে যায় যা পরিবর্তিত ফাইলগুলির উপর নির্ভর করে। এটি সর্বোত্তম যদি আমরা জানি যে একই শীর্ষ-স্তরের নোড আবার তৈরি করা হবে। নোট করুন যে বটম-আপ ইনভালিডেশনের জন্য পূর্ববর্তী বিল্ডের সমস্ত ইনপুট ফাইলে stat() চালানো প্রয়োজন যেগুলি পরিবর্তন করা হয়েছে কিনা তা নির্ধারণ করতে। পরিবর্তিত ফাইল সম্পর্কে জানতে inotify বা অনুরূপ পদ্ধতি ব্যবহার করে এটি উন্নত করা যেতে পারে।

  • টপ-ডাউন ইনভেলিডেশনের সময়, টপ-লেভেল নোডের ট্রানজিটিভ ক্লোজার চেক করা হয় এবং শুধুমাত্র সেই নোডগুলো রাখা হয় যাদের ট্রানজিটিভ ক্লোজার পরিষ্কার। এটি আরও ভাল যদি আমরা জানি যে বর্তমান নোড গ্রাফটি বড়, তবে পরবর্তী বিল্ডে আমাদের শুধুমাত্র এটির একটি ছোট উপসেট প্রয়োজন: নীচে-আপ অবৈধকরণ প্রথম বিল্ডের বড় গ্রাফটিকে বাতিল করবে, টপ-ডাউন অবৈধকরণের বিপরীতে, যা শুধু দ্বিতীয় বিল্ডের ছোট গ্রাফে চলে।

আমরা বর্তমানে শুধুমাত্র বটম-আপ অবৈধকরণ করি।

আরও বৃদ্ধি পাওয়ার জন্য, আমরা পরিবর্তন ছাঁটাই ব্যবহার করি: যদি একটি নোড অবৈধ হয়ে যায়, কিন্তু পুনর্নির্মাণের পরে, এটি আবিষ্কৃত হয় যে এটির নতুন মান এটির পুরানো মানের সমান, এই নোডের পরিবর্তনের কারণে যে নোডগুলি বাতিল করা হয়েছিল সেগুলি "পুনরুত্থিত হয়" ”

এটি দরকারী, উদাহরণস্বরূপ, যদি কেউ একটি C++ ফাইলে একটি মন্তব্য পরিবর্তন করে: তাহলে এটি থেকে উত্পন্ন .o ফাইলটি একই হবে, এইভাবে, আমাদের আবার লিঙ্কারকে কল করার দরকার নেই।

ইনক্রিমেন্টাল লিঙ্কিং/সংকলন

এই মডেলের প্রধান সীমাবদ্ধতা হল যে একটি নোডের অবৈধকরণ একটি সম্পূর্ণ বা কিছুই নয়: যখন একটি নির্ভরতা পরিবর্তিত হয়, তখন নির্ভরশীল নোডটি সর্বদা স্ক্র্যাচ থেকে পুনর্নির্মাণ করা হয়, এমনকি যদি একটি ভাল অ্যালগরিদম বিদ্যমান থাকে যা এর পুরানো মানকে পরিবর্তন করবে পরিবর্তনের উপর ভিত্তি করে নোড। কয়েকটি উদাহরণ যেখানে এটি দরকারী হবে:

  • ইনক্রিমেন্টাল লিঙ্কিং
  • যখন একটি একক .class ফাইল একটি .jar .jar আবার স্ক্র্যাচ থেকে তৈরি না করে পরিবর্তন করতে পারি।

কেন Bazel বর্তমানে নীতিগতভাবে এই জিনিসগুলিকে সমর্থন করে না (আমাদের কাছে ক্রমবর্ধমান লিঙ্কিংয়ের জন্য কিছু পরিমাপ সমর্থন রয়েছে, তবে এটি স্কাইফ্রেমের মধ্যে প্রয়োগ করা হয়নি) দ্বিগুণ: আমাদের শুধুমাত্র সীমিত কর্মক্ষমতা লাভ ছিল এবং ফলাফলের গ্যারান্টি দেওয়া কঠিন ছিল পরিব্যক্তির পরিচ্ছন্ন পুনর্নির্মাণের মতই একই, এবং Google মানগুলি বিট-ফর-বিট পুনরাবৃত্তিযোগ্য।

এখন অবধি, আমরা সর্বদা একটি ব্যয়বহুল বিল্ড স্টেপকে বিচ্ছিন্ন করে এবং সেইভাবে আংশিক পুনঃমূল্যায়ন অর্জনের মাধ্যমে সর্বদা যথেষ্ট ভাল পারফরম্যান্স অর্জন করতে পারি: এটি একটি অ্যাপের সমস্ত ক্লাসকে একাধিক গ্রুপে বিভক্ত করে এবং আলাদাভাবে সেগুলির উপর ডেক্সিং করে৷ এইভাবে, যদি একটি গ্রুপে ক্লাস পরিবর্তন না হয়, তাহলে ডেক্সিং আবার করতে হবে না।

Bazel ধারণা ম্যাপিং

এটি কিছু SkyFunction বাস্তবায়নের একটি মোটামুটি ওভারভিউ যা Bazel একটি বিল্ড সম্পাদন করতে ব্যবহার করে:

  • FileStateValue একটি lstat() এর ফলাফল। বিদ্যমান ফাইলগুলির জন্য, আমরা ফাইলের পরিবর্তনগুলি সনাক্ত করার জন্য অতিরিক্ত তথ্যও গণনা করি। এটি Skyframe গ্রাফের সর্বনিম্ন স্তরের নোড এবং এর কোন নির্ভরতা নেই।
  • ফাইল ভ্যালু । ফাইলের প্রকৃত বিষয়বস্তু এবং/অথবা সমাধান করা পথের বিষয়ে যত্নশীল এমন কিছু দ্বারা ব্যবহৃত হয়। সংশ্লিষ্ট FileStateValue এবং যেকোন সিমলিংকের উপর নির্ভর করে যা সমাধান করা প্রয়োজন (যেমন a/b এর FileValue এর জন্য a-এর সমাধান করা পথ এবং a a/b এর সমাধান করা পথ প্রয়োজন)। FileStateValue এর মধ্যে পার্থক্য গুরুত্বপূর্ণ কারণ কিছু ক্ষেত্রে (উদাহরণস্বরূপ, ফাইল সিস্টেম গ্লোব মূল্যায়ন করা (যেমন srcs=glob(["*/*.java"]) ) ফাইলের বিষয়বস্তু আসলে প্রয়োজন হয় না।
  • ডিরেক্টরিলিস্টিং ভ্যালু । মূলত readdir() এর ফলাফল। ডিরেক্টরির সাথে সংশ্লিষ্ট FileValue উপর নির্ভর করে।
  • প্যাকেজ ভ্যালু । একটি BUILD ফাইলের পার্সকৃত সংস্করণ উপস্থাপন করে। সংশ্লিষ্ট BUILD ফাইলের FileValue এর উপর নির্ভর করে, এবং প্যাকেজে গ্লোবগুলিকে সমাধান করতে ব্যবহৃত যেকোন DirectoryListingValue এর উপরও ট্রানজিটিভভাবে নির্ভর করে (অভ্যন্তরীণভাবে একটি BUILD ফাইলের বিষয়বস্তু প্রতিনিধিত্ব করে এমন ডেটা কাঠামো)
  • কনফিগার করা টার্গেট ভ্যালু । একটি কনফিগার করা লক্ষ্যের প্রতিনিধিত্ব করে, যা একটি লক্ষ্য বিশ্লেষণের সময় উত্পন্ন ক্রিয়াগুলির সেটের একটি টিপল এবং এটির উপর নির্ভর করে কনফিগার করা লক্ষ্যগুলিতে প্রদত্ত তথ্য। PackageValue উপর নির্ভর করে সংশ্লিষ্ট টার্গেট, সরাসরি নির্ভরতার ConfiguredTargetValues করা টার্গেট ভ্যালু এবং বিল্ড কনফিগারেশনের প্রতিনিধিত্বকারী একটি বিশেষ নোড।
  • আর্টিফ্যাক্ট ভ্যালু । বিল্ডে একটি ফাইলের প্রতিনিধিত্ব করে, এটি একটি উত্স বা একটি আউটপুট আর্টিফ্যাক্ট (আর্টিফ্যাক্টগুলি প্রায় ফাইলের সমতুল্য, এবং বিল্ড ধাপগুলির প্রকৃত সম্পাদনের সময় ফাইলগুলিকে উল্লেখ করতে ব্যবহৃত হয়)। সোর্স ফাইলের জন্য, এটি সংশ্লিষ্ট নোডের ফাইল ভ্যালুর উপর নির্ভর করে, আউটপুট আর্টিফ্যাক্টের জন্য, এটি আর্টিফ্যাক্ট তৈরি করা যাই হোক না কেন ActionExecutionValue FileValue উপর নির্ভর করে।
  • অ্যাকশন এক্সিকিউশন ভ্যালু । একটি ক্রিয়া সম্পাদনের প্রতিনিধিত্ব করে। এর ইনপুট ফাইলের ArtifactValues ​​এর উপর নির্ভর করে। এটি যে ক্রিয়াটি সম্পাদন করে তা বর্তমানে এর স্কাই কী-এর মধ্যে রয়েছে, যা আকাশ কীগুলি ছোট হওয়া উচিত এই ধারণার বিপরীত। আমরা এই অসঙ্গতি সমাধানে কাজ করছি (মনে রাখবেন যে ActionExecutionValue এবং ArtifactValue অব্যবহৃত হয় যদি আমরা Skyframe-এ এক্সিকিউশন ফেজ না চালাই)।