ঠিক 8192 উপাদানগুলিকে লুপ করার সময় আমার প্রোগ্রামটি কেন ধীর?


755

এখানে প্রশ্নযুক্ত প্রোগ্রাম থেকে নিষ্কাশন। ম্যাট্রিক্সের img[][]সাইজ সাইজ × সাইজ রয়েছে এবং এতে আরম্ভ করা হয়েছে:

img[j][i] = 2 * j + i

তারপরে, আপনি একটি ম্যাট্রিক্স res[][]তৈরি করেন এবং এখানকার প্রতিটি ক্ষেত্রকে img ম্যাট্রিক্সের চারপাশের 9 টি ক্ষেত্রের গড় হিসাবে গড়ে তোলা হয়। সরলতার জন্য সীমানাটি 0 এ বাকি আছে।

for(i=1;i<SIZE-1;i++) 
    for(j=1;j<SIZE-1;j++) {
        res[j][i]=0;
        for(k=-1;k<2;k++) 
            for(l=-1;l<2;l++) 
                res[j][i] += img[j+l][i+k];
        res[j][i] /= 9;
}

প্রোগ্রাম এটাই আছে। সম্পূর্ণতার জন্য, এখানে আসার আগে। এর পরে কোনও কোড আসে না। আপনি দেখতে পাচ্ছেন, এটি কেবল সূচনা।

#define SIZE 8192
float img[SIZE][SIZE]; // input image
float res[SIZE][SIZE]; //result of mean filter
int i,j,k,l;
for(i=0;i<SIZE;i++) 
    for(j=0;j<SIZE;j++) 
        img[j][i] = (2*j+i)%8196;

মূলত, এই প্রোগ্রামটি ধীর হয় যখন SIZE 2048 এর একাধিক হয়, যেমন সম্পাদনের সময়:

SIZE = 8191: 3.44 secs
SIZE = 8192: 7.20 secs
SIZE = 8193: 3.18 secs

সংকলকটি হলেন জিসিসি। আমি যা জানি তা থেকে, এটি মেমরি পরিচালনার কারণে, তবে আমি সত্যই সেই বিষয়টি সম্পর্কে খুব বেশি জানি না, যার কারণেই আমি এখানে জিজ্ঞাসা করছি।

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

আমি ইতিমধ্যে ম্যালোক / ফ্রি সম্পর্কে জানি, তবে সমস্যাটি ব্যবহৃত মেমরির পরিমাণ নয়, এটি কেবলমাত্র মৃত্যুদন্ডের সময়, তাই আমি জানি না কীভাবে এটি সাহায্য করবে।


67
@ বোকান এটি তখনই ঘটে যখন আকারটি ক্যাশের সমালোচনামূলক দিকের একাধিক।
লুচিয়ান গ্রিগোর

5
@ মিস্টিয়াল, এতে কিছু যায় আসে না, এটি একই সমস্যাটি প্রকাশ করে; কোড ভিন্ন হতে পারে, তবে মূলত উভয় প্রশ্নই একই সময় সম্পর্কে জিজ্ঞাসা করে (এবং তাদের শিরোনাম অবশ্যই স্পষ্টভাবে একই)।
গ্রিভেস

33
আপনি যদি উচ্চ কার্যকারিতা চান তবে আপনার 2 টি মাত্রার অ্যারে ব্যবহার করে চিত্রটি প্রক্রিয়া করা উচিত নয়। সমস্ত পিক্সেল কাঁচা অবস্থায় থাকার বিষয়টি বিবেচনা করুন এবং তাদেরকে এক মাত্রার অ্যারের মতো প্রক্রিয়া করুন। এই পাসটি দুটি পাসে করুন Do প্রথমে 3 পিক্সেলের স্লাইডিং যোগ ব্যবহার করে পার্শ্ববর্তী পিক্সেলের মান যুক্ত করুন: স্লাইডসাম + = এসসিআর [i + 1] -src [i-1]; DEST [আমি] = slideSum ;. তারপরে একইভাবে উলম্বভাবে করুন এবং একই সাথে ভাগ করুন: গন্তব্য [i] = (এসআরসি [i-প্রস্থ] + এসআরসি [i] + এসআরসি [i + প্রস্থ]) / 9। www-personal.engin.umd.umich.edu/~jwvm/ece581/18_RankedF.pdf
বোকন

8
এখানে আসলে দুটি জিনিস চলছে। এটি কেবল সুপার-সারিবদ্ধতা নয়।
রহস্যময়

7
(জাস্ট আপনার উত্তরে একটি ছোটখাট nitpick প্রথম কোড সেগমেন্ট জন্য, এটি চমৎকার হবে যদি আপনার সব loops জন্য ছিল ধনুর্বন্ধনী।।)
ট্রেভর বয়েড স্মিথ

উত্তর:


954

পার্থক্যটি নিম্নলিখিত সম্পর্কিত প্রশ্নগুলি থেকে একই সুপার-অ্যালাইনমেন্ট ইস্যু দ্বারা সৃষ্ট:

কোডটি নিয়ে অন্য একটি সমস্যা রয়েছে বলেই তা কেবল।

মূল লুপ থেকে শুরু:

for(i=1;i<SIZE-1;i++) 
    for(j=1;j<SIZE-1;j++) {
        res[j][i]=0;
        for(k=-1;k<2;k++) 
            for(l=-1;l<2;l++) 
                res[j][i] += img[j+l][i+k];
        res[j][i] /= 9;
}

প্রথম লক্ষ করুন যে দুটি অভ্যন্তরীণ লুপগুলি তুচ্ছ। এগুলি নিবন্ধভুক্ত হতে পারে:

for(i=1;i<SIZE-1;i++) {
    for(j=1;j<SIZE-1;j++) {
        res[j][i]=0;
        res[j][i] += img[j-1][i-1];
        res[j][i] += img[j  ][i-1];
        res[j][i] += img[j+1][i-1];
        res[j][i] += img[j-1][i  ];
        res[j][i] += img[j  ][i  ];
        res[j][i] += img[j+1][i  ];
        res[j][i] += img[j-1][i+1];
        res[j][i] += img[j  ][i+1];
        res[j][i] += img[j+1][i+1];
        res[j][i] /= 9;
    }
}

সুতরাং এটি দুটি আগ্রহের বাইরের লুপগুলিকে ছেড়ে দেয় যা আমরা আগ্রহী।

এখন আমরা দেখতে পাচ্ছি যে এই প্রশ্নটিতে সমস্যাটি একই রকম: 2D অ্যারেতে পুনরাবৃত্তি হওয়ার সময় লুপের ক্রমটি কার্য সম্পাদনকে কেন প্রভাবিত করে?

আপনি সারিবদ্ধের পরিবর্তে ম্যাট্রিক্স কলাম অনুসারে পুনরাবৃত্তি করছেন।


এই সমস্যাটি সমাধান করার জন্য, আপনার দুটি লুপের বিনিময় করা উচিত।

for(j=1;j<SIZE-1;j++) {
    for(i=1;i<SIZE-1;i++) {
        res[j][i]=0;
        res[j][i] += img[j-1][i-1];
        res[j][i] += img[j  ][i-1];
        res[j][i] += img[j+1][i-1];
        res[j][i] += img[j-1][i  ];
        res[j][i] += img[j  ][i  ];
        res[j][i] += img[j+1][i  ];
        res[j][i] += img[j-1][i+1];
        res[j][i] += img[j  ][i+1];
        res[j][i] += img[j+1][i+1];
        res[j][i] /= 9;
    }
}

এটি সমস্ত অ-অনুক্রমিক অ্যাক্সেস সম্পূর্ণরূপে সরিয়ে দেয় যাতে আপনি আর বৃহত্তর শক্তিগুলির মধ্যে এলোমেলো ধীর-ডাউনগুলি পান না।


কোর আই 7920 @ 3.5 গিগাহার্টজ

আসল কোড:

8191: 1.499 seconds
8192: 2.122 seconds
8193: 1.582 seconds

বিনিময় বহিরাগত লুপগুলি:

8191: 0.376 seconds
8192: 0.357 seconds
8193: 0.351 seconds

217
আমি আরও নোট করব যে অভ্যন্তরীণ লুপগুলি তালিকাভুক্তকরণের কার্যকারিতার উপর কোনও প্রভাব নেই। সংকলক সম্ভবত এটি স্বয়ংক্রিয়ভাবে করে। বাইরের লুপগুলির সাথে সমস্যাটি চিহ্নিত করা সহজ করার জন্য এগুলি থেকে মুক্তি পাওয়ার একমাত্র উদ্দেশ্যে আমি তাদের তালিকাভুক্ত করা হয়নি।
রহস্যময়

29
এবং আপনি প্রতিটি সারি বরাবর যোগফলগুলি ক্যাচ করে তিনটি অন্য ফ্যাক্টর দ্বারা এই কোডটি গতিময় করতে পারেন। তবে এটি এবং অন্যান্য অপ্টিমাইজেশানগুলি মূল প্রশ্নের ক্ষেত্রের বাইরে।
এরিক পোস্টপিসিল

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

19
@ ক্লিকউপভোট: আপনি বরং বিভ্রান্ত বলে মনে হচ্ছে। "দ্বিতীয় লুপ" হ'ল মাইস্টিকালটি হাত দ্বারা অভ্যন্তরীণ লুপগুলি তালিকাভুক্ত করেছিল। এটি এমন কিছু যা আপনার সংকলকটি অবশ্যই অবশ্যই যাইহোক করতে পারে, এবং মায়াস্টিকাল কেবলমাত্র বাইরের লুপগুলি দিয়ে বিষয়টি আরও সুস্পষ্ট করার জন্য এটি করেছিল did এটি কোনওভাবেই আপনার নিজের করা বিরক্ত করা উচিত নয়।
লিলি বালার্ড

154
এটি এসও-তে একটি ভাল উত্তরের একটি নিখুঁত উদাহরণ: অনুরূপ প্রশ্নগুলি উল্লেখ করে, আপনি কীভাবে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপে ধাপ আপনার মেশিনে আপনার অবদানের জন্য ধন্যবাদ.
ম্যাটসায়ার

57

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


এইভাবে চিত্রগুলি প্রক্রিয়া করা দক্ষ নয় efficient একক মাত্রার অ্যারে ব্যবহার করা ভাল। সমস্ত পিক্সেল প্রসেসিং করা হয় একটি লুপে সম্পন্ন। পয়েন্টগুলিতে এলোমেলো অ্যাক্সেস ব্যবহার করে করা যেতে পারে:

pointer + (x + y*width)*(sizeOfOnePixel)

এই বিশেষ ক্ষেত্রে, অনুভূমিকভাবে তিন পিক্সেল গ্রুপের যোগফল গণনা করা এবং ক্যাশে করা ভাল কারণ তারা প্রতিবার তিনবার ব্যবহার করা হয়।

আমি কিছু পরীক্ষা করেছি এবং আমার মনে হয় এটি ভাগ করে নেওয়া ভাল। প্রতিটি ফলাফল গড়ে পাঁচটি পরীক্ষা।

ব্যবহারকারী 1615209 দ্বারা মূল কোড:

8193: 4392 ms
8192: 9570 ms

রহস্যময় সংস্করণ:

8193: 2393 ms
8192: 2190 ms

1 ডি অ্যারে ব্যবহার করে দুটি পাস: অনুভূমিক অঙ্কের জন্য প্রথম পাস, উল্লম্ব যোগফল এবং গড়ের জন্য দ্বিতীয়। তিনটি পয়েন্টার সহ দু'টি পাস ঠিকানা এবং কেবলমাত্র এই জাতীয় বৃদ্ধি:

imgPointer1 = &avg1[0][0];
imgPointer2 = &avg1[0][SIZE];
imgPointer3 = &avg1[0][SIZE+SIZE];

for(i=SIZE;i<totalSize-SIZE;i++){
    resPointer[i]=(*(imgPointer1++)+*(imgPointer2++)+*(imgPointer3++))/9;
}

8193: 938 ms
8192: 974 ms

একটি 1 ডি অ্যারে ব্যবহার করে এবং এর মতো সম্বোধন করে দুটি পাস করুন:

for(i=SIZE;i<totalSize-SIZE;i++){
    resPointer[i]=(hsumPointer[i-SIZE]+hsumPointer[i]+hsumPointer[i+SIZE])/9;
}

8193: 932 ms
8192: 925 ms

একটি পাসের ক্যাচিংয়ের অনুভূমিক অঙ্কগুলি সামনের এক সারি এগিয়ে যায় যাতে তারা ক্যাশে থাকে:

// Horizontal sums for the first two lines
for(i=1;i<SIZE*2;i++){
    hsumPointer[i]=imgPointer[i-1]+imgPointer[i]+imgPointer[i+1];
}
// Rest of the computation
for(;i<totalSize;i++){
    // Compute horizontal sum for next line
    hsumPointer[i]=imgPointer[i-1]+imgPointer[i]+imgPointer[i+1];
    // Final result
    resPointer[i-SIZE]=(hsumPointer[i-SIZE-SIZE]+hsumPointer[i-SIZE]+hsumPointer[i])/9;
}

8193: 599 ms
8192: 652 ms

উপসংহার:

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

আমি নিশ্চিত যে আরও ভাল করা সম্ভব।

দ্রষ্টব্য, দয়া করে নোট করুন যে আমি এই উত্তরটি মাইস্টিকালের দুর্দান্ত উত্তরে বর্ণিত ক্যাশে সমস্যার পরিবর্তে সাধারণ পারফরম্যান্সের বিষয়গুলি লক্ষ্য করেই লিখেছি। শুরুতে এটি কেবল ছদ্ম কোড ছিল। আমাকে মন্তব্যে পরীক্ষাগুলি করতে বলা হয়েছিল ... এখানে পরীক্ষাগুলি সহ একটি সম্পূর্ণ রিফ্যাক্টরড সংস্করণ।


9
"আমি মনে করি এটি কমপক্ষে 3 গুণ বেশি দ্রুত" - কিছু দাবি বা উদ্ধৃতি দিয়ে এই দাবির ব্যাক আপ রাখতে হবে?
অ্যাডাম রোজেনফিল্ড

8
@ অ্যাডামরোসেনফিল্ড "আমার মনে হয়" = অনুমান! = "এটি" = দাবি। এর জন্য আমার কোনও মেট্রিক নেই এবং আমি একটি পরীক্ষা দেখতে চাই। তবে খনিতে 7 ইনক্রিমেন্ট, 2 উপ, 2 অ্যাড এবং পিক্সেল প্রতি এক ডিভ প্রয়োজন। প্রতিটি লুপ সিপিইউতে নিবন্ধভুক্ত হওয়ার চেয়ে কম স্থানীয় ভেরি ব্যবহার করে। সংকলক অপ্টিমাইজেশনের উপর নির্ভর করে সম্বোধনের জন্য অন্যটির জন্য 7 বর্ধিতকরণ, 6 হ্রাস, 1 ডিভ এবং 10 থেকে 20 মুলের মধ্যে প্রয়োজন। লুপের প্রতিটি নির্দেশের জন্য পূর্ববর্তী নির্দেশাবলীর ফলাফল প্রয়োজন, এটি পেন্টিয়ামগুলির সুপার-স্ক্যালার আর্কিটেকচারের সুবিধা বর্জন করে। সুতরাং এটি দ্রুত হতে হবে।
বোকান

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

1
ভাল, এগুলি কিছু চিত্তাকর্ষক সংখ্যা। যেমনটি আপনি পেয়েছেন, এটি মেমরির সম্পাদন সম্পর্কে সমস্ত কিছু - ইনক্রিমেন্ট সহ বেশ কয়েকটি পয়েন্টার ব্যবহার করে কোনও লাভ হয় নি।
অ্যাডাম রোজেনফিল্ড 6'12

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