সীমাটি 959 নয় তবে 960 নয় কেন সাধারণ লুপটি অনুকূলিত হবে?


131

এই সাধারণ লুপটি বিবেচনা করুন:

float f(float x[]) {
  float p = 1.0;
  for (int i = 0; i < 959; i++)
    p += 1;
  return p;
}

যদি আপনি জিসিসি 7 (স্ন্যাপশট) বা ঝনঝন (ট্রাঙ্ক) দিয়ে -march=core-avx2 -Ofastআপনার সাথে সংকলন করেন তবে এর সাথে খুব সামান্য কিছু পান।

.LCPI0_0:
        .long   1148190720              # float 960
f:                                      # @f
        vmovss  xmm0, dword ptr [rip + .LCPI0_0] # xmm0 = mem[0],zero,zero,zero
        ret

অন্য কথায় এটি কেবল লুপ ছাড়াই 960 এর উত্তর নির্ধারণ করে।

তবে আপনি যদি কোডটি পরিবর্তন করেন:

float f(float x[]) {
  float p = 1.0;
  for (int i = 0; i < 960; i++)
    p += 1;
  return p;
}

উত্পাদিত সমাবেশ আসলে লুপ যোগফল সম্পাদন করে? উদাহরণ হিসাবে ঝনঝন দেয়:

.LCPI0_0:
        .long   1065353216              # float 1
.LCPI0_1:
        .long   1086324736              # float 6
f:                                      # @f
        vmovss  xmm0, dword ptr [rip + .LCPI0_0] # xmm0 = mem[0],zero,zero,zero
        vxorps  ymm1, ymm1, ymm1
        mov     eax, 960
        vbroadcastss    ymm2, dword ptr [rip + .LCPI0_1]
        vxorps  ymm3, ymm3, ymm3
        vxorps  ymm4, ymm4, ymm4
.LBB0_1:                                # =>This Inner Loop Header: Depth=1
        vaddps  ymm0, ymm0, ymm2
        vaddps  ymm1, ymm1, ymm2
        vaddps  ymm3, ymm3, ymm2
        vaddps  ymm4, ymm4, ymm2
        add     eax, -192
        jne     .LBB0_1
        vaddps  ymm0, ymm1, ymm0
        vaddps  ymm0, ymm3, ymm0
        vaddps  ymm0, ymm4, ymm0
        vextractf128    xmm1, ymm0, 1
        vaddps  ymm0, ymm0, ymm1
        vpermilpd       xmm1, xmm0, 1   # xmm1 = xmm0[1,0]
        vaddps  ymm0, ymm0, ymm1
        vhaddps ymm0, ymm0, ymm0
        vzeroupper
        ret

এটি কেন এবং কেন এটি ঝনঝন এবং জিসিসির জন্য হুবহু এক?


আপনি যদি প্রতিস্থাপন floatকরেন তবে একই লুপের সীমা double479 g এটি আবার জিসিসি এবং ঝনঝন করার জন্য একই।

আপডেট 1

দেখা যাচ্ছে যে জিসিসি 7 (স্ন্যাপশট) এবং ক্ল্যাং (ট্রাঙ্ক) খুব আলাদা আচরণ করে। ঝাঁকুনি যতটা আমি বলতে পারি 960 এরও কম সীমাবদ্ধতার জন্য লুপগুলি অনুকূল করে izes অন্যদিকে জিসিসি সঠিক মানের সাথে সংবেদনশীল এবং এর উচ্চতর সীমা নেই। উদাহরণস্বরূপ, যখন সীমাটি 200 (পাশাপাশি অনেকগুলি অন্যান্য মান) হয় তখন এটি লুপটি অনুকূলিত করে না তবে সীমাটি 202 এবং 20002 (পাশাপাশি অন্যান্য অনেক মান) হয় তখন তা করে।


3
সুলতানের সম্ভবত এর অর্থ হ'ল 1) সংকলকটি লুপটিকে আনরোল করে এবং 2) একবার এটি অনিয়ন্ত্রিত হয় দেখায় যে যোগফলগুলি একটিকে বিভক্ত করা যেতে পারে। যদি লুপটি নিবন্ধভুক্ত না হয় তবে ক্রিয়াকলাপগুলি গোষ্ঠীভুক্ত করা যাবে না।
জিন-

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

3
@HansPassant এছাড়াও এটা কোন সংখ্যা জন্য অপ্টিমাইজ করা হয় ছোট 959. চেয়ে
eleanora

6
এটি সাধারণত একটি পাগল পরিমাণে তালিকাভুক্ত না করে ইন্ডাকশন ভেরিয়েবল নির্মূলকরণের মাধ্যমে করা হবে? 959 এর একটি ফ্যাক্টর দ্বারা তালিকাভুক্ত হওয়া পাগল।
হেরোলেড

4
@ ইলিয়ানোরা আমি সেই সংকলক এক্সপ্লোরারটির সাথে খেলেছি এবং নিম্নলিখিতগুলি মনে হয় (কেবলমাত্র জিসিসি স্ন্যাপশটের কথা বলছি): লুপের গণনা যদি 4 এবং কমপক্ষে 72 এর একাধিক হয়, তবে লুপটি অনিবন্ধিত না হয় (বা বরং একটি দ্বারা অনিবন্ধিত) 4 এর ফ্যাক্টর); অন্যথায়, পুরো লুপটি একটি ধ্রুবক দ্বারা প্রতিস্থাপিত হয় - লুপের গণনা 2000000001 হলেও - আমার সন্দেহ: অকাল অপটিমাইজেশন (যেমন একটি অকাল "হেই, 4 এর একাধিক, এটি আনলোলিংয়ের জন্য ভাল" যে আরও অপ্টিমাইজেশন বনাম একটিকে অবরুদ্ধ করে আরও পুঙ্খানুপুঙ্খ "যাইহোক এই লুপটির সাথে কী চুক্তি?")
হ্যাগেন ফন ইটজেন

উত্তর:


88

টি এল; ডিআর

ডিফল্টরূপে, বর্তমান স্ন্যাপশট জিসিসি 7 অসামঞ্জস্য আচরণ করে, যখন আগের সংস্করণগুলির কারণে ডিফল্ট সীমা ছিল PARAM_MAX_COMPLETELY_PEEL_TIMES16, এটি কমান্ড-লাইন থেকে ওভাররাইড করা যেতে পারে।

সীমাবদ্ধতার যুক্তিটি হ'ল খুব আক্রমণাত্মক লুপকে তালিকাভুক্তি রোধ করা, এটি একটি দ্বি-তরোয়াল তরোয়াল হতে পারে ।

জিসিসির সংস্করণ <= 6.3.0

জিসিসির জন্য প্রাসঙ্গিক অপ্টিমাইজেশান বিকল্পটি -fpeel-loopsযা পতাকা সহ পরোক্ষভাবে সক্ষম করা হয় -Ofast(জোর দেওয়া আমার):

পিলগুলি লুপ করে যার জন্য পর্যাপ্ত তথ্য রয়েছে যে তারা বেশি রোল দেয় না (প্রোফাইল প্রতিক্রিয়া বা স্থির বিশ্লেষণ থেকে )। এটি সম্পূর্ণ লুপ পিলিংও চালু করে (অর্থাত্ সংক্ষিপ্ত সংখ্যক পুনরাবৃত্তির সাথে লুপগুলি সম্পূর্ণ অপসারণ )।

-O3এবং / অথবা দ্বারা সক্ষম করা হয়েছে -fprofile-use

আরও বিশদ যোগ করে প্রাপ্ত করা যেতে পারে -fdump-tree-cunroll:

$ head test.c.151t.cunroll 

;; Function f (f, funcdef_no=0, decl_uid=1919, cgraph_uid=0, symbol_order=0)

Not peeling: upper bound is known so can unroll completely

বার্তাটি এসেছে /gcc/tree-ssa-loop-ivcanon.c:

if (maxiter >= 0 && maxiter <= npeel)
    {
      if (dump_file)
        fprintf (dump_file, "Not peeling: upper bound is known so can "
         "unroll completely\n");
      return false;
    }

সুতরাং try_peel_loopফাংশন রিটার্ন false

আরও ভার্বোজ আউটপুট এর সাথে পৌঁছে যেতে পারে -fdump-tree-cunroll-details:

Loop 1 iterates 959 times.
Loop 1 iterates at most 959 times.
Not unrolling loop 1 (--param max-completely-peeled-times limit reached).
Not peeling: upper bound is known so can unroll completely

প্লেমগুলি max-completely-peeled-insns=nএবং প্যারামের মাধ্যমে সীমাটি মুছে ফেলা সম্ভব max-completely-peel-times=n:

max-completely-peeled-insns

সম্পূর্ণ ছোলানো লুপের সর্বাধিক সংখ্যক ইনসান।

max-completely-peel-times

সম্পূর্ণ পিলিংয়ের জন্য উপযুক্ত হওয়ার জন্য একটি লুপের সর্বাধিক সংখ্যক পুনরাবৃত্তি।

ইনস সম্পর্কে আরও জানতে, আপনি জিসিসি ইন্টারনালস ম্যানুয়ালটি উল্লেখ করতে পারেন ।

উদাহরণস্বরূপ, যদি আপনি নিম্নলিখিত বিকল্পগুলির সাথে সংকলন করেন:

-march=core-avx2 -Ofast --param max-completely-peeled-insns=1000 --param max-completely-peel-times=1000

তারপরে কোডটি এতে পরিণত হয়:

f:
        vmovss  xmm0, DWORD PTR .LC0[rip]
        ret
.LC0:
        .long   1148207104

ঝনঝন

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

#pragma unroll
for (int i = 0; i < 960; i++)
    p++;

ফলাফলগুলি এতে:

.LCPI0_0:
        .long   1148207104              # float 961
f:                                      # @f
        vmovss  xmm0, dword ptr [rip + .LCPI0_0] # xmm0 = mem[0],zero,zero,zero
        ret

এই খুব সুন্দর উত্তরের জন্য আপনাকে ধন্যবাদ। অন্যরা যেমন উল্লেখ করেছে, জিসিসি সঠিক সীমা আকারের জন্য সংবেদনশীল বলে মনে হচ্ছে। উদাহরণস্বরূপ এটি 912 Godbolt.org/g/EQJHvT এর লুপটি অপসারণ করতে ব্যর্থ । এ ক্ষেত্রে এফডাম্প-ট্রি-কুনরোল-বিশদটি কী বলে?
ইলিয়ানোরা

বাস্তবে 200 জনেরও এই সমস্যা রয়েছে। গডবোল্ট যে সমস্ত সিসিপি 7 এর স্ন্যাপশটে সরবরাহ করে। Godbolt.org/g/Vg3SVs এগুলি ঝাঁকুনির জন্য মোটেই প্রযোজ্য নয়।
ইলানোরা

13
আপনি পিলিংয়ের যান্ত্রিকতাকে ব্যাখ্যা করুন, তবে 960 এর প্রাসঙ্গিকতা কী তা নয় বা কেন একেবারেই সীমা রয়েছে
এমএম

1
@ মিমি: জিসিসি .3.৩.০ এবং সর্বশেষ স্ন্যাপফোস্টের মধ্যে পিলিংয়ের আচরণটি সম্পূর্ণ আলাদা। পূর্বের ক্ষেত্রে, আমি PARAM_MAX_COMPLETELY_PEEL_TIMES/gcc/params.def:321
দৃ strongly়ভাবে

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

19

সুলতানের মন্তব্য পড়ার পরে, আমি অনুমান করি:

  1. লুপের কাউন্টারটি যদি স্থির থাকে (এবং খুব বেশি না হয়) তবে সংকলক সম্পূর্ণরূপে লুপটিকে আনআরোলস করবে

  2. এটি একবার নিবন্ধভুক্ত হয়ে গেলে, সংকলকটি দেখায় যে যোগফলগুলি একটিতে বিভক্ত করা যেতে পারে।

যদি লুপটি কোনও কারণে নিবন্ধভুক্ত না হয় (এখানে: এটি এর সাথে অনেক বেশি বিবৃতি উত্পন্ন করবে 1000), ক্রিয়াকলাপগুলি গোষ্ঠীভুক্ত করা যাবে না।

কম্পাইলার পারে দেখতে যে 1000 বিবৃতিগুলির উদ্ঘাটিত করা একটি একক উপরন্তু পরিমাণ কিন্তু পদক্ষেপ 1 & 2 উপরে বর্ণিত দুটি পৃথক অপ্টিমাইজেশন হয় তাই এটি unrolling, বুদ্ধিমান যদি অপারেশন দলে ভাগ করা যায় (উদাহরণস্বরূপ না "ঝুঁকি" নিতে পারবেন না: একটি ফাংশন কলকে গ্রুপবদ্ধ করা যায় না)।

দ্রষ্টব্য: এটি একটি কোণার কেস: আবার একই জিনিসটি যুক্ত করতে কে একটি লুপ ব্যবহার করে? সেক্ষেত্রে সংকলক সম্ভাব্য তালিকাভুক্তি / অনুকূলিতকরণের উপর নির্ভর করবেন না; সরাসরি একটি নির্দেশে সঠিক অপারেশন লিখুন।


1
তাহলে আপনি কি সেই not too highঅংশটির দিকে মনোনিবেশ করতে পারেন ? মানে ঝুঁকি নেই কেন 100? আমি কিছু অনুমান করেছি ... উপরের আমার মন্তব্যে..তাই এর কারণ হতে পারে?
ব্যবহারকারী2736738

আমি মনে করি যে সংকলকটি ভাসমান পয়েন্টের ত্রুটি যা ট্রিগার করতে পারে সম্পর্কে অবগত নয়। আমার ধারণা এটি কেবল একটি নির্দেশের আকারের সীমা। আপনার max-unrolled-insnsপাশাপাশি রয়েছেmax-unrolled-times
জিন-

আহ এটি আমার চিন্তাভাবনা বা অনুমানের ধরণ ছিল ... আরও সুস্পষ্ট যুক্তি খুঁজে পেতে ইচ্ছুক।
ব্যবহারকারী2736738

5
উত্সাহের ব্যাপার হল যদি আপনি পরিবর্তন floatএকটি থেকে int, জিসিসি কম্পাইলার তার আনয়ন পরিবর্তনশীল অপ্টিমাইজেশন কারণে পুনরাবৃত্তির গণনা নির্বিশেষে লুপ শক্তি-কমাতে, সক্ষম হয় ( -fivopts)। কিন্তু তাদের জন্য কাজ করে না বলে মনে হয় float
তাভিয়ান বার্নেস

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

12

খুব ভাল প্রশ্ন!

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

আপনি পৃথক সংকলক এবং বিকল্পগুলি কোডটি কীভাবে প্রভাবিত করে তা তুলনা করতে আপনি গডবোল্টের সংকলক এক্সপ্লোরার এর সাথে খেলতে পারেন : gcc 6.2এবং icc 17960 এর জন্য কোডটি ইনলাইন করুন, যেখানে clang 3.9না হয় (ডিফল্ট গডবোল্ট কনফিগারেশন সহ, এটি আসলে l৩ এ ইনলাইনিং বন্ধ করে)।


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