c++ - কেন যৌথ লুপ তুলনায় আলাদা loops elementwise সংযোজন অনেক দ্রুত?
performance compiler-optimization (7)
অনুমান করুন a1
, b1
, c1
এবং d1
পয়েন্ট মেমরি হিপ এবং আমার সংখ্যাসূচক d1
নিম্নলিখিত মূল লুপ রয়েছে।
const int n = 100000;
for (int j = 0; j < n; j++) {
a1[j] += b1[j];
c1[j] += d1[j];
}
এই লুপ লুপ জন্য অন্য বাইরের মাধ্যমে 10,000 বার মৃত্যুদন্ড কার্যকর করা হয়। এটি দ্রুততর করার জন্য, আমি কোডটি এতে পরিবর্তন করেছি:
for (int j = 0; j < n; j++) {
a1[j] += b1[j];
}
for (int j = 0; j < n; j++) {
c1[j] += d1[j];
}
এমটি ভিসুয়াল সি ++ 10.0 এ SSE2 সম্পূর্ণ অপ্টিমাইজেশান এবং SSE2 একটি Intel Core 2 Duo (x64) এ 32-বিটের জন্য সক্ষম, প্রথম উদাহরণ 5.5 সেকেন্ড সময় নেয় এবং ডাবল-লুপ উদাহরণটি শুধুমাত্র 1.9 সেকেন্ড সময় নেয়। আমার প্রশ্ন হল: (নীচের আমার rephrased প্রশ্ন পড়ুন দয়া করে)
PS: আমি নিশ্চিত নই, যদি এটি সাহায্য করে:
প্রথম লুপের জন্য Disassembly মূলত এই মত দেখায় (এই ব্লক পুরো প্রোগ্রামে প্রায় পাঁচবার পুনরাবৃত্তি করা হয়):
movsd xmm0,mmword ptr [edx+18h]
addsd xmm0,mmword ptr [ecx+20h]
movsd mmword ptr [ecx+20h],xmm0
movsd xmm0,mmword ptr [esi+10h]
addsd xmm0,mmword ptr [eax+30h]
movsd mmword ptr [eax+30h],xmm0
movsd xmm0,mmword ptr [edx+20h]
addsd xmm0,mmword ptr [ecx+28h]
movsd mmword ptr [ecx+28h],xmm0
movsd xmm0,mmword ptr [esi+18h]
addsd xmm0,mmword ptr [eax+38h]
ডবল লুপ উদাহরণের প্রতিটি লুপ এই কোডটি তৈরি করে (নিম্নলিখিত ব্লকটি প্রায় তিনবার পুনরাবৃত্তি হয়):
addsd xmm0,mmword ptr [eax+28h]
movsd mmword ptr [eax+28h],xmm0
movsd xmm0,mmword ptr [ecx+20h]
addsd xmm0,mmword ptr [eax+30h]
movsd mmword ptr [eax+30h],xmm0
movsd xmm0,mmword ptr [ecx+28h]
addsd xmm0,mmword ptr [eax+38h]
movsd mmword ptr [eax+38h],xmm0
movsd xmm0,mmword ptr [ecx+30h]
addsd xmm0,mmword ptr [eax+40h]
movsd mmword ptr [eax+40h],xmm0
প্রশ্নটি কোন প্রাসঙ্গিকতা হিসাবে পরিণত হয়েছে, কারণ আচরণগুলি অ্যারে (এন) এবং CPU ক্যাশের মাপের উপর গুরুতরভাবে নির্ভর করে। তাই যদি আরও আগ্রহ থাকে, তবে আমি প্রশ্নটি পুনরায় লিখি:
আপনি নীচের গ্রাফের পাঁচটি অঞ্চলের দ্বারা চিত্রিত বিভিন্ন ক্যাশে আচরণের দিকে পরিচালিত বিশদগুলিতে কিছু কঠিন অন্তর্দৃষ্টি সরবরাহ করতে পারেন?
CPU গুলি / ক্যাশে আর্কিটেকচারের মধ্যে পার্থক্যগুলি নির্দেশ করতে এটিও আকর্ষণীয় হতে পারে, এই CPU গুলির জন্য একই গ্রাফ সরবরাহ করে।
পিপিএস: এখানে সম্পূর্ণ কোড। এটি উচ্চ রেজল্যুশন সময়কালের জন্য TBB Tick_Count
ব্যবহার করে, যা TBB_TIMING
ম্যাক্রো সংজ্ঞায়িত না করে অক্ষম করা যেতে পারে:
#include <iostream>
#include <iomanip>
#include <cmath>
#include <string>
//#define TBB_TIMING
#ifdef TBB_TIMING
#include <tbb/tick_count.h>
using tbb::tick_count;
#else
#include <time.h>
#endif
using namespace std;
//#define preallocate_memory new_cont
enum { new_cont, new_sep };
double *a1, *b1, *c1, *d1;
void allo(int cont, int n)
{
switch(cont) {
case new_cont:
a1 = new double[n*4];
b1 = a1 + n;
c1 = b1 + n;
d1 = c1 + n;
break;
case new_sep:
a1 = new double[n];
b1 = new double[n];
c1 = new double[n];
d1 = new double[n];
break;
}
for (int i = 0; i < n; i++) {
a1[i] = 1.0;
d1[i] = 1.0;
c1[i] = 1.0;
b1[i] = 1.0;
}
}
void ff(int cont)
{
switch(cont){
case new_sep:
delete[] b1;
delete[] c1;
delete[] d1;
case new_cont:
delete[] a1;
}
}
double plain(int n, int m, int cont, int loops)
{
#ifndef preallocate_memory
allo(cont,n);
#endif
#ifdef TBB_TIMING
tick_count t0 = tick_count::now();
#else
clock_t start = clock();
#endif
if (loops == 1) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++){
a1[j] += b1[j];
c1[j] += d1[j];
}
}
} else {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
a1[j] += b1[j];
}
for (int j = 0; j < n; j++) {
c1[j] += d1[j];
}
}
}
double ret;
#ifdef TBB_TIMING
tick_count t1 = tick_count::now();
ret = 2.0*double(n)*double(m)/(t1-t0).seconds();
#else
clock_t end = clock();
ret = 2.0*double(n)*double(m)/(double)(end - start) *double(CLOCKS_PER_SEC);
#endif
#ifndef preallocate_memory
ff(cont);
#endif
return ret;
}
void main()
{
freopen("C:\\test.csv", "w", stdout);
char *s = " ";
string na[2] ={"new_cont", "new_sep"};
cout << "n";
for (int j = 0; j < 2; j++)
for (int i = 1; i <= 2; i++)
#ifdef preallocate_memory
cout << s << i << "_loops_" << na[preallocate_memory];
#else
cout << s << i << "_loops_" << na[j];
#endif
cout << endl;
long long nmax = 1000000;
#ifdef preallocate_memory
allo(preallocate_memory, nmax);
#endif
for (long long n = 1L; n < nmax; n = max(n+1, long long(n*1.2)))
{
const long long m = 10000000/n;
cout << n;
for (int j = 0; j < 2; j++)
for (int i = 1; i <= 2; i++)
cout << s << plain(n, m, j, i);
cout << endl;
}
}
(এটি n
বিভিন্ন মানগুলির জন্য FLOP / গুলি দেখায়।)
এটি একটি ভিন্ন কোডের কারণে নয়, তবে ক্যাশিংয়ের কারণে: সিএমপি নিবন্ধকগুলির চেয়ে RAM বেশি ধীর এবং CPU- র মধ্যে একটি ক্যাশে মেমরি রয়েছে যা প্রতিবার পরিবর্তনশীল পরিবর্তন করার সময় RAM লিখতে বাধা দেয়। কিন্তু ক্যাশটি RAM এর মতো বড় নয়, অতএব, এটি কেবল এটির একটি ভগ্নাংশকে ম্যাপ করে।
প্রথম কোড প্রতিটি লুপে তাদের পরিবর্তিত দূরবর্তী মেমরি ঠিকানা সংশোধন করে, এইভাবে ক্যাশে অকার্যকর করার জন্য ক্রমাগত প্রয়োজন।
দ্বিতীয় কোডটি বিকল্প নয়: এটি কেবল দুবার উপাত্তগুলিতে প্রবাহিত হয়। এটি ক্যাশে সমস্ত কাজ সম্পন্ন করে তোলে, দ্বিতীয় লুপ শুরু হওয়ার পরেই এটি অকার্যকর করে।
এর আরও বিশ্লেষণের পরে, আমি বিশ্বাস করি এটি (অন্তত আংশিকভাবে) চার পয়েন্টারগুলির ডাটা সংযোজন দ্বারা সৃষ্ট। এই ক্যাশ ব্যাংক / উপায় দ্বন্দ্ব কিছু স্তর হতে হবে।
আপনি যদি কীভাবে আপনার অ্যারে বরাদ্দ করছেন সে বিষয়ে সঠিকভাবে আমি অনুমান করেছি, তবে পৃষ্ঠা লাইনটিতে এটি সংলগ্ন হওয়ার সম্ভাবনা রয়েছে ।
এর মানে হল যে প্রতিটি লুপে আপনার সমস্ত অ্যাক্সেস একই ক্যাশে উপায়ে পড়ে। তবে, ইন্টেল প্রসেসরগুলির কিছু সময়ের জন্য 8-উপায় L1 ক্যাশে সহযোগিতা ছিল। কিন্তু বাস্তবে, কর্মক্ষমতা সম্পূর্ণরূপে অভিন্ন নয়। 4-উপায়ে অ্যাক্সেস করা এখনও ২-উপায়ে বলার অপেক্ষা রাখে না।
সম্পাদন করুন: এটি আসলে দেখায় যে আপনি আলাদাভাবে সমস্ত অ্যারে বরাদ্দ করা হয়। সাধারণত যখন এই ধরনের বড় বরাদ্দ অনুরোধ করা হয়, তখন বরাদ্দকারী ওএস থেকে তাজা পৃষ্ঠাগুলির অনুরোধ করবে। অতএব, একটি উচ্চ সীমাবদ্ধতা একটি পৃষ্ঠার সীমানা থেকে একই অফসেট এ প্রদর্শিত হবে যে একটি উচ্চ সম্ভাবনা আছে।
এখানে পরীক্ষা কোড:
int main(){
const int n = 100000;
#ifdef ALLOCATE_SEPERATE
double *a1 = (double*)malloc(n * sizeof(double));
double *b1 = (double*)malloc(n * sizeof(double));
double *c1 = (double*)malloc(n * sizeof(double));
double *d1 = (double*)malloc(n * sizeof(double));
#else
double *a1 = (double*)malloc(n * sizeof(double) * 4);
double *b1 = a1 + n;
double *c1 = b1 + n;
double *d1 = c1 + n;
#endif
// Zero the data to prevent any chance of denormals.
memset(a1,0,n * sizeof(double));
memset(b1,0,n * sizeof(double));
memset(c1,0,n * sizeof(double));
memset(d1,0,n * sizeof(double));
// Print the addresses
cout << a1 << endl;
cout << b1 << endl;
cout << c1 << endl;
cout << d1 << endl;
clock_t start = clock();
int c = 0;
while (c++ < 10000){
#if ONE_LOOP
for(int j=0;j<n;j++){
a1[j] += b1[j];
c1[j] += d1[j];
}
#else
for(int j=0;j<n;j++){
a1[j] += b1[j];
}
for(int j=0;j<n;j++){
c1[j] += d1[j];
}
#endif
}
clock_t end = clock();
cout << "seconds = " << (double)(end - start) / CLOCKS_PER_SEC << endl;
system("pause");
return 0;
}
বেঞ্চমার্ক ফলাফল:
সম্পাদনা করুন: একটি প্রকৃত কোর 2 আর্কিটেকচার মেশিনের ফলাফল:
২ x ইন্টেল জিয়ন X5482 হারপার্টন @ 3.2 গিগাহার্জঃ
#define ALLOCATE_SEPERATE
#define ONE_LOOP
00600020
006D0020
007A0020
00870020
seconds = 6.206
#define ALLOCATE_SEPERATE
//#define ONE_LOOP
005E0020
006B0020
00780020
00850020
seconds = 2.116
//#define ALLOCATE_SEPERATE
#define ONE_LOOP
00570020
00633520
006F6A20
007B9F20
seconds = 1.894
//#define ALLOCATE_SEPERATE
//#define ONE_LOOP
008C0020
00983520
00A46A20
00B09F20
seconds = 1.993
পর্যবেক্ষণ:
6.206 সেকেন্ডের সাথে এক লুপ এবং দুইটি লুপ সহ 2.116 সেকেন্ড । এটি ঠিক OP এর ফলাফল পুনরুত্পাদন করে।
প্রথম দুটি পরীক্ষায়, অ্যারে আলাদাভাবে বরাদ্দ করা হয়। আপনি তাদের সমস্ত পৃষ্ঠার অনুরূপ একই সারিবদ্ধ আছে লক্ষ্য করবেন।
দ্বিতীয় দুই পরীক্ষায়, অ্যারে যে সারিবদ্ধ বিরতি একসাথে প্যাক করা হয়। এখানে আপনি উভয় loops দ্রুত লক্ষ্য করবেন। উপরন্তু, দ্বিতীয়টি (ডবল) লুপটি এখন ধীর গতির হিসাবে আপনি সাধারণত আশা করবেন।
@ স্টিফেন ক্যানন মন্তব্যগুলিতে উল্লেখ করেছেন যে, এই সীমাবদ্ধতাটি লোড / স্টোর ইউনিট বা ক্যাশে মিথ্যা অ্যালিয়াসিংয়ের কারণ হতে পারে। আমি এই জন্য প্রায় Googled এবং পাওয়া যায় যে ইন্টেল আসলে আংশিক ঠিকানা aliasing স্টল জন্য একটি হার্ডওয়্যার পাল্টা আছে:
5 অঞ্চল - ব্যাখ্যা
অঞ্চল 1:
এই এক সহজ। ডেটাসেটটি এত ছোট যে কর্মক্ষমতা ওভারহেডের মতো লুপিং এবং শাখা দ্বারা প্রভাবিত হয়।
অঞ্চল 2:
এখানে, তথ্য মাপ বৃদ্ধি হিসাবে, আপেক্ষিক ওভারহেড পরিমাণ নিচে যায় এবং কর্মক্ষমতা "saturates"। এখানে দুটি loops ধীর কারণ এটি দ্বিগুণ অনেক লুপ এবং শাখা ওভারহেড আছে।
আমি নিশ্চিত নই যে এখানে কি হচ্ছে ... অ্যালেনার ফগ ক্যাশ ব্যাঙ্কের দ্বন্দ্ব উল্লেখ করে অ্যালাইনমেন্টটি এখনও কার্যকর হতে পারে। (যে লিঙ্কটি স্যান্ডি সেতু সম্পর্কে, তবে ধারণা এখনও কোর 2 তে প্রযোজ্য হওয়া উচিত।)
অঞ্চল 3:
এই সময়ে, তথ্য L1 ক্যাশে আর ফিট হয় না। সুতরাং কর্মক্ষমতা L1 <-> L2 ক্যাশে ব্যান্ডউইথ দ্বারা capped হয়।
অঞ্চল 4:
একক লুপ কর্মক্ষমতা ড্রপ আমরা পর্যবেক্ষণ করা হয়। এবং যেমন উল্লেখ করা হয়েছে, এটি অ্যালাইনমেন্টের কারণে যা (সম্ভবত) প্রসেসর লোড / স্টোর ইউনিটে মিথ্যা অ্যালাইজিং স্টলগুলি ঘটায়।
যাইহোক, মিথ্যা aliasing ঘটতে জন্য, ডেটাসেট মধ্যে একটি বড় যথেষ্ট stride থাকতে হবে। এজন্যই আপনি এই অঞ্চলে 3 দেখতে পাবেন না।
অঞ্চল 5:
এই সময়ে, কিছুই ক্যাশে ফিট করে। সুতরাং আপনি মেমরি ব্যান্ডউইথ দ্বারা আবদ্ধ করছি।
কারণ CPU এ এত ক্যাশে মিস নেই (এটি RAM এর চিপ থেকে আসা অ্যারে ডেটার জন্য অপেক্ষা করতে হবে)। আপনার অ্যারের আকারটি নিয়মিতভাবে সামঞ্জস্য করা আপনার পক্ষে আকর্ষণীয় হবে যাতে আপনি স্তরটি 1 ক্যাশে (L1) এর আকার এবং তারপরে আপনার CPU এর স্তর 2 ক্যাশে (L2) অতিক্রম করতে পারেন এবং আপনার কোডের জন্য সময় নেওয়া হয় অ্যারের মাপ বিরুদ্ধে চালানো। গ্রাফ আপনি আশা চাই মত একটি সোজা লাইন করা উচিত নয়।
ঠিক আছে, সঠিক উত্তরটি অবশ্যই CPU ক্যাশে দিয়ে কিছু করতে হবে। কিন্তু ক্যাশে যুক্তি ব্যবহার করা খুব কঠিন হতে পারে, বিশেষ করে ডেটা ছাড়া।
অনেক উত্তর আছে, যা অনেক আলোচনার দিকে পরিচালিত করেছে, তবে আসুন এটির মুখোমুখি হোন: ক্যাশের সমস্যাগুলি খুব জটিল এবং এক মাত্রিক নয়। তারা তথ্য আকারের উপর ব্যাপকভাবে নির্ভর করে, তাই আমার প্রশ্নটি অন্যায় ছিল: এটি ক্যাশে গ্রাফের একটি খুব আকর্ষণীয় বিন্দুতে পরিণত হয়েছিল।
@ মিস্টিসিয়ালের উত্তরটি অনেক লোককে (আমার সাথে) বিশ্বাস করেছে, সম্ভবত কারণ এটি কেবলমাত্র একমাত্র সত্যের উপর নির্ভর করে বলে মনে হয়েছিল, তবে এটি সত্যের একমাত্র "তথ্য বিন্দু" ছিল।
এজন্যই আমি তার পরীক্ষা (একটানা বনাম পৃথক বরাদ্দের ব্যবহার করে) এবং @ জেমস এর উত্তরের পরামর্শটি একত্রিত করেছি।
নীচের গ্রাফগুলি দেখায় যে, বেশিরভাগ উত্তর এবং বিশেষ করে প্রশ্ন এবং উত্তরগুলির বেশীরভাগ মন্তব্যগুলি সম্পূর্ণ দৃশ্যকল্প এবং পরামিতিগুলির উপর নির্ভর করে সম্পূর্ণরূপে ভুল বা সত্য হিসাবে বিবেচিত হতে পারে।
উল্লেখ্য যে আমার প্রাথমিক প্রশ্ন এন = 100.000 ছিল । এই বিন্দু (দুর্ঘটনা দ্বারা) বিশেষ আচরণ প্রদর্শন করে:
এটি এক এবং দুই লুপ সংস্করণ (প্রায় তিনটি একটি ফ্যাক্টর) মধ্যে সর্বাধিক অসঙ্গতি রয়েছে।
এটি একমাত্র বিন্দু, যেখানে এক-লুপ (অর্থাত্ ক্রমাগত বরাদ্দ সহ) দুটি লুপ সংস্করণকে আঘাত করে। (এই রহস্যময় উত্তর সম্ভব হয়েছে, সব সময়ে।)
প্রাথমিক তথ্য ব্যবহার করে ফলাফল:
আনুমানিক ডেটা ব্যবহার করে ফলাফল (এইটি মাস্টিসিয়াল পরীক্ষিত):
এবং এটি একটি হার্ড-টু-স্পষ্ট ব্যাখ্যা: প্রাথমিক তথ্য, যা একবার বরাদ্দ করা হয় এবং বিভিন্ন ভেক্টর আকারের নিম্নলিখিত পরীক্ষার ক্ষেত্রে পুনরায় ব্যবহার করা হয়:
প্রস্তাব
স্ট্যাক ওভারফ্লো সম্পর্কিত প্রতিটি নিম্ন-স্তরের কর্মক্ষমতা সম্পর্কিত প্রশ্নটি ক্যাশের সম্পূর্ণ পরিসরের জন্য মফ্লপ্স তথ্য সরবরাহের প্রয়োজনীয় হওয়া উচিত! উত্তরগুলি চিন্তা করার জন্য প্রত্যেকের সময় অপচয় এবং বিশেষ করে এই তথ্য ছাড়াই অন্যদের সাথে আলোচনা করুন।
আমি এখানে আলোচনা ফলাফল প্রতিলিপি করতে পারবেন না।
নিম্নোক্ত কোডটি ব্যবহার করে আমার মেশিনে অপর্যাপ্ত 10 শতাংশের মধ্যে দুটো পদ্ধতির দরিদ্র বেঞ্চমার্ক কোড দায়ী কিনা তা আমি জানি না, এবং একটি লুপ সাধারণত দুটি চেয়ে দ্রুততর - যেমন আপনি চান আশা।
অ্যারের মাপ ২ ^ 16 থেকে 2 ^ 24, আটটি লুপ ব্যবহার করে। আমি সোর্স অ্যারেগুলি সূচনা করার জন্য সতর্ক ছিলাম যাতে +=
অ্যাসাইনমেন্টটি FPU কে ডাবল হিসাবে ব্যাখ্যা করা মেমরি আবর্জনা যোগ করার জন্য জিজ্ঞাসা করে না।
আমি বিভিন্ন স্কিমগুলির সাথে প্রায় অভিনয় করেছি, যেমন b[j]
, d[j]
লুপের অভ্যন্তরে InitToZero[j]
এবং += b[j] = 1
এবং += d[j] = 1
, এবং আমি মোটামুটি সামঞ্জস্যপূর্ণ ফলাফল পেয়েছিলাম।
যেমনটি আপনি আশা করতে পারেন, InitToZero[j]
ব্যবহার করে লুপের ভিতরে b
এবং d
আরম্ভ করা, সম্মিলিত পদ্ধতিটিকে একটি সুবিধা দেয়, কারণ এটি a
এবং c
InitToZero[j]
পূর্বে ব্যাক-টু-ব্যাক করে, তবে এখনও 10% এর মধ্যে। চিত্রে যান.
হার্ডওয়্যার জেনারেল ডেল এক্সপিএস 8500 প্রজন্ম 3 কোর i7 @ 3.4 গিগাহার্জ এবং 8 গিগাবাইট মেমরি। 2 ^ 16 থেকে ২ ^ ২4, আটটি লুপ ব্যবহার করে ক্রমবর্ধমান সময় যথাক্রমে 44.987 এবং 40.965 ছিল। ভিসুয়াল সি ++ 2010, সম্পূর্ণরূপে অপ্টিমাইজ করা।
PS: আমি শূন্যে গণনা করার জন্য লুপ পরিবর্তন করেছি, এবং যৌথ পদ্ধতিটি সামান্য দ্রুত ছিল। আমার মাথা scratching। নতুন অ্যারের আকার এবং লুপ গণনা নোট করুন।
// MemBufferMystery.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <cmath>
#include <string>
#include <time.h>
#define dbl double
#define MAX_ARRAY_SZ 262145 //16777216 // AKA (2^24)
#define STEP_SZ 1024 // 65536 // AKA (2^16)
int _tmain(int argc, _TCHAR* argv[]) {
long i, j, ArraySz = 0, LoopKnt = 1024;
time_t start, Cumulative_Combined = 0, Cumulative_Separate = 0;
dbl *a = NULL, *b = NULL, *c = NULL, *d = NULL, *InitToOnes = NULL;
a = (dbl *)calloc( MAX_ARRAY_SZ, sizeof(dbl));
b = (dbl *)calloc( MAX_ARRAY_SZ, sizeof(dbl));
c = (dbl *)calloc( MAX_ARRAY_SZ, sizeof(dbl));
d = (dbl *)calloc( MAX_ARRAY_SZ, sizeof(dbl));
InitToOnes = (dbl *)calloc( MAX_ARRAY_SZ, sizeof(dbl));
// Initialize array to 1.0 second.
for(j = 0; j< MAX_ARRAY_SZ; j++) {
InitToOnes[j] = 1.0;
}
// Increase size of arrays and time
for(ArraySz = STEP_SZ; ArraySz<MAX_ARRAY_SZ; ArraySz += STEP_SZ) {
a = (dbl *)realloc(a, ArraySz * sizeof(dbl));
b = (dbl *)realloc(b, ArraySz * sizeof(dbl));
c = (dbl *)realloc(c, ArraySz * sizeof(dbl));
d = (dbl *)realloc(d, ArraySz * sizeof(dbl));
// Outside the timing loop, initialize
// b and d arrays to 1.0 sec for consistent += performance.
memcpy((void *)b, (void *)InitToOnes, ArraySz * sizeof(dbl));
memcpy((void *)d, (void *)InitToOnes, ArraySz * sizeof(dbl));
start = clock();
for(i = LoopKnt; i; i--) {
for(j = ArraySz; j; j--) {
a[j] += b[j];
c[j] += d[j];
}
}
Cumulative_Combined += (clock()-start);
printf("\n %6i miliseconds for combined array sizes %i and %i loops",
(int)(clock()-start), ArraySz, LoopKnt);
start = clock();
for(i = LoopKnt; i; i--) {
for(j = ArraySz; j; j--) {
a[j] += b[j];
}
for(j = ArraySz; j; j--) {
c[j] += d[j];
}
}
Cumulative_Separate += (clock()-start);
printf("\n %6i miliseconds for separate array sizes %i and %i loops \n",
(int)(clock()-start), ArraySz, LoopKnt);
}
printf("\n Cumulative combined array processing took %10.3f seconds",
(dbl)(Cumulative_Combined/(dbl)CLOCKS_PER_SEC));
printf("\n Cumulative seperate array processing took %10.3f seconds",
(dbl)(Cumulative_Separate/(dbl)CLOCKS_PER_SEC));
getchar();
free(a); free(b); free(c); free(d); free(InitToOnes);
return 0;
}
আমি নিশ্চিত নই যে এমএফএলপিএস একটি প্রাসঙ্গিক মেট্রিক কেন এটি সিদ্ধান্ত নিয়েছে। যদিও ধারণাটি মেমরির অ্যাক্সেসগুলিতে ফোকাস করা ছিল, তাই আমি ভাসমান বিন্দু গণনায়ের সময়টি কমিয়ে দেওয়ার চেষ্টা করেছি। আমি +=
বাকি, +=
কিন্তু আমি নিশ্চিত না কেন।
কোন গণনা ছাড়াই একটি সরাসরি নিয়োগ মেমরি অ্যাক্সেস সময় একটি ক্লিনার পরীক্ষা হবে এবং লুপ গণনা নির্বিশেষে অভিন্ন যে একটি পরীক্ষা তৈরি করবে। হয়তো আমি কথোপকথনে কিছু মিস করেছি, কিন্তু এটি সম্পর্কে দ্বিগুণ চিন্তা মূল্য। যদি প্লাসটি বরাদ্দ থেকে বাদ দেওয়া হয় তবে ক্রমবর্ধমান সময় প্রায় 31 সেকেন্ডে প্রায় সমান।
মূল প্রশ্ন
কেন একটি লুপ দুটি loops তুলনায় এত ধীর?
উপসংহার:
কেস 1 একটি ক্লাসিক ইন্টারপোলেশন সমস্যা যা একটি অকার্যকর হতে পারে। আমিও মনে করি এটি বহু নেতৃস্থানীয় কারিগরি আর্কিটেকচার এবং ডেভেলপারগুলি মাল্টি-থ্রেডেড অ্যাপ্লিকেশনগুলি এবং সমান্তরাল প্রোগ্রামিং করার ক্ষমতা সহ মাল্টি-কোর সিস্টেমগুলি নির্মাণ এবং ডিজাইন করার শেষ কারণগুলির মধ্যে একটি।
হার্ডওয়্যার, ওএস এবং কম্পাইলারগুলি একসঙ্গে RAM, ক্যাশে, পৃষ্ঠা ফাইল ইত্যাদির সাথে জড়িত হিপ বরাদ্দগুলি কীভাবে সম্পন্ন করে তা জড়িত না করেই এই পদ্ধতির থেকে এটিকে দেখছেন। এই অ্যালগরিদমের ভিত্তি যা গণিত আমাদের দুটি ভাল সমাধান যা দেখায়। আমরা একটি উপমা যেখানে একটি ব্যবহার করতে পারেন Boss
বা Summation
একটি উপস্থাপিত করবে For Loop
শ্রমিকদের মধ্যে ভ্রমণ করতে যে A
& B
আমরা সহজেই দেখতে পারেন কেস 2 কমপক্ষে 1 / 2 যদি একটু বেশি যত দ্রুত কেস 1ভ্রমণ এবং শ্রমিকদের মধ্যে সময় নেওয়া প্রয়োজন যে দূরত্ব মধ্যে পার্থক্য কারণে। এই গণিত লাইনগুলি প্রায় আংশিকভাবে এবং যথোপযুক্ত সৃষ্টিকর্তা নির্দেশাবলীর মধ্যে ব্যান মার্ক টাইমস এবং পার্থক্য পরিমাণ উভয় সঙ্গে আপ।
আমি এখন কিভাবে সব এই কাজ নিচে ব্যাখ্যা করতে শুরু করবে।
সমস্যা মূল্যায়ন
ওপি এর কোড:
const int n=100000;
for(int j=0;j<n;j++){
a1[j] += b1[j];
c1[j] += d1[j];
}
এবং
for(int j=0;j<n;j++){
a1[j] += b1[j];
}
for(int j=0;j<n;j++){
c1[j] += d1[j];
}
কনসিডেশন
অপ্রত্যাশিত উত্তরের উত্তরগুলি এবং দরকারী মন্তব্যগুলি সহ ক্যাশের আচরণের প্রতি তারপরে 2 টি রূপের ওপরে ওপরে থাকা মূল প্রশ্ন সম্পর্কে ওপিকে প্রশ্ন করা হচ্ছে; আমি এই পরিস্থিতি এবং সমস্যা সম্পর্কে ভিন্ন দৃষ্টিভঙ্গি গ্রহণ করে এখানে চেষ্টা করতে এবং কিছু করতে চাই।
অভিগমন
দুটি loops এবং ক্যাশে এবং পৃষ্ঠা ফাইলিং সম্পর্কে আলোচনার বিষয়ে বিবেচনা করে আমি ভিন্ন দৃষ্টিকোণ থেকে এটি দেখার জন্য অন্য একটি পদ্ধতি গ্রহণ করতে চাই। ক্যাশে এবং পৃষ্ঠা ফাইলগুলি এবং মেমরি বরাদ্দ করার জন্য মৃত্যুদন্ড কার্যকর করা না এমন একটি, প্রকৃতপক্ষে এই পদ্ধতিটি প্রকৃত হার্ডওয়্যার বা সফ্টওয়্যারকে এমনকি সঙ্কট করে না।
পরিপ্রেক্ষিত
কিছুক্ষণের জন্য কোডটি দেখার পরে এটি কী স্পষ্ট হয়ে উঠেছে এবং এটি কী উৎপন্ন করছে তা বেশ স্পষ্ট হয়ে উঠেছে। এটিকে আলগোরিদিমিক সমস্যাতে ভাঙ্গতে এবং গাণিতিক নোটগুলি ব্যবহারের দৃষ্টিকোণ থেকে এটি দেখার জন্য গণিত সমস্যাগুলির সাথে সাথে অ্যালগরিদমগুলিতে একটি উপমা প্রয়োগ করুন।
আমরা কি জানি
আমরা জানি যে তার লুপ 100,000 বার চালানো হবে। আমরা জানি যে a1
, b1
, c1
&d1
একটি 64-বিট আর্কিটেকচারের পয়েন্টার হয়। 32-বিট মেশিনে C ++ এর মধ্যে সমস্ত পয়েন্টার 4 বাইট এবং 64-বিট মেশিনে 8 বাইটের আকারের হয়, কারণ পয়েন্টারগুলি স্থির দৈর্ঘ্যের। আমরা জানি যে আমাদের 32 টি বাইট রয়েছে যা উভয় ক্ষেত্রেই বরাদ্দ করা হয়। একমাত্র পার্থক্য হল আমরা প্রতিটি বায়নার জন্য 32 বাইট বা 2-8 বাইটের 2 সেট বরাদ্দ করছি যেখানে দ্বিতীয় ক্ষেত্রে আমরা উভয় স্বাধীন loops জন্য প্রতিটি পুনরাবৃত্তি জন্য 16 বাইট বরাদ্দ করা হয়। সুতরাং উভয় loops এখনও মোট বরাদ্দ মধ্যে 32 বাইট সমান। এই তথ্য দিয়ে এগিয়ে যান এবং সাধারণ গণিত, অ্যালগরিদম এবং এর উপমা প্রদর্শন। আমরা উভয় ক্ষেত্রেই একই সেট বা গ্রুপ অপারেশন সঞ্চালন করতে হবে কতবার পরিমাণ জানি। আমরা উভয় ক্ষেত্রে বরাদ্দ করা প্রয়োজন মেমরি পরিমাণ জানি না।আমরা asses যে উভয় ক্ষেত্রে বরাদ্দ সামগ্রিক কাজ লোড প্রায় একই হতে হবে।
আমরা কি জানি না
আমরা যদি কাউন্টার সেট না করে এবং একটি বেঞ্চ চিহ্ন পরীক্ষা চালানো না হওয়া পর্যন্ত প্রতিটি ক্ষেত্রে কতক্ষণ সময় লাগবে তা আমরা জানি না। যাইহোক বেঞ্চ চিহ্নগুলি মূল প্রশ্ন থেকে এবং কিছু উত্তর এবং মন্তব্য থেকেও অন্তর্ভুক্ত করা হয়েছে এবং আমরা উভয়ের মধ্যে একটি উল্লেখযোগ্য পার্থক্য দেখতে পাচ্ছি এবং এই সমস্যাটির এই প্রশ্নের সম্পূর্ণ যুক্তি এবং এটির উত্তর দেওয়ার জন্য দিয়ে শুরু.
এর তদন্ত করা যাক
এটি ইতিমধ্যেই স্পষ্ট যে হিপ বরাদ্দকরণ, বেঞ্চ মার্ক পরীক্ষাগুলি, RAM, ক্যাশে এবং পৃষ্ঠা ফাইলগুলির দিকে তাকিয়ে অনেকেই ইতিমধ্যে এটি করেছেন। নির্দিষ্ট তথ্য বিন্দু এবং নির্দিষ্ট পুনরাবৃত্তি সূচকগুলি সন্ধান করা হয়েছে এবং এই নির্দিষ্ট সমস্যা সম্পর্কে বিভিন্ন কথোপকথনগুলিতে অনেক লোক এটি সম্পর্কিত অন্যান্য সম্পর্কিত বিষয়গুলি নিয়ে প্রশ্ন করতে শুরু করেছে। সুতরাং কিভাবে আমরা গাণিতিক আলগোরিদিম ব্যবহার করে এবং এটি একটি উপমা প্রয়োগ করে এই সমস্যাটি দেখতে শুরু করব? আমরা একটি দম্পতি তৈরীর দ্বারা শুরু বন্ধ! তারপর আমরা সেখানে থেকে আমাদের অ্যালগরিদম নির্মাণ।
আমাদের asstiontions:
- আমরা আমাদের লুপ এবং তার পুনরাবৃত্তিগুলি একটি সমীকরণ হতে শুরু করব যা 1 এ শুরু হবে এবং 0 এর সাথে 100,000 এ শুরু হবে পরিবর্তে 0 টি লুপের মতো যা আমাদের স্মৃতির ঠিকানার 0 সূচী পরিকল্পনা সম্পর্কে চিন্তা করতে হবে না কারণ আমরা আগ্রহী আলগোরিদিম নিজেই।
- উভয় ক্ষেত্রেই আমাদের প্রতিটি ফাংশন কলটিতে 2 টি ক্রিয়াকলাপের সাথে কাজ করার জন্য 4 টি ফাংশন এবং 2 ফাংশন কল রয়েছে। সুতরাং আমরা এই সেট হবে আপ হিসাবে ফাংশন এবং ফাংশন হতে আহ্বান
F1()
,F2()
,f(a)
,f(b)
,f(c)
এবংf(d)
।
আলগোরিদিম:
প্রথম মামলা: - শুধুমাত্র একটি সংক্ষেপে কিন্তু দুটি স্বাধীন ফাংশন কল।
Sum n=1 : [1,100000] = F1(), F2();
F1() = { f(a) = f(a) + f(b); }
F2() = { f(c) = f(c) + f(d); }
দ্বিতীয় কেস: - দুটি সংক্ষেপে কিন্তু প্রতিটি নিজস্ব ফাংশন কল আছে।
Sum1 n=1 : [1,100000] = F1();
F1() = { f(a) = f(a) + f(b); }
Sum2 n=1 : [1,100000] = F1();
F1() = { f(c) = f(c) + f(d); }
যদি আপনি F2()
শুধুমাত্র Sum
উভয় Sum1
এবং Sum2
শুধুমাত্র রয়েছে যেখানে বিদ্যমান F1()
। এটি পরেও স্পষ্ট হবে যখন আমরা এই উপসংহারে শুরু করব যে দ্বিতীয় অ্যালগরিদম থেকে অপ্টিমাইজেশান হচ্ছে।
প্রথম ক্ষেত্রে মাধ্যমে পুনরাবৃত্তি Sum
কল f(a)
যে তার স্ব যোগ করা হবে f(b)
তারপর কল f(c)
এটি একই কাজ কিন্তু f(d)
প্রতিটি জন্য নিজেই যোগ করা হবে 100000 iterations
। দ্বিতীয় ক্ষেত্রে আমাদের আছে Sum1
এবং Sum2
উভয় একই কাজ করে, যেন তারা একই ফাংশনটি সারিতে দুবার ডাকা হয়। এই ক্ষেত্রে আমরা চিকিত্সা করতে পারি Sum1
এবং Sum2
কেবলমাত্র প্লেইন পুরাতন হিসাবে Sum
যেখানে Sum
এই ক্ষেত্রে Sum n=1 : [1,100000] { f(a) = f(a) + f(b); }
এটির মত দেখাচ্ছে : এবং এখন এটি একটি অপ্টিমাইজেশান বলে মনে হচ্ছে যেখানে আমরা এটি একই ফাংশন হিসাবে বিবেচনা করতে পারি।
বিশ্লেষণ সঙ্গে সংক্ষিপ্ত বিবরণ
দ্বিতীয় ক্ষেত্রে আমরা যা দেখেছি তা দেখে প্রায়শই অপ্টিমাইজেশান হিসাবে প্রদর্শিত হয় যেহেতু লুপগুলির জন্য উভয় একই সঠিক স্বাক্ষর রয়েছে, তবে এটি প্রকৃত সমস্যা নয়। ইস্যু কাজ করা হয় যে কাজ করা হচ্ছে না f(a)
, f(b)
, f(c)
& f(d)
উভয় ক্ষেত্রে এবং দুই মধ্যে তুলনা এটা দূরত্ব সমষ্টি উভয় ক্ষেত্রেই যে সময় সম্পাদন পার্থক্য দেয় ভ্রমণ করতে হয়েছে যে পার্থক্য আছে।
চিন্তা করুন For Loops
হচ্ছে Summations
একটি হচ্ছে পুনরাবৃত্তিও করে Boss
দুই জনের যে আদেশ প্রদান করা হয় A
& B
এবং যে তাদের কাজ মাংস হয় C
& D
যথাক্রমে তাদের কাছ থেকে কিছু প্যাকেজ নিতে এবং এটা দেখাবে। এখানে অনুরূপ লুপ বা সংক্ষেপনের পুনরাবৃত্তি এবং অবস্থা চেক নিজেই প্রতিনিধিত্ব করে না Boss
। আসলে কি প্রতিনিধিত্ব করে Boss
এখানে প্রকৃত গাণিতিক আলগোরিদিম সরাসরি থেকে নয়, কিন্তু প্রকৃত ধারণা থেকে Scope
এবং Code Block
একটি রুটিন বা উপ-রুটিন, পদ্ধতি, ফাংশন, অনুবাদ ইউনিট, ইত্যাদি মধ্যে যেখানে 2nd অ্যালগরিদম 2 আছে প্রথম অ্যালগরিদম 1 সুযোগ আছে ধারাবাহিক scopes।
প্রতিটি কলের উপর প্রথম ক্ষেত্রে মধ্যে চিলতা Boss
যায় A
শৃঙ্খলা দেয় এবং A
যায় বন্ধ আনতে B's
তারপর প্যাকেজ Boss
যায় C
এবং আদেশ দেয় একই কাজ থেকে প্যাকেজ গ্রহণ করতে D
প্রতিটি পুনরাবৃত্তির উপর।
দ্বিতীয় ক্ষেত্রেই Boss
সরাসরি প্যাকেজগুলি পেতে A
এবং B's
প্যাকেজগুলি আনতে প্যাকেজগুলি গ্রহণ না করা পর্যন্ত সরাসরি কাজ করে । তারপর সব প্যাকেজ পাওয়ার জন্য একই Boss
কাজ করে।C
D's
যেহেতু আমরা একটি 8 বাইট পয়েন্টারের সাথে কাজ করছি এবং হিপ বরাদ্দের সাথে ডিল করার জন্য এখানে এই সমস্যাটি বিবেচনা করি। আসুন আমরা বলি যে এটি Boss
100 ফুট A
এবং এর A
থেকে 500 ফুট C
। মৃত্যুদন্ডের আদেশের কারণে Boss
প্রাথমিকভাবে এ পর্যন্ত কতটা উদ্বিগ্ন হওয়া দরকার সে বিষয়ে আমাদের চিন্তা করতে হবে না C
। উভয় ক্ষেত্রে Boss
প্রাথমিকভাবে A
প্রথম থেকে তারপর ভ্রমণ B
। এই উপমাটি এই দূরত্ব সঠিক নয় বলে নয়; এটি শুধুমাত্র একটি ব্যবহার পরীক্ষা ক্ষেত্রে দৃশ্যকল্প আলগোরিদিম এর কাজকর্ম দেখাতে। বেশিরভাগ ক্ষেত্রে হিপ বরাদ্দকরণ এবং ক্যাশে এবং পৃষ্ঠা ফাইলগুলির সাথে কাজ করার সময়, ঠিকানা অবস্থানগুলির মধ্যে এই দূরত্বগুলি পার্থক্যগুলির মধ্যে অনেকগুলি পরিবর্তিত হতে পারে না বা তারা ডাটা প্রকার এবং অ্যারের মাপের প্রকৃতির উপর নির্ভর করে খুব উল্লেখযোগ্যভাবে উল্লেখ করতে পারে।
টেস্ট ক্ষেত্রে:
প্রথম মামলা: প্রথম পুনরাবৃত্তিBoss
শুরুতে অর্ডারটি স্লিপ দেওয়ার জন্য প্রথমে 100 ফুট যেতে হবেA
এবংA
তার জিনিসটি শেষ হবে, তবেতার অর্ডার স্লিপ দেওয়ার জন্য তাকেBoss
500 ফুট ভ্রমণ করতেC
হবে। তারপর পরবর্তী পুনরাবৃত্তি এবং প্রতিটি অন্যান্য পুনরাবৃত্তি পরেBoss
দুই মধ্যে 500 ফুট পিছনে যেতে হবেপরে।
দ্বিতীয় ক্ষেত্রে: The Boss
প্রথম পুনরাবৃত্তিতে 100 ফুট ভ্রমণ করতে হবেA
, কিন্তু তারপরে তিনি ইতিমধ্যেই সেখানে আছেন এবংA
সমস্ত স্লিপগুলি পূরণ না হওয়া পর্যন্ত ফিরে যাওয়ারজন্য অপেক্ষা করছেন। তারপর TheBoss
প্রথম পুনরাবৃত্তির উপর 500 ফুট ভ্রমণ করতে হয়েছেC
কারণC
থেকে 500 ফুটA
এই যেহেতুBoss( Summation, For Loop )
অধিকার নিয়ে কাজ পরে বলা হচ্ছেA
এবং তারপর মাত্র অপেক্ষা মত সে করেনিA
যতক্ষণ না সবC's
অর্ডার স্লিপ করা হয়।
দূরত্ব মধ্যে ভ্রমণ পার্থক্য
const n = 100000
distTraveledOfFirst = (100 + 500) + ((n-1)*(500 + 500);
// Simplify
distTraveledOfFirst = 600 + (99999*100);
distTraveledOfFirst = 600 + 9999900;
distTraveledOfFirst = 10000500;
// Distance Traveled On First Algorithm = 10,000,500ft
distTraveledOfSecond = 100 + 500 = 600;
// Distance Traveled On Second Algorithm = 600ft;
নিরপেক্ষ মান তুলনা
আমরা সহজেই দেখতে পারি যে 600 টি 10 মিলিয়নের বেশি কম। এখন এটি সঠিক নয়, কারণ আমরা RAM এর কোন ঠিকানার মধ্যে দূরত্বের প্রকৃত পার্থক্যটি জানি না বা প্রতিটি পুনরাবৃত্তি প্রতিটি কেশে বা পৃষ্ঠা ফাইলের প্রতিটি কলটি অন্যান্য অদৃশ্য ভেরিয়েবলগুলির কারণে হতে চলেছে, তবে এটি ঠিক পরিস্থিতির একটি মূল্যায়ন সচেতন হতে এবং সবচেয়ে খারাপ ক্ষেত্রে দৃশ্যকল্প থেকে এটি দেখার চেষ্টা।
সুতরাং এই সংখ্যার দ্বারা এটি প্রায় এলগরিদম এক অ্যালগরিদম দুই চেয়ে 99% ধীর হওয়া উচিত বলে মনে হবে; যাইহোক, এই মাত্র The Boss's
অংশ বা আলগোরিদিম দায়িত্ব এবং এটা প্রকৃত শ্রমিকদের জন্য অ্যাকাউন্ট নেই A
, B
, C
, & D
এবং তারা কি একে এবং লুপ প্রতিটি পুনরাবৃত্তির উপর করতে হবে। কাজেই মোট চাকরির প্রায় 15 - 40% মালিকের মনিব চাকরির হিসাব রয়েছে। কাজেই শ্রমিকদের মাধ্যমে যে পরিমাণ কাজ করা হয় তার গতির হারের পার্থক্য অনুমান রাখতে প্রায় 50-70%
পর্যবেক্ষণ: - দুটি অ্যালগরিদম মধ্যে পার্থক্য
এই অবস্থায় এটি কাজ সম্পন্ন প্রক্রিয়াটির গঠন এবং এটি দেখায় যে কেস 2টি একই কার্যকরী ঘোষণা এবং সংজ্ঞা থাকার আংশিক অপ্টিমাইজেশান উভয় থেকে আরও কার্যকরী, যেখানে এটি কেবলমাত্র চরিত্রগুলির নাম অনুসারে ভিন্ন । এবং আমরা দেখি যে কেস 1 তে ভ্রমণ করা মোট দূরত্বটি কেস ২ এর চেয়ে অনেক বেশি এবং আমরা এই দূরত্বটি দুইটি অ্যালগরিদমগুলির মধ্যে আমাদের সময় ফ্যাক্টর ভ্রমণ করতে বিবেচনা করতে পারি । কেস 1 এর চেয়ে কেস 1 এর চেয়ে অনেক বেশি কাজ আছে। এই প্রমাণ পাওয়া যায় নিASM
যে উভয় ক্ষেত্রে দেখানো হয়েছে। এমনকি সঙ্গে কি ছিল ইতিমধ্যে এই মামলা সম্পর্কে বলেন, এটি সত্য হিসাব নয় যে এ কেস 1 মনিব উভয়ের জন্য অপেক্ষা করতে হবে A
& C
ফিরে পেতে আগে তিনি ফিরে যেতে পারেন A
পরবর্তী পুনরাবৃত্তিতে আবার এবং এটি doesn সত্য যে যদি 't অ্যাকাউন্ট A
বা B
তারপর একটি অত্যন্ত দীর্ঘ সময় নিচ্ছে উভয় Boss
এবং অন্যান্য শ্রমিক (গুলি) এছাড়াও একটি অলস সময়ে অপেক্ষা করছে। ইন কেস 2 শুধুমাত্র এক হচ্ছে নিষ্ক্রিয় Boss
পর্যন্ত শ্রমিক ফিরে পায়। তাই এই এমনকি আলগোরিদিম একটি প্রভাব আছে।
OPs সংশোধিত প্রশ্ন (গুলি)
সম্পাদন করুন: প্রশ্নটি কোনও প্রাসঙ্গিকতা হিসাবে পরিণত হয়নি, কারণ আচরণগুলি অ্যারেগুলির আকার (এন) এবং CPU ক্যাশে মাপের উপর গুরুতরভাবে নির্ভর করে। তাই যদি আরও আগ্রহ থাকে, তবে আমি প্রশ্নটি পুনরায় লিখি:
আপনি নীচের গ্রাফের পাঁচটি অঞ্চলের দ্বারা চিত্রিত বিভিন্ন ক্যাশে আচরণের দিকে পরিচালিত বিশদগুলিতে কিছু কঠিন অন্তর্দৃষ্টি সরবরাহ করতে পারেন?
CPU গুলি / ক্যাশে আর্কিটেকচারের মধ্যে পার্থক্যগুলি নির্দেশ করতে এটিও আকর্ষণীয় হতে পারে, এই CPU গুলির জন্য একই গ্রাফ সরবরাহ করে।
এই প্রশ্ন সম্পর্কে
যেহেতু আমি সন্দেহ ছাড়াই দেখানো হয়েছে, হার্ডওয়্যার এবং সফ্টওয়্যার জড়িত হওয়ার আগেও একটি অন্তর্নিহিত সমস্যা রয়েছে। এখন মেমরি এবং ক্যাশিংয়ের পরিচালনা পাতার ফাইল সহ, ইত্যাদির মধ্যে যা একত্রিত হয়: The Architecture
{হার্ডওয়্যার, ফার্মওয়্যার, কিছু এমবেডেড ড্রাইভার, কার্নেল এবং এএসএম নির্দেশনা সেট}, The OS
{ফাইল ও মেমরি ম্যানেজমেন্ট সিস্টেম , ড্রাইভারস এবং রেজিস্ট্রি}, The Compiler
{সোর্স কোডের অনুবাদ ইউনিট এবং অপ্টিমাইজেশান} এবং এমনকি Source Code
নিজস্ব স্বতন্ত্র অ্যালগরিদমের সেট (গুলি) সহ; আমরা ইতিমধ্যে দেখতে পারেন একটি বোতলের যে প্রথম অ্যালগরিদম মধ্যে ঘটছে আগে আমরা এমনকি কোনো অবাধ সঙ্গে কোনো মেশিনে এটি প্রয়োগ নেই Architecture
, OS
এবংProgrammable Language
দ্বিতীয় অ্যালগরিদম তুলনায়। অতএব একটি আধুনিক কম্পিউটারের অন্তর্নিহিত জড়িত হওয়ার আগে ইতিমধ্যেই একটি সমস্যা বিদ্যমান ছিল।
শেষ ফলাফল
যাহোক; এটা বলা হয় না যে এই নতুন প্রশ্নগুলি গুরুত্বের কারণ নয় কারণ তারা নিজেদের এবং তারা সব পরে একটি ভূমিকা পালন করে। তারা পদ্ধতি এবং সামগ্রিক কর্মক্ষমতা প্রভাবিত করে এবং এটি তাদের উত্তর (গুলি) বা মন্তব্য (গুলি) দিয়েছেন এমন অনেকের কাছ থেকে বিভিন্ন গ্রাফ এবং মূল্যায়নগুলির সাথে স্পষ্ট। তোমাদের মধ্যে উপমা মনোযোগ দিতে তাহলে Boss
ও দুই শ্রমিক A
ও B
যারা ছিল যান এবং থেকে প্যাকেজ পুনরুদ্ধার করতে C
& D
যথাক্রমে এবং প্রশ্ন দুটি আলগোরিদিম গাণিতিক স্বরলিপি বিবেচনায় আপনি দেখতে পারেন করে এই কম্পিউটারের এমনকি সম্পৃক্ততা ছাড়া Case 2
প্রায় 60% তুলনায় দ্রুততরCase 1
এবং যখন আপনি এই অ্যালগরিদমগুলি সোর্স কোডে প্রয়োগ করার পরে গ্রাফ এবং চার্টগুলি দেখেন, তখন সংজ্ঞায়িত এবং অপ্টিমাইজ করা এবং ওএসের মাধ্যমে প্রদত্ত হার্ডওয়্যারগুলিতে ক্রিয়াকলাপগুলি সম্পাদন করার জন্য আপনি এই অ্যালগরিদমগুলির মধ্যে পার্থক্যগুলির মধ্যে আরও বেশি অবনতি দেখতে পান।
এখন যদি "ডেটা" সেটটি মোটামুটি ছোট তবে প্রথমে এটিতে কোনও পার্থক্যের খারাপ মনে Case 1
হয় না তবে যেহেতু 60 - 70%
ধীরে ধীরে ধীরে ধীরে Case 2
এটি ফাংশনটির বৃদ্ধির দিকে নজর দেয়, যেমন সময় ফাঁসিতে পার্থক্যগুলির পরিপ্রেক্ষিতে:
DeltaTimeDifference approximately = Loop1(time) - Loop2(time)
//where
Loop1(time) = Loop2(time) + (Loop2(time)*[0.6,0.7]) // approximately
// So when we substitute this back into the difference equation we end up with
DeltaTimeDifference approximately = (Loop2(time) + (Loop2(time)*[0.6,0.7])) - Loop2(time)
// And finally we can simplify this to
DeltaTimeDifference approximately = [0.6,0.7]*(Loop2(time)
এবং এই আনুমানিকতা উভয় অ্যালগরিদমিক্যাল এবং সফ্টওয়্যার অপ্টিমাইজেশান এবং মেশিন নির্দেশাবলী জড়িত মেশিন অপারেশন উভয় loops মধ্যে গড় পার্থক্য। সুতরাং তথ্য সেট রৈখিকভাবে বৃদ্ধি পায়, তাই দুই মধ্যে সময় পার্থক্য করে। অ্যালগরিদম 1 অ্যালগরিদম 2 চেয়ে বেশি নিয়ে আসে যা স্পষ্ট হয় যখন হয়েছে Boss
পিছনে মধ্যে বের সর্বাধিক দূরত্ব ভ্রমণ ছিল A
& C
প্রথম পুনরাবৃত্তির পর প্রতি পুনরাবৃত্তির সময় অ্যালগরিদম 2 The Boss
ভ্রমণ করতে ছিল A
করা হচ্ছে সঙ্গে পরে একবার এবং তারপর A
তিনি ভ্রমণ ছিল সর্বাধিক দূরত্ব শুধুমাত্র এক সময় যখন থেকে যাচ্ছে A
করার C
।
তাই Boss
একইভাবে একই রকম দুটি কাজ করার উপর মনোযোগ কেন্দ্রীভূত করার এবং একই ধারাবাহিক কাজের উপর মনোযোগ কেন্দ্রীভূত করার পরিবর্তে তাদের পিছনে জগৎ করার চেষ্টা করা হচ্ছে, কারণ সেটি দিনের শেষে শেষ পর্যন্ত রাগ করে যাচ্ছিল কারণ তাকে ভ্রমণ করতে এবং দ্বিগুণ কাজ করতে হয়েছিল। তাই আপনার বসকে একটি বিযুক্ত বিঘ্ন ঘটাতে পরিস্থিতিটির সুযোগ হারাবেন না কারণ বসের পত্নী এবং সন্তানরা এতে কৃতজ্ঞ হবে না।
প্রথম লুপ প্রতিটি পরিবর্তনশীল লিখুন বিকল্প। দ্বিতীয় এবং তৃতীয় বেশী শুধুমাত্র উপাদান আকার ছোট জাম্প করা।
20 সেমি দ্বারা পৃথক একটি কলম এবং কাগজ সঙ্গে 20 ক্রস দুটি সমান্তরাল লাইন লিখতে চেষ্টা করুন। এক এবং তারপর অন্য লাইন শেষ একবার চেষ্টা করুন এবং একযোগে প্রতিটি লাইন একটি ক্রস writting করে অন্য সময় চেষ্টা করুন।