বহনযোগ্য মাল্টিকোর / NUMA মেমরি বরাদ্দ / সূচনা সেরা অনুশীলন


17

যখন মেমরি ব্যান্ডউইথ সীমাবদ্ধ গণনা ভাগ করা মেমরি পরিবেশে সঞ্চালিত হয় (উদাঃ ওপেনএমপি, প্রথ্রেডস বা টিবিবি দিয়ে থ্রেডেড), তখন কীভাবে মেমরিটি সঠিকভাবে শারীরিক মেমরির মধ্যে বিতরণ করা যায় তা নিশ্চিত করার দ্বিধা রয়েছে যেমন প্রতিটি থ্রেড বেশিরভাগই একটিতে মেমরি অ্যাক্সেস করে "লোকাল" মেমরি বাস যদিও ইন্টারফেসগুলি পোর্টেবল নয়, বেশিরভাগ অপারেটিং সিস্টেমে থ্রেড অ্যাফিনিটি সেট করার উপায় রয়েছে (যেমন উইন্ডোজে লিনাক্সে pthread_setaffinity_np()অনেকগুলি পসিক্স সিস্টেমে )। মেমরি শ্রেণিবদ্ধতা নির্ধারণের জন্য hwloc এর মতো লাইব্রেরিও রয়েছে , তবে দুর্ভাগ্যক্রমে, বেশিরভাগ অপারেটিং সিস্টেমগুলি এখনও NUMA মেমরি পলিসি সেট করার উপায় সরবরাহ করে না। লিনাক্স লিবনুমা সহ একটি উল্লেখযোগ্য ব্যতিক্রমsched_setaffinity()SetThreadAffinityMask()অ্যাপ্লিকেশনটিকে মেমোরি নীতি এবং পৃষ্ঠা গ্রানুলারিটিতে পৃষ্ঠা মাইগ্রেশন হেরফের করার অনুমতি দেয় (২০০৪ সাল থেকে মূল লাইনে, এইভাবে ব্যাপকভাবে উপলব্ধ)। অন্যান্য অপারেটিং সিস্টেমগুলি আশা করে যে ব্যবহারকারীরা একটি অন্তর্নিহিত "প্রথম স্পর্শ" নীতি পর্যবেক্ষণ করবে।

"প্রথম স্পর্শ" নীতি নিয়ে কাজ করার অর্থ হ'ল কলকারীর তাজা বরাদ্দ মেমোরিতে প্রথম লেখার পরে তারা পরে যে পরিমাণ স্নেহ ব্যবহার করতে চান তারা থ্রেড তৈরি এবং বিতরণ করা উচিত। (খুব কম সিস্টেম এমনভাবে কনফিগার করা আছে যেগুলি malloc()পৃষ্ঠাগুলি সন্ধান করে, এটি কেবল ত্রুটিযুক্ত হলে এটিগুলি খুঁজে বের করার প্রতিশ্রুতি দেয়, সম্ভবত বিভিন্ন থ্রেড দ্বারা।) এর দ্বারা বোঝানো হয় যে বরাদ্দ ব্যবহারের calloc()পরে বরাদ্দ দেওয়ার পরে মেমরির তাত্ক্ষণিক ব্যবহার করা বা তাত্ক্ষণিক memset()ক্ষতিকারক যেহেতু এটি ত্রুটিযুক্ত হবে বরাদ্দ থ্রেড চালিত কোরের মেমরি বাসের মধ্যে সমস্ত মেমরি, একাধিক থ্রেড থেকে মেমরিটি অ্যাক্সেস করা হলে সবচেয়ে খারাপ ক্ষেত্রে মেমরি ব্যান্ডউইথের দিকে নিয়ে যায়। একই সি ++ newঅপারেটরের ক্ষেত্রে প্রযোজ্য যা অনেকগুলি নতুন বরাদ্দ শুরু করার জন্য জোর দেয় (উদাঃ)std::complex)। এই পরিবেশ সম্পর্কে কিছু পর্যবেক্ষণ:

  • বরাদ্দকে "থ্রেড সম্মিলিত" করা যেতে পারে, তবে এখন বরাদ্দটি থ্রেডিং মডেলে মিশ্রিত হয়ে যায় যা গ্রন্থাগারের জন্য অনাকাঙ্ক্ষিত, যা বিভিন্ন থ্রেডিং মডেল (সম্ভবত তাদের নিজস্ব থ্রেড পুলের সাহায্যে ক্লায়েন্টদের সাথে যোগাযোগ করতে পারে) হতে পারে।
  • RAII আইডোমেটিক সি +++ এর একটি গুরুত্বপূর্ণ অঙ্গ হিসাবে বিবেচিত, তবে এটি একটি NUMA পরিবেশে মেমরির সম্পাদনের জন্য সক্রিয়ভাবে ক্ষতিকারক বলে মনে হচ্ছে। স্থান নির্ধারণের newমাধ্যমে malloc()বা রুটিনগুলির মাধ্যমে বরাদ্দ হওয়া মেমরির সাহায্যে ব্যবহার করা যেতে পারে libnumaতবে এটি বরাদ্দকরণের প্রক্রিয়াটি পরিবর্তন করে (যা আমি বিশ্বাস করি যে এটি প্রয়োজনীয়)।
  • সম্পাদনা: অপারেটর সম্পর্কে আমার পূর্ববর্তী বক্তব্যটি newভুল ছিল, এটি একাধিক যুক্তি সমর্থন করতে পারে, চেতন এর উত্তর দেখুন। আমি বিশ্বাস করি যে নির্দিষ্ট সংযুক্তি ব্যবহারের জন্য গ্রন্থাগার বা এসটিএল ধারক পাওয়ার এখনও একটি উদ্বেগ রয়েছে। একাধিক ক্ষেত্রগুলি প্যাক করা হতে পারে এবং এটি নিশ্চিত করতে অসুবিধা হতে পারে, যেমন, std::vectorসঠিক প্রসঙ্গে ম্যানেজারটি সক্রিয় রেখে পুনরায় স্থান গ্রহণ করা।
  • প্রতিটি থ্রেড তার নিজস্ব ব্যক্তিগত মেমরি বরাদ্দ করতে এবং ত্রুটিযুক্ত করতে পারে তবে তার পরে প্রতিবেশী অঞ্চলে সূচীকরণ আরও জটিল। (একটি ভার্চুয়াল ম্যাট্রিক্স-ভেক্টর পণ্যটি বিবেচনা করুন the ম্যাট্রিক্স এবং ভেক্টরগুলির একটি সারি পার্টিশন সহ একটি ; ভার্চুয়াল মেমরির সাথে সংগতিপূর্ণ না হলে এর অজানা অংশকে সূচিকরণের জন্য আরও জটিল ডেটা কাঠামো প্রয়োজন ))Yএকজনএক্সএক্সএক্স

NUMA বরাদ্দ / ইনিশিয়ালেশনের কোনও সমাধান কি মূর্তিমান? আমি কি অন্যান্য সমালোচকদের হাতছাড়া করেছি?

(আমার সি ++ উদাহরণগুলি সেই ভাষার উপর জোর বোঝানোর জন্য আমি বোঝাতে চাইছি না, তবে সি ++ ভাষা মেমরি পরিচালনা সম্পর্কে এমন কিছু সিদ্ধান্ত এনকোড করে যা সি এর মতো কোন ভাষা নয়, সুতরাং সি ++ প্রোগ্রামাররা সেগুলি করার পরামর্শ দিলে আরও প্রতিরোধের ঝোঁক থাকে) জিনিস অন্যভাবে।)

উত্তর:


7

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


1
এটি একটি ব্যবহারিক সমাধান, তবে যদিও আমরা দ্রুত আরও বেশি কোর পাচ্ছি, তবে NUMA নোডের প্রতি কোরের সংখ্যা মোটামুটি ৪ টার দিকে স্থবির So তাই অনুমানমূলক 1000 কোর নোডের উপর, আমরা 250 এমপিআই প্রক্রিয়া চালিয়ে যাব? (এটি দুর্দান্ত হবে তবে আমি সন্দেহবাদী))
জেড ব্রাউন

আমি একমত নই যে NUMA প্রতি করের সংখ্যা স্থবির। স্যান্ডি ব্রিজ ই 5-তে ৮. ম্যাগনি কোর্স ছিল ১২. আমি একটি ওয়েস্টমিয়ার-এক্স নোড পেয়েছি १० দিয়ে। ইন্টারলাগোস (ওআরএনএল টাইটান) এর ২০ টি রয়েছে। নাইটস কর্নারের ৫০ এরও বেশি থাকবে I'd আমি অনুমান করতে পারি যে NUMA প্রতি করগুলি পালন করছে কমবেশি মুরের আইন নিয়ে গতি বাড়ান।
বিল বার্থ

ম্যাগনি কোর্স এবং ইন্টারলাগোসের বিভিন্ন NUMA অঞ্চলে দু'জন মারা যায়, এইভাবে NUMA অঞ্চলে 6 এবং 8 টি কোর হয়। ২০০ 2006-এ রিওয়াইন্ড করুন যেখানে কোয়াড-কোর ক্লোভারটাউনের দুটি সকেট একই ইন্টারফেস (ব্ল্যাকফোর্ড চিপসেট) মেমরির সাথে ভাগ করে নিবে এবং এটি আমার কাছে দেখে মনে হচ্ছে না যে NUMA অঞ্চলে প্রতি কোরের সংখ্যা এত দ্রুত বাড়ছে। নীল জিন / কিউ মেমরির এই সমতল দৃষ্টিভঙ্গিটি আরও কিছুটা বাড়িয়েছে এবং সম্ভবত নাইটস কর্নার আরও একটি পদক্ষেপ নেবে (যদিও এটি একটি পৃথক ডিভাইস, তাই সম্ভবত আমাদের পরিবর্তে জিপিইউগুলির সাথে তুলনা করা উচিত, যেখানে আমাদের 15 (ফার্মি) বা এখন 8 ( কেপলার) ফ্ল্যাট স্মৃতি দেখছেন এসএমএস)।
জেদ ব্রাউন

এএমডি চিপসে ভাল কল। আমি ভুলেগেছি. তবুও, আমি মনে করি আপনি কিছুক্ষণের জন্য এই অঞ্চলে ক্রমাগত বৃদ্ধি দেখতে যাচ্ছেন।
বিল বার্থ

6

এই উত্তরটি প্রশ্নের মধ্যে দুটি সি ++ সম্পর্কিত ভুল ধারণার প্রতিক্রিয়া হিসাবে।

  1. "একই বিষয়টি সি ++ নতুন অপারেটরের ক্ষেত্রে প্রযোজ্য যা নতুন বরাদ্দ (পিওডি সহ) শুরু করার জন্য জোর দেয়"
  2. "সি ++ অপারেটর নতুন মাত্র একটি প্যারামিটার নেয়"

আপনার উল্লেখ করা মাল্টি-কোর ইস্যুগুলির জন্য এটি সরাসরি উত্তর নয়। সুনাম বজায় থাকে যাতে সি ++ প্রোগ্রামারদের সি ++ জেলিয়ট হিসাবে শ্রেণিবদ্ধ করে এমন মন্তব্যে কেবল প্রতিক্রিয়া জানাচ্ছি;)।

1. পয়েন্ট 1. সি ++ "নতুন" বা স্ট্যাক বরাদ্দের নতুন বস্তুগুলি আরম্ভ করার জন্য জোর দেয় না, পিওডি কিনা তা নয়। শ্রেণীর ডিফল্ট কনস্ট্রাক্টর, যেমন ব্যবহারকারী দ্বারা নির্ধারিত হয়, সেই দায়িত্ব রয়েছে। নীচের প্রথম কোডটি ক্লাসটি পিওডি কিনা তা মুদ্রিত জাঙ্কটি দেখায়।

2 বিন্দুতে সি ++ একাধিক যুক্তি দিয়ে ওভারলোডিং "নতুন" করতে দেয়। নীচের দ্বিতীয় কোডটি একক অবজেক্ট বরাদ্দ করার জন্য এই জাতীয় কেস দেখায়। এটি একটি ধারণা দেওয়া উচিত এবং সম্ভবত আপনার যে পরিস্থিতিতে রয়েছে তা কার্যকর হবে। অপারেটর নতুন [] যথাযথভাবেও পরিবর্তন করা যেতে পারে।

// পয়েন্ট 1 এর কোড।

#include <iostream>

struct A
{
    // int/double/char/etc not inited with 0
    // with or without this constructor
    // If present, the class is not POD, else it is.
    A() { }

    int i;
    double d;
    char c[20];
};

int main()
{
    A* a = new A;
    std::cout << a->i << ' ' << a->d << '\n';
    for(int i = 0; i < 20; ++i)
        std::cout << (int) a->c[i] << '\n';
}

ইন্টেলের 11.1 সংকলক এই আউটপুটটি দেখায় (যা অবশ্যই "অ" দ্বারা নির্দেশিত অবিচ্ছিন্ন মেমরি)।

993001483 6.50751e+029
105
108
... // skipped
97
108

// পয়েন্ট 2 জন্য কোড।

#include <cstddef>
#include <iostream>
#include <new>

// Just to use two different classes.
class arena { };
class policy { };

struct A
{
    void* operator new(std::size_t, arena& arena_obj, policy& policy_obj)
    {
        std::cout << "special operator new\n";
        return (void*)0x1234; //Just to test
    }
};

void* operator new(std::size_t, arena& arena_obj, policy& policy_obj)
{
    std::cout << "special operator new (global)\n";
    return (void*)0x5678; //Just to test
}

int main ()
{
    arena arena_obj;
    policy policy_obj;
    A* ptr = new(arena_obj, policy_obj) A;
    int* iptr = new(arena_obj, policy_obj) int;
    std::cout << ptr << "\n";
    std::cout << iptr << "\n";
}

সংশোধনের জন্য ধন্যবাদ। এটা তোলে সি ++ অ POD অ্যারে যেমন ছাড়া সি আপেক্ষিক না বর্তমান অতিরিক্ত জটিলতা, যে আছে বলে মনে হয় std::complexযা করছে স্পষ্টভাবে সক্রিয়া।
জেদ ব্রাউন

1
@ জেডব্রাউন: 6 নম্বর কারণ ব্যবহার এড়াতে std::complex?
জ্যাক পলসন

1

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

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

(ii) আমি কীভাবে জানতে পারি যে আমি কোথায় আছি, যেখানে প্রতিটি স্ক্র্যাচ অবজেক্ট রয়েছে এবং আমার বর্তমান কোরের ক্যাশে গরম থাকা একটিটি অ্যাক্সেস করার জন্য আমার কোন স্ক্র্যাচ অবজেক্টটি নিতে হবে?

শেষ পর্যন্ত, আমরা এই সমাধানগুলির কোনওটিরও উত্তর পাই না এবং বেশ কয়েকটি কাজ করার পরে সিদ্ধান্ত নিয়েছে যে এই সমস্যাগুলি অনুসন্ধান ও সমাধান করার জন্য আমাদের কাছে সরঞ্জামের অভাব রয়েছে। আমি জানি কীভাবে কমপক্ষে নীতিগতভাবে সমস্যা সমাধান করা যায় (ii) (যথা, থ্রেড-লোকাল অবজেক্টগুলি ব্যবহার করে, ধরে নেওয়া যে থ্রেডগুলি প্রসেসরের কোরগুলিতে পিন করা আছে - অন্য অনুমান যা পরীক্ষার জন্য তুচ্ছ নয়) তবে আমার কাছে সমস্যা পরীক্ষা করার কোনও সরঞ্জাম নেই (ঝ)।

সুতরাং, আমাদের দৃষ্টিকোণ থেকে, NUMA এর সাথে ডিল করা এখনও একটি অমীমাংসিত প্রশ্ন।


আপনার থ্রেডগুলি সকেটের সাথে আবদ্ধ করা উচিত যাতে আপনার প্রসেসরগুলি পিন করা আছে কিনা তা ভাবতে হবে না। লিনাক্স জিনিসপত্র প্রায় সরানো পছন্দ করে।
বিল বার্থ

এছাড়াও, নমুনা getcpu () বা वेळापत्रक_getcpu () (আপনার libc এবং কার্নেল এবং হোয়াট নোটের উপর নির্ভর করে) আপনাকে লিনাক্সে থ্রেড কোথায় চলছে তা নির্ধারণ করতে দেওয়া উচিত।
বিল বার্থ

হ্যাঁ, এবং আমি মনে করি যে থ্রেডিং বিল্ডিং ব্লকগুলি আমরা থ্রেড পিন থ্রেডগুলিতে প্রসেসরের কাছে কাজ শিডিয়ুল করতে ব্যবহার করি। এই কারণেই আমরা থ্রেড-লোকাল স্টোরেজ নিয়ে কাজ করার চেষ্টা করেছি। তবে এখনও আমার সমস্যার সমাধান নিয়ে আসা আমার পক্ষে কঠিন (i)।
ওল্ফগ্যাং ব্যাঙ্গারথ

1

Hwloc এর বাইরে কয়েকটি সরঞ্জাম রয়েছে যা এইচপিসি ক্লাস্টারের মেমরি পরিবেশের বিষয়ে রিপোর্ট করতে পারে এবং যা বিভিন্ন ধরণের NUMA কনফিগারেশন সেট করতে ব্যবহার করা যেতে পারে।

আমি LIKWID কে এই জাতীয় একটি সরঞ্জাম হিসাবে প্রস্তাব করব কারণ এটি একটি কোড ভিত্তিক পদ্ধতিকে এড়িয়ে যায় যা আপনাকে উদাহরণস্বরূপ একটি কোরটিতে একটি প্রক্রিয়া পিন করতে দেয়। যন্ত্রটি নির্দিষ্ট মেমরির কনফিগারেশনকে সম্বোধন করার জন্য টুলিংয়ের এই পদ্ধতিটি ক্লাস্টারগুলিতে আপনার কোডের বহনযোগ্যতা নিশ্চিত করতে সহায়তা করবে।

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


LIKWID দরকারী, তবে প্রশ্নটি কীভাবে সংখ্যা / মেমরি-সংবেদনশীল গ্রন্থাগারগুলি লিখতে পারে যা নির্ভরযোগ্যভাবে কার্যকর করতে পারে এবং প্রত্যাশিত পরিবেশের বিবিধ পরিসর পরিবেশ, থ্রেডিং স্কিম, এমপিআই রিসোর্স ম্যানেজমেন্ট এবং অ্যাফিনিটি-সেটিং, এর সাথে ব্যবহারের প্রত্যাশিত স্থানীয় অবস্থান পরীক্ষা করতে পারে অন্যান্য গ্রন্থাগার, ইত্যাদি
জেড ব্রাউন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.