একটি পূর্ণসংখ্যার পরিসর দিয়ে আমি কী অপটিমাইজারটি ইঙ্গিত করতে পারি?


173

আমি intএকটি মান সঞ্চয় করতে একটি টাইপ ব্যবহার করছি । প্রোগ্রামটির শব্দার্থবিজ্ঞানের দ্বারা, মানটি সর্বদা খুব কম পরিসরে (0 - 36) পরিবর্তিত হয় এবং int(ক নয় char) কেবলমাত্র সিপিইউ দক্ষতার কারণে ব্যবহৃত হয়।

দেখে মনে হচ্ছে অনেকগুলি সংখ্যার গাণিতিক অপ্টিমাইজেশানগুলি এত ছোট সংখ্যার পূর্ণসংখ্যার উপর সম্পাদন করা যেতে পারে। এই পূর্ণসংখ্যার উপর অনেকগুলি ফাংশন কলগুলি "জাদুকরী" ক্রিয়াকলাপের একটি ছোট সেটে অনুকূলিত হতে পারে এবং কিছু ফাংশন এমনকি টেবিলের চেহারাতেও অনুকূলিত হতে পারে।

সুতরাং, এটি কি কমপাইলারকে বলা সম্ভব যে intএটি সর্বদা সেই ছোট পরিসরে থাকে এবং সংকলকটির পক্ষে সেই অপটিমাইজেশন করা কি সম্ভব?


4
মান পরিসীমা অপ্টিমাইজেশন অনেকগুলি সংকলক উপস্থিত রয়েছে, যেমন exists llvm তবে আমি এটি ঘোষণার জন্য কোনও ভাষার ইঙ্গিত সম্পর্কে সচেতন নই।
রিমাস রুসানু

2
মনে রাখবেন যে আপনার যদি কখনও নেতিবাচক সংখ্যা না থাকে তবে unsignedপ্রকারগুলি ব্যবহারের ক্ষেত্রে আপনার খুব কম লাভ হতে পারে কারণ সেগুলি সংকলকটির সাথে যুক্ত করার পক্ষে সহজ।
ব্যবহারকারী 694733

4
@RemusRusanu: পাসকাল আপনি সংজ্ঞায়িত করতে পারবেন subrange ধরনের , যেমন var value: 0..36;
এডগার বোনেট

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

1
বলতে ভুলে গেছেন: intএবং unsigned intবেশিরভাগ সিস্টেমে -৪-বিট পয়েন্টার সহ সাইন- বা শূন্য-প্রসারিত হওয়া দরকার। মনে রাখবেন যে x86-64- তে, 32-বিট-এ অপারেশনগুলি শূন্য-প্রসারিত 64-বিটকে নিখরচায় নিবন্ধভুক্ত করে (সাইন ইনডেন্ড নয়, তবে স্বাক্ষরিত ওভারফ্লোটি অনির্ধারিত আচরণ, তাই সংকলক চাইলে কেবলমাত্র 64-বিট স্বাক্ষরিত গণিতটি ব্যবহার করতে পারে)। সুতরাং আপনি কেবল শূন্য-প্রসারিত 32-বিট ফাংশন আরগগুলির জন্য অতিরিক্ত নির্দেশাবলী দেখতে পাচ্ছেন, গণনার ফলাফল নয়। আপনি স্বাক্ষরযুক্ত স্বাক্ষরযুক্ত প্রকারের জন্য চাই।
পিটার কর্ডস

উত্তর:


230

হ্যা এটা সম্ভব. উদাহরণস্বরূপ, এর জন্য gccআপনি __builtin_unreachableঅসম্ভব পরিস্থিতি সম্পর্কে সংকলককে বলতে ব্যবহার করতে পারেন:

if (value < 0 || value > 36) __builtin_unreachable();

আমরা উপরের শর্তটি ম্যাক্রোতে গুটিয়ে রাখতে পারি:

#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)

এবং এটি এর মতো ব্যবহার করুন:

assume(x >= 0 && x <= 10);

আপনি দেখতে পাচ্ছেন , gccএই তথ্যের উপর ভিত্তি করে অনুকূলিতকরণ সম্পাদন করে:

#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)

int func(int x){
    assume(x >=0 && x <= 10);

    if (x > 11){
        return 2;
    }
    else{
        return 17;
    }
}

উত্পাদন:

func(int):
    mov     eax, 17
    ret

তবে একটি খারাপ দিক, আপনার কোড যদি কখনও এই ধরনের অনুমানগুলি ভঙ্গ করে তবে আপনি অপরিজ্ঞাত আচরণ পান

এটি যখন ঘটে তখন আপনাকে অবহিত করে না, এমনকি ডিবাগ নির্মাণেও। অনুমান সহ আরও সহজে ডিবাগ / পরীক্ষা / বাগগুলি ধরতে, আপনি এর মতো একটি হাইব্রিড ধরে নেওয়া / জোড় করা ম্যাক্রো (@ ডেভিড জেড এর ক্রেডিট) ব্যবহার করতে পারেন:

#if defined(NDEBUG)
#define assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
#else
#include <cassert>
#define assume(cond) assert(cond)
#endif

ডিবাগ বিল্ডগুলিতে ( সংজ্ঞায়িত NDEBUG না করে ), এটি একটি সাধারণ assert, মুদ্রণ ত্রুটি বার্তা এবং abort'আইএনএন প্রোগ্রামের মতো কাজ করে এবং রিলিজে এটি একটি অনুমানের ব্যবহার করে, অনুকূলিত কোড তৈরি করে code

তবে নোট করুন, এটি নিয়মিত কোনও বিকল্প নয় assert- condরিলিজ বিল্ডে থেকে যায়, তাই আপনার মতো কিছু করা উচিত নয় assume(VeryExpensiveComputation())


5
সংক্ষিপ্তকারক return 2দ্বারা কোড থেকে শাখাটি মুছে ফেলা হিসাবে, উদাহরণস্বরূপ এটি ইতিমধ্যে ঘটছে, আমার উদাহরণস্বরূপ, এটি পেল না ।

6
তবে, মনে হয় যে জিসিসি অপেক্ষাকৃত অপ্রত্যাশিত হিসাবে যাদুকরী ক্রিয়াকলাপগুলি বা টেবিল অনুসন্ধানের ক্ষেত্রে ফাংশনগুলি অনুকূল করতে পারে না
jingyu9575

19
@ ব্যবহারকারী 3528438, __builtin_expectএটি একটি কঠোর ইঙ্গিত। __builtin_expect(e, c)" eসম্ভবত মূল্যায়ন করার সম্ভাবনা সবচেয়ে বেশি " হিসাবে পড়তে cহবে এবং শাখার পূর্বাভাসটি অনুকূল করতে কার্যকর হতে পারে তবে এটি eসর্বদা সীমাবদ্ধ থাকে না c, সুতরাং অপ্টিমাইজারকে অন্যান্য কেস ফেলে দেওয়ার অনুমতি দেয় না। দেখুন শাখাগুলি কীভাবে সমাবেশে সংগঠিত হয়

6
তাত্ত্বিকভাবে যে কোনও কোড যা নিঃশর্তভাবে অনির্ধারিত আচরণের কারণ হয় তার জায়গায় ব্যবহার করা যেতে পারে __builtin_unreachable()
কোডসইনচাওস

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

61

এটির জন্য স্ট্যান্ডার্ড সমর্থন রয়েছে। কি কি করতে হবে অন্তর্ভুক্ত করা হয় stdint.h( cstdint) এবং তারপর টাইপ ব্যবহার uint_fast8_t

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


2
এই ধরণেরগুলি যতটা হওয়া উচিত তার প্রায় ব্যবহার করা হয় না (আমি ব্যক্তিগতভাবে ভুলে যাব যে তারা বিদ্যমান)। তারা কোড দেয় যা উভয়ই দ্রুত এবং বহনযোগ্য, বেশ উজ্জ্বল। এবং তারা 1999 এর কাছাকাছি ছিল
লন্ডিন

এটি সাধারণ ক্ষেত্রে ভাল পরামর্শ sugges ড্যানিসের উত্তর নির্দিষ্ট পরিস্থিতিতে জন্য আরও মারাত্মক সমাধান দেখায়।
bit ই

1
সংকলকটি কেবলমাত্র uint_fast8_tএমন সিস্টেমগুলিতে 0-255 পরিসরের তথ্য পায় যেখানে আসলে 8-বিট টাইপ (যেমন unsigned char) এটি x86 / এআরএম / এমআইপিএস / পিপিসি ( Godbolt.org/g/KNyc31 ) তে থাকে। উপর 21164A আগেই ডিসেম্বর আলফা , বাইট লোড / দোকান, সমর্থিত হয় নি তাই কোনো বিবেকী বাস্তবায়ন ব্যবহার করেন typedef uint32_t uint_fast8_t। আফাইক, বেশিরভাগ সংকলক (জিসিসির মতো) এর সাথে অতিরিক্ত ধরণের সীমাবদ্ধতা রাখার কোনও ব্যবস্থা নেই, তাই আমি দৃ pretty়ভাবে নিশ্চিত যে সে ক্ষেত্রে বা যা কিছু হোক uint_fast8_tঠিক তার মতো আচরণ করবে unsigned int
পিটার কর্ডস

( boolবিশেষ, এবং এটি 0 বা 1 এর মধ্যে সীমাবদ্ধ, তবে এটি একটি অন্তর্নির্মিত প্রকার, charজিডিসি / ক্ল্যাংয়ের ক্ষেত্রে শিরোনাম ফাইল দ্বারা সংজ্ঞায়িত নয় Like যেমনটি আমি বলেছি, আমি মনে করি না যে অধিকাংশ সংকলকগুলির একটি পদ্ধতি আছে) এটি সম্ভব করে তুলবে))
পিটার কর্ডেস

1
যাইহোক, uint_fast8_tএটি একটি ভাল সুপারিশ, যেহেতু এটি প্ল্যাটফর্মগুলিতে একটি 8-বিট প্রকার ব্যবহার করবে যেখানে এটি তত দক্ষ unsigned int। (আমি আসলে নিশ্চিত নই যে fastপ্রকারগুলি কীসের জন্য দ্রুত হওয়া উচিত , এবং ক্যাশে পদচিহ্ন ট্রেডঅফ এর অংশ হওয়ার কথা whether)। মেমোরি উত্সের সাথে বাইট অ্যাড করার জন্য x86 এর বাইট অপারেশনের জন্য বিস্তৃত সমর্থন রয়েছে, তাই আপনাকে পৃথক শূন্য-প্রসারিত লোডও করতে হবে না (যা খুব সস্তা)। জিসিসি uint_fast16_tx86-তে একটি 64-বিট প্রকার তৈরি করে যা বেশিরভাগ ব্যবহারের জন্য উন্মাদ (বনাম 32-বিট)। Godbolt.org/g/Rmq5bv
পিটার কর্ডস

8

বর্তমান উত্তরটি মামলার পক্ষে ভাল যখন আপনি নিশ্চিতভাবে জানতে পারেন যে সীমাটি কী তা তবে আপনি যদি এখনও প্রত্যাশিত সীমা ছাড়িয়ে মান সঠিক আচরণ করতে চান তবে তা কার্যকর হবে না।

সেক্ষেত্রে, আমি এই কৌশলটি কাজ করতে পারে তা পেয়েছি:

if (x == c)  // assume c is a constant
{
    foo(x);
}
else
{
    foo(x);
}

ধারণাটি একটি কোড-ডেটা ট্রেড অফ: আপনি নিয়ন্ত্রণের যুক্তিতে 1 বিট ডেটা (কিনা x == c) সরাচ্ছেন
এটি অপটিমাইজারের প্রতি ইঙ্গিত দেয় যা xপ্রকৃতপক্ষে একটি পরিচিত ধ্রুবক , সম্ভবত একেবারে ভারীভাবে বাকী থেকে আলাদা cকরার প্রথম অনুরোধটিকে ইনलाइन এবং অনুকূলিত করতে উত্সাহিত fooকরে।

কোডটিকে একটি একক সাবরুটিনে আসলে ফ্যাক্টর করে তা নিশ্চিত করুন foo- যদিও কোডটি নকল করবেন না।

উদাহরণ:

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

#include <math.h>
#include <stdio.h>

unsigned foo(unsigned x)
{
    return x * (x + 1);
}

unsigned bar(unsigned x) { return foo(x + 1) + foo(2 * x); }

int main()
{
    unsigned x;
    scanf("%u", &x);
    unsigned r;
    if (x == 1)
    {
        r = bar(bar(x));
    }
    else if (x == 0)
    {
        r = bar(bar(x));
    }
    else
    {
        r = bar(x + 1);
    }
    printf("%#x\n", r);
}

শুধু ব্যবহার -O3এবং প্রাক মূল্যায়ন ধ্রুবক লক্ষ্য 0x20এবং 0x30eপ্রতীকী ভাষান্তর আউটপুট


আপনি চান না if (x==c) foo(c) else foo(x)? কেবল constexprবাস্তবায়ন হলেই হবে foo?
MSalters

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

4

আমি কেবল এই কথাটি বলতে চাইছি যে আপনি যদি এমন কোনও সমাধান চান যা আরও বেশি স্ট্যান্ডার্ড সি ++, আপনি [[noreturn]]নিজের লেখার জন্য বৈশিষ্ট্যটি ব্যবহার করতে পারেন unreachable

সুতরাং আমি প্রত্যাখ্যান করার জন্য দুর্দান্ত উদাহরণটিকে অস্বীকার করব purpose

namespace detail {
    [[noreturn]] void unreachable(){}
}

#define assume(cond) do { if (!(cond)) detail::unreachable(); } while (0)

int func(int x){
    assume(x >=0 && x <= 10);

    if (x > 11){
        return 2;
    }
    else{
        return 17;
    }
}

যা আপনি দেখতে পাচ্ছেন , প্রায় অভিন্ন কোডের ফলাফল:

detail::unreachable():
        rep ret
func(int):
        movl    $17, %eax
        ret

অবক্ষয়টি অবশ্যই, যে আপনি একটি সতর্কতা পেয়েছেন যে কোনও [[noreturn]]ফাংশন আসলেই ফিরে আসে।


এটির সাথে কাজ করে clang, যখন আমার আসল সমাধানটি না হয় , তাই দুর্দান্ত কৌশল এবং +1। তবে পুরো জিনিসটি খুব সংকলক-নির্ভর (যেমন পিটার কর্ডেস আমাদের দেখিয়েছিলেন, iccএতে কার্য সম্পাদন আরও খারাপ হতে পারে ), তাই এটি এখনও সর্বজনীনভাবে প্রযোজ্য নয়। এছাড়াও, ছোট নোট: unreachableসংজ্ঞাটি অপ্টিমাইজারের জন্য উপলব্ধ থাকতে হবে এবং এটি কাজ করার জন্য ইনডিল করা হয়েছে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.