সত্তা সিস্টেমগুলিতে ক্যাশে মিস এবং ব্যবহারযোগ্যতা ability


18

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

তবে এটি সামগ্রিক সি ++ আচরণ, আমি যে ভাষাতে সত্তা সিস্টেমটি প্রয়োগ করি সেইসাথে কিছু ব্যবহারযোগ্যতার সমস্যা সম্পর্কেও কিছু প্রশ্ন উত্থাপন করেছিল।

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

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

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


4
আমি ধারাবাহিক স্মৃতিতে উপাদানগুলি রাখার বিরক্ত করব না তবে কেবল প্রতিটি উপাদানগুলির জন্য গতিশীলভাবে মেমরি বরাদ্দ করব। সামঞ্জস্যপূর্ণ মেমরিটি আপনাকে কোনও ক্যাশে পারফরম্যান্স লাভ দেয় কারণ আপনি যে কোনও উপায়ে সুন্দর এলোমেলোভাবে ক্রমগুলি অ্যাক্সেস করতে পারেন।
জার্ককোএল

@ গ্রিমশো এখানে পড়ার জন্য একটি আকর্ষণীয় নিবন্ধ: ক্ষতিকারক.ক্যাট-
v.org/software/OO_programming/_pdf/…

@ জার্ককোএল -১০ পয়েন্ট আপনি যদি সিস্টেম ক্যাশে বান্ধব বানান এবং এলোমেলো উপায়ে এটি অ্যাক্সেস করেন তবে এটি কার্য সম্পাদনকে ব্যথা দেয় তবে এটি কেবল এটির শব্দেই বোকা। রৈখিক উপায়ে এটি অ্যাক্সেস করার বিন্দু । ইসিএসের শিল্প এবং কর্মক্ষমতা অর্জন রৈখিক উপায়ে অ্যাক্সেস করা সি / এস লেখার বিষয়ে about
আশ্চর্য

@ গ্রিমশো ভুলে যাবেন না ক্যাশে একটি বড় পূর্ণসংখ্যা। আপনি বেশ কয়েকটি কে 1 এল 1 ক্যাশে উপলব্ধ পেয়েছেন (এবং অন্যান্য এমবি), আপনি যদি দৈত্য কিছু না করেন তবে একবারে এবং ক্যাশে-বান্ধব হওয়ার সময় কয়েকটি সিস্টেমে অ্যাক্সেস করা ঠিক হবে।
আশ্চর্য

2
@ ওয়ানড্রা আপনি কীভাবে উপাদানগুলিতে রৈখিক অ্যাক্সেস নিশ্চিত করবেন? আমি যদি রেন্ডারিংয়ের জন্য উপাদানগুলি সংগ্রহ করি এবং ক্যামেরা থেকে ক্রমান্বয়ে ক্রমে সংস্থাগুলি প্রক্রিয়াজাতকরণ চাই তা বলি। এই সত্তাগুলির জন্য রেন্ডারিং উপাদানগুলি মেমরিতে রৈখিকভাবে অ্যাক্সেস করতে পারে না। আপনি যা বলছেন তত্ত্বগতভাবে এটি দুর্দান্ত জিনিস যদিও আমি এটি বাস্তবে কাজ করে দেখছি না তবে আপনি যদি আমাকে ভুল প্রমাণ করেন তবে আমি আনন্দিত (:
বাস্তবে JarkkoL

উত্তর:


13

প্রথমত, আমি এটি বলব না যে এই ক্ষেত্রে আপনি আপনার ব্যবহারের ক্ষেত্রে নির্ভর করে খুব শীঘ্রই অনুকূলিত করছেন। যাইহোক যাইহোক, আপনি একটি আকর্ষণীয় প্রশ্ন জিজ্ঞাসা করেছেন এবং আমার নিজেই যেমন এটির অভিজ্ঞতা পেয়েছেন, আমি ওজন করব I'll আমি কীভাবে আমি কীভাবে কাজ শেষ করেছি এবং পথে কী পেলাম তা ব্যাখ্যা করার চেষ্টা করব।

  • প্রতিটি সত্তা জেনেরিক উপাদান হ্যান্ডেলগুলির একটি ভেক্টর ধারণ করে যা কোনও প্রকারের প্রতিনিধিত্ব করতে পারে।
  • প্রতিটি উপাদান হ্যান্ডেল একটি কাঁচা টি * পয়েন্টার উত্পাদনের জন্য নির্ধারণ করা যেতে পারে। *নিচে দেখ.
  • প্রতিটি উপাদান ধরণের নিজস্ব পুল রয়েছে, মেমরির একটি অবিচ্ছিন্ন ব্লক (আমার ক্ষেত্রে স্থির আকার)।

এটি লক্ষ করা উচিত যে না, আপনি কেবল কোনও উপাদান পুলে সর্বদা অতিক্রম করতে পারবেন না এবং আদর্শ, পরিষ্কার জিনিসটি করতে পারবেন না। যেমনটি আপনি বলেছেন, উপাদানগুলির মধ্যে অপরিহার্য লিঙ্ক রয়েছে, যার মধ্যে আপনাকে সত্যিকার অর্থে জিনিসগুলিকে একটি সময়ে সত্তা প্রসেস করতে হবে।

তবে, এমন কেস রয়েছে (যেমন আমি খুঁজে পেয়েছি) যেখানে আপনি কোনও নির্দিষ্ট উপাদান ধরণের জন্য আক্ষরিকভাবে একটি লুপের জন্য লিখতে পারেন এবং আপনার সিপিইউ ক্যাশে লাইনের দুর্দান্ত ব্যবহার করতে পারেন। যারা অজান্ত বা আরও জানতে চান তাদের জন্য https://en.wikedia.org/wiki/Locality_of_references দেখুন । একই নোটে, যখন সম্ভব হবে তখন আপনার সিপিইউ ক্যাশে লাইনের আকারের চেয়ে কম বা তার সমান অংশ রাখার চেষ্টা করুন। আমার লাইনের আকার ছিল 64 বাইট, যা আমি বিশ্বাস করি সাধারণ।

আমার ক্ষেত্রে, সিস্টেমটি প্রয়োগের প্রচেষ্টা করা এটির পক্ষে যথেষ্ট ছিল। আমি দৃশ্যমান পারফরম্যান্স লাভ দেখেছি (অবশ্যই প্রোফাইল)। এটি আপনার পক্ষে সিদ্ধান্ত নেওয়া দরকার এটি একটি ভাল ধারণা কিনা। পারফরম্যান্সের সবচেয়ে বড় লাভ আমি 1000+ সত্তা দেখেছি।

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

আমি ব্যক্তিগতভাবেও এই সমস্যাটি সমাধান করেছি। আমি একটি সিস্টেম থাকার শেষ যেখানে:

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

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

সর্বোপরি, কেবল কিছু চেষ্টা করুন। যতক্ষণ না আপনি আসল বিশ্বের দৃশ্যের অবতারণা করেন, কেউ এখানে যা কিছু বলে তা কেবল কাজ করার একমাত্র উপায়, যা আপনার পক্ষে উপযুক্ত নাও হতে পারে।

এটা কি সাহায্য করে? আমি অস্পষ্ট যে কোনও বিষয় পরিষ্কার করার চেষ্টা করব। এছাড়াও কোন সংশোধন প্রশংসা করা হয়।


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

5

শুধু এই উত্তর দিতে:

আমার প্রশ্নটি, যেহেতু আমি এই ক্ষেত্রেগুলিতে একবারে রৈখিকভাবে একটি স্বতন্ত্র অ্যারের পুনরাবৃত্তি করি না, তাই আমি কি অবিলম্বে এইভাবে উপাদানগুলি বরাদ্দ করা থেকে কর্মক্ষমতা লাভের ত্যাগ করছি? আমি যখন সি ++ তে পুনরায় পুনরুক্তি করি, তখন প্রতিটি চক্রের দুটি পৃথক সংঘবদ্ধ অ্যারে ব্যবহার করি এবং উভয় থেকে ডেটা ব্যবহার করি?

না (অন্তত প্রয়োজন হয় না)। ক্যাশে নিয়ন্ত্রক, বেশিরভাগ ক্ষেত্রেই দক্ষতার সাথে একাধিক সংঘবদ্ধ অ্যারে থেকে পড়াতে সক্ষম হন। গুরুত্বপূর্ণ অংশটি হ'ল প্রতিটি অ্যারেটিকে রৈখিকভাবে অ্যাক্সেস করার জন্য চেষ্টা করা।

এটি প্রদর্শনের জন্য, আমি একটি ছোট বেঞ্চমার্ক লিখেছিলাম (সাধারণ বেনমার্ক ক্যাভেটস প্রযোজ্য)।

একটি সাধারণ ভেক্টর কাঠামো দিয়ে শুরু করা:

struct float3 { float x, y, z; };

আমি দেখতে পেলাম যে একটি লুপ দুটি পৃথক অ্যারের প্রতিটি উপাদানকে সংমিশ্রণ করে এবং তৃতীয়টিতে ফলাফল সংরক্ষণ করে ঠিক একই সংস্করণে সম্পাদিত হয় যেখানে উত্স ডেটাটি একটি একক অ্যারেতে অন্তর্নিবিষ্ট ছিল এবং ফলাফলটি তৃতীয় অংশে সঞ্চিত ছিল। তবে আমি খুঁজে পেলাম, যদি আমি উত্সটির সাথে ফলাফলটি আন্তঃলিখন করি, তবে পারফরম্যান্স ক্ষতিগ্রস্থ হয়েছিল (প্রায় 2 এর ফ্যাক্টর দ্বারা)।

যদি আমি এলোমেলোভাবে ডেটা অ্যাক্সেস করে থাকি তবে 10 এবং 20 এর মধ্যে একটি ফ্যাক্টর দ্বারা কার্য সম্পাদনটি ক্ষতিগ্রস্থ হয়।

সময় (10,000,000 উপাদান)

লিনিয়ার অ্যাক্সেস

  • পৃথক অ্যারে 0.21 গুলি
  • আন্তঃবাহিত উত্স 0.21
  • আন্তঃভিত্তিক উত্স এবং ফলাফল 0.48 গুলি

এলোমেলো প্রবেশ

  • পৃথক অ্যারে 2.42 গুলি
  • আন্তঃবাহিত উত্স 4.43s
  • আন্তঃবাহিত উত্স এবং ফলাফল 4.00s

উত্স (ভিজ্যুয়াল স্টুডিও 2013 এর সাথে সংকলিত):

#include <Windows.h>
#include <vector>
#include <algorithm>
#include <iostream>

struct float3 { float x, y, z; };

float3 operator+( float3 const &a, float3 const &b )
{
    return float3{ a.x + b.x, a.y + b.y, a.z + b.z };
}

struct Both { float3 a, b; };

struct All { float3 a, b, res; };


// A version without any indirection
void sum( float3 *a, float3 *b, float3 *res, int n )
{
    for( int i = 0; i < n; ++i )
        *res++ = *a++ + *b++;
}

void sum( float3 *a, float3 *b, float3 *res, int *index, int n )
{
    for( int i = 0; i < n; ++i, ++index )
        res[*index] = a[*index] + b[*index];
}

void sum( Both *both, float3 *res, int *index, int n )
{
    for( int i = 0; i < n; ++i, ++index )
        res[*index] = both[*index].a + both[*index].b;
}

void sum( All *all, int *index, int n )
{
    for( int i = 0; i < n; ++i, ++index )
        all[*index].res = all[*index].a + all[*index].b;
}

class PerformanceTimer
{
public:
    PerformanceTimer() { QueryPerformanceCounter( &start ); }
    double time()
    {
        LARGE_INTEGER now, freq;
        QueryPerformanceCounter( &now );
        QueryPerformanceFrequency( &freq );
        return double( now.QuadPart - start.QuadPart ) / double( freq.QuadPart );
    }
private:
    LARGE_INTEGER start;
};

int main( int argc, char* argv[] )
{
    const int count = 10000000;

    std::vector< float3 > a( count, float3{ 1.f, 2.f, 3.f } );
    std::vector< float3 > b( count, float3{ 1.f, 2.f, 3.f } );
    std::vector< float3 > res( count );

    std::vector< All > all( count, All{ { 1.f, 2.f, 3.f }, { 1.f, 2.f, 3.f }, { 1.f, 2.f, 3.f } } );
    std::vector< Both > both( count, Both{ { 1.f, 2.f, 3.f }, { 1.f, 2.f, 3.f } } );

    std::vector< int > index( count );
    int n = 0;
    std::generate( index.begin(), index.end(), [&]{ return n++; } );
    //std::random_shuffle( index.begin(), index.end() );

    PerformanceTimer timer;
    // uncomment version to test
    //sum( &a[0], &b[0], &res[0], &index[0], count );
    //sum( &both[0], &res[0], &index[0], count );
    //sum( &all[0], &index[0], count );
    std::cout << timer.time();
    return 0;
}

1
এটি ক্যাশে স্থানীয়তা সম্পর্কে আমার সন্দেহের সাথে অনেক সহায়তা করে, ধন্যবাদ!
গ্রিমশো

সহজ এবং আকর্ষণীয় উত্তর যা আমিও আশ্বাস পাই find :) আমি দেখতে আগ্রহী যে এই ফলাফলগুলি বিভিন্ন আইটেম গণনাগুলির জন্য কীভাবে পৃথক হয় (উদাহরণস্বরূপ, 10,000,000 এর পরিবর্তে 1000?) অথবা আপনার যদি মানগুলির আরও অ্যারে থাকে (যেমন, 3 এর উপাদানগুলির সংমিশ্রণ) -5 আলাদা অ্যারে এবং মানটিকে আলাদা আলাদা অ্যারেতে সঞ্চয় করে)।
আভোসোমানিয়া

2

সংক্ষিপ্ত উত্তর: প্রোফাইল তারপর অনুকূলিতকরণ।

দীর্ঘ উত্তর:

তবে, যখন আমি প্রকৃত গেমপ্লে বাস্তবায়নের জন্য কোনও সিস্টেম থেকে তাদের সাথে কিছু করার জন্য উপাদান উপাদানগুলি পুনরাবৃত্তি করতে চলেছি তখন আমি লক্ষ্য করেছি যে আমি প্রায় সবসময়ই একবারে দু'বার বা আরও বেশি উপাদানের সাথে কাজ করছি।

আমি যখন সি ++ তে পুনরায় পুনরুক্তি করি, তখন প্রতিটি চক্রের দুটি পৃথক সংঘবদ্ধ অ্যারে ব্যবহার করি এবং উভয় থেকে ডেটা ব্যবহার করি?

C ++ ক্যাশে মিস করার জন্য দায়ী নয়, কারণ এটি কোনও প্রোগ্রামিং ভাষার জন্য প্রযোজ্য। আধুনিক সিপিইউ আর্কিটেকচার কীভাবে কাজ করে তা এটির সাথে সম্পর্কিত।

আপনার সমস্যাটি প্রাক-পরিপক্ক অপ্টিমাইজেশন বলা যেতে পারে তার একটি ভাল উদাহরণ হতে পারে ।

আমার মতে আপনি প্রোগ্রামের মেমরি অ্যাক্সেসের নিদর্শনগুলি না দেখে ক্যাশে লোকালটির জন্য খুব তাড়াতাড়ি অনুকূলিত হন। তবে আরও বড় প্রশ্নটি কি আপনার সত্যিকারের অনুকূলতার এই জাতীয় (রেফারেন্সের লোকেশন) দরকার ছিল?

অ্যাগনারের কুয়াশা পরামর্শ দেয় যে আপনি নিজের অ্যাপ্লিকেশনটি প্রোফাইল দেওয়ার আগে এবং / বা বাধা কোথায় রয়েছে তা নিশ্চিত হওয়ার আগে আপনার অনুকূলিত হওয়া উচিত নয়। (এগুলি তার চমৎকার গাইডে উল্লেখ করা হয়েছে below নীচে লিঙ্ক করুন)

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

দুর্ভাগ্যক্রমে আপনি যা করেছিলেন তা অনুমান করে নেওয়া হয়েছিল যে অ্যারে প্রতি একটি উপাদান ধরণের বরাদ্দ করা আপনাকে আরও ভাল পারফরম্যান্স দেবে, যখন বাস্তবে আপনি সম্ভবত আরও বেশি ক্যাশে মিস করেছেন বা এমনকি ক্যাশে বিতর্ক সৃষ্টি করেছেন।

আপনার অবশ্যই তাঁর দুর্দান্ত সি ++ অপ্টিমাইজেশান গাইডটি দেখতে হবে

আর একটি বিষয় যা আমি জিজ্ঞাসা করতে চেয়েছিলাম, তা হল কীভাবে উপাদান বা সত্তাগুলির রেফারেন্স রাখা উচিত, কারণ উপাদানগুলি কীভাবে মেমোরিতে রাখা হয় তার খুব প্রকৃতি।

ব্যক্তিগতভাবে আমি একক মেমরি ব্লকে সর্বাধিক ব্যবহৃত উপাদানগুলি একসাথে বরাদ্দ করব, যাতে তাদের "কাছাকাছি" ঠিকানা রয়েছে। উদাহরণস্বরূপ একটি অ্যারে দেখতে পাবেন:

[{ID0 Transform Model PhysicsComp }{ID10 Transform Model PhysicsComp }{ID2 Transform Model PhysicsComp }..] এবং তারপরে পারফরম্যান্স "যথেষ্ট ভাল" না হলে সেখান থেকে অনুকূলকরণ শুরু করুন start


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

আমি যা দেখছি সেগুলি থেকে উপাদানগুলি সংরক্ষণের তিনটি প্রধান উপায় রয়েছে, সমস্ত সত্তা প্রতি একক অ্যারে জুড়ে, সমস্ত একসাথে স্বতন্ত্র অ্যারে টাইপ করে, এবং আমি সঠিকভাবে বুঝতে পারলে, আপনি বিভিন্ন সত্ত্বাকে একটি বড় অ্যারেতে স্বচ্ছভাবে সংরক্ষণ করার পরামর্শ দেন, এবং প্রতি সত্তা, এর সমস্ত উপাদান একসাথে আছে?
গ্রিমশো

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

ডাউনভোটার কে বুঝিয়ে দেবেন কেয়ার? আমার উত্তরে কেবল সমস্যাটি উল্লেখ করুন। আরও ভাল উত্তর দিতে ভাল।
ধারণাগুলি

1

আমার প্রশ্নটি, যেহেতু আমি এই ক্ষেত্রেগুলিতে একবারে রৈখিকভাবে একটি স্বতন্ত্র অ্যারের পুনরাবৃত্তি করি না, তাই আমি কি অবিলম্বে এইভাবে উপাদানগুলি বরাদ্দ করা থেকে কর্মক্ষমতা লাভের ত্যাগ করছি?

সম্ভাবনাগুলি হ'ল আপনি "অনুভূমিক" ভেরিয়েবল-সাইজের ব্লকের কোনও সত্তার সাথে সংযুক্ত উপাদানগুলি ইন্টারলেভ করার চেয়ে কমপ্লেক্স টাইপ আলাদা আলাদা "উল্লম্ব" অ্যারে দিয়ে সামগ্রিকভাবে কম ক্যাশে মিস করবেন so

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

// Assuming 8-bit chars and 64-bit doubles.
struct Foo
{
    // 1 byte
    char a;

    // 1 byte
    char b;
};

struct Bar
{
    // 8 bytes
    double opacity;

    // 8 bytes
    double radius;
};

আসুন আমরা বইয়ের পাতার মাঝে মাঝে করতে চান Fooএবং Barতাদের মেমরির সঠিক পরবর্তী প্রতিটি অন্যান্য দোকান:

// Assuming 8-bit chars and 64-bit doubles.
struct FooBar
{
    // 1 byte
    char a;

    // 1 byte
    char b;

    // 6 bytes padding for 64-bit alignment of 'opacity'

    // 8 bytes
    double opacity;

    // 8 bytes
    double radius;
};

এখন পৃথক মেমরি অঞ্চলে ফু এবং বার সঞ্চয় করতে 18 বাইট নেওয়ার পরিবর্তে এগুলিকে ফিউজ করতে 24 বাইট লাগবে। আপনি অর্ডারটি অদলবদল করুন তা বিবেচ্য নয়:

// Assuming 8-bit chars and 64-bit doubles.
struct BarFoo
{
    // 8 bytes
    double opacity;

    // 8 bytes
    double radius;

    // 1 byte
    char a;

    // 1 byte
    char b;

    // 6 bytes padding for 64-bit alignment of 'opacity'
};

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

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

এখানে চিত্র বর্ণনা লিখুন

যেখানে তীরগুলি কেবল ইঙ্গিত দেয় যে সত্তা কোনও উপাদানটির "মালিকানাধীন"। আমরা দেখতে পাচ্ছি যে আমরা যদি উভয় সত্তার সমস্ত গতি এবং রেন্ডারিং উপাদানগুলিতে অ্যাক্সেস করার চেষ্টা করি তবে আমরা স্মৃতিতে সমস্ত স্থান জুড়ে শেষ করি। এই ধরণের বিক্ষিপ্ত অ্যাক্সেস প্যাটার্নটিতে আপনি কোনও গতি উপাদানকে অ্যাক্সেস করতে, বলতে, কোনও গতি উপাদানকে অ্যাক্সেস করতে, ক্যাশ লাইনে ডেটা লোড করতে পারেন এবং তারপরে আরও আগের উপাদানগুলি অকার্যকর করতে পারেন, কেবল একই মেমরি অঞ্চলটি আবার লোড করার জন্য যা ইতিমধ্যে অন্য গতির জন্য উচ্ছেদ করা হয়েছিল load উপাদান. সুতরাং যে একই মেমরি অঞ্চলগুলি একাধিকবার ক্যাশে লাইনে কেবল লুপটি লুপ এবং উপাদানগুলির তালিকার অ্যাক্সেসে লোড করা খুব অপব্যয়কর হতে পারে।

আসুন সেই জগাখিটি কিছুটা পরিষ্কার করুন যাতে আমরা আরও পরিষ্কারভাবে দেখতে পারি:

এখানে চিত্র বর্ণনা লিখুন

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

পরিস্থিতি উন্নতির একটি খুব সহজ উপায় হ'ল আপনার উপাদানগুলির মালিকানাধীন আইডি / সূচকগুলির উপর ভিত্তি করে আপনার উপাদানগুলি কেবল রেডিক্স করা। এই মুহুর্তে আপনি এই জাতীয় কিছু পান:

এখানে চিত্র বর্ণনা লিখুন

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

সর্বাধিক গুরুত্বপূর্ণ, একবার এই বাছাই করা হয়ে গেলে, আপনি কেবল একটি লুপে পুনরায় লোড করতে কেবল কোনও মেমরি অঞ্চলকে ক্যাশে লাইনে ডেটা লোড করবেন না।

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

Sorting 1000000 elements 32 times...
mt_sort_int: {0.203000 secs}
-- small result: [ 22 48 59 77 79 80 84 84 93 98 ]
mt_sort: {1.248000 secs}
-- small result: [ 22 48 59 77 79 80 84 84 93 98 ]
mt_radix_sort: {0.202000 secs}
-- small result: [ 22 48 59 77 79 80 84 84 93 98 ]
std::sort: {1.810000 secs}
-- small result: [ 22 48 59 77 79 80 84 84 93 98 ]
qsort: {2.777000 secs}
-- small result: [ 22 48 59 77 79 80 84 84 93 98 ]

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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.