Кіріспе

Компьютерлік бағдарламаны оңтайландыру әдісі Процедурааралық оңтайландыру (IPO) - шағын немесе орташа ұзындықта жиі қолданылатын көптеген функцияларды қамтитын бағдарламалардың өнімділігін жақсарту үшін компьютерлік бағдарламалауда қолданылатын компилятор әдістерінің жиынтығы. IPO басқа компиляторлық оптимизациялардан бір функция немесе код блогына қарама-қарсы тұтас бағдарламаны талдау арқылы ерекшеленеді. IPO қайталанған есептеулерді азайтуға немесе жоюға, жадты тиімсіз пайдалануға және цикл сияқты қайталанатын реттіліктерді оңайлатуға ұмтылады. Егер басқа жүйеге қоңырау орама ішінде пайда болса, IPO-ның талдауы сол жүйеге кіріктірудің ең жақсы екенін анықтауы мүмкін. Сонымен қатар, IPO жадының орналасуы мен жергілікті жерін жақсарту үшін режімдерді қайта тапсыруы мүмкін. IPO сонымен қатар бүкіл бағдарлама деңгейінде қолданылатын типтік компиляторды оңтайландыруды қамтуы мүмкін, мысалы, өлі кодты жою (DCE), бұл ешқашан орындалмаған кодты алып тастайды. IPO тұрақтыларды жақсырақ пайдалануды қамтамасыз етуге тырысады. Қазіргі заманғы компиляторлар компиляция кезінде IPO-ны опция ретінде ұсынады. Нақты IPO процесі адам оқитын бастапқы код пен бітірілген орындалатын екілік бағдарламаны шығару арасындағы кез келген кезеңде болуы мүмкін. Файлдан файлға компиляцияланатын тілдер үшін аударма бірліктері (модульдік файлдар) бойынша тиімді IPO бағдарламаның "кіріс нүктелерін" білуді талап етеді, осылайша бүкіл бағдарламаны оңтайландыру (WPO) орындалуы мүмкін. Көп жағдайда бұл сілтеме уақытын оңтайландыру (LTO) өтуі ретінде жүзеге асырылады, өйткені бүкіл бағдарлама сілтеме берушіге көрінеді.

Талдау

Кез келген жылдамдықты оңтайландырудың мақсаты - бағдарламаны мүмкіндігінше тез орындау; мәселе компилятордың бағдарламаны дұрыс талдап, оның не істейтінін анықтау мүмкін емес, одан да аз, бағдарламашының оны не істеуге ниеттенгенін анықтау. Керісінше, адам бағдарламалаушылар екінші жағынан мақсатпен бастайды және оған жету үшін бағдарлама жасауға тырысады, әсіресе бұл процесте көп ойланбастан. Әр түрлі себептермен, соның ішінде оқуға ыңғайлылық үшін, бағдарламалар бірнеше жалпы жағдайларды қарастыратын бірқатар процедураларға жиі бөлінеді. Алайда, әрбір процедураның жалпылығы белгілі бір пайдалануда текке жұмсалған күш-жігерге әкелуі мүмкін. Процедурааралық оңтайландыру осы ысырапты азайтудың әрекеті болып табылады. F ((x) -ді бағалайтын процедура бар деп болжайық, және F таза функция, және код F ((6) -ның нәтижесін сұрайды, содан кейін F ((6) -ды қайталайды. Бұл екінші бағалау қажет емес: нәтиже сақталып, кейінге қалдырылуы мүмкін еді. Бұл қарапайым оңтайландыру F ((x) іске асырылуы таза емес болған кезде бұзылады; яғни оның орындалуы шақырулар арасында өзгертілген 6 аргументінен басқа параметрлерге сілтемелерді немесе кейбір хабарламаларды журналда басып шығару, бағалау санын есептеу, CPU уақытын жинақтау, ішкі кестелерді дайындау, осылайша байланысты параметрлерді кейінгі шақырулар жеңілдетіледі және т.б. Бұл жанама әсерлерді екінші рет бағалаудан бас тарту мүмкін, немесе олар мүмкін емес. Жалпы алғанда, оңтайландырудан басқа, процедураларды қолданудың екінші себебі - әр рәсім орындалған сайын бірдей немесе бірдей нәтиже беретін кодты қайталаудан аулақ болу. Оптимизацияның жалпы әдісі осыны кері қайтару болып табылады: белгілі бір процедураның кейбір немесе барлық шақырулары тиісті кодпен ауыстырылады, параметрлер тиісті түрде ауыстырылады. Компилятор нәтижелерді оңтайландыруға тырысады.

WPO және LTO

Бүкіл бағдарламаны оңтайландыру (WPO) - бағдарламаның барлық модульдері туралы ақпаратты пайдалана отырып, бағдарламаның компиляторды оңтайландыру. Әдетте, оптимизациялар модульге, "компиляцияға" негізде жүргізіледі; бірақ бұл тәсіл, құрастыру кезінде ресурстарды жазу мен сынау оңай және аз талап етілетін болса да, агрессивті инлайнинг сияқты бірқатар оптимизацияның қауіпсіздігі туралы сенімділікке жол бермейді және сондықтан оларды орындай алмайды, тіпті егер олар шынымен шығарылған объектінің семантикасын өзгертпейтін тиімділік пайдасы болып табылса да. Байланыс уақытын оңтайландыру (LTO) - бағдарламаны оңтайландырудың бір түрі, оны компилятор бағдарламаға байланысты уақыт кезінде орындайды. Байланыс уақытын оңтайландыру бағдарламалау тілдерінде маңызды, олар бағдарламаларды файл бойынша файл негізінде құрастырады, содан кейін сол файлдарды бірден емес (Java-ның жай уақыт құрастыруы (JIT)) біріктіреді (мысалы, C және Fortran). Барлық файлдар жеке нысан файлдарына компиляцияланғаннан кейін, дәстүрлі түрде компилятор нысан файлдарын бір файлға, орындау файлына байланыстырады (қосады). Алайда, GNU Compiler Collection (GCC) және LLVM іске асырған LTO-да компилятор өзінің аралық бейнелеуін (IR), яғни GIMPLE байт кодын немесе LLVM бит кодын, тиісінше, құйып тастай алады, сондықтан бір орындалатын файлды құрайтын барлық әр түрлі компиляциялық бірліктер, содан кейін, бір модуль ретінде оңтайландырылуы мүмкін. Бұл интерпроцедурлық оптимизацияның аясын бүкіл бағдарламаны қамтуға кеңейтеді (немесе, керісінше, сілтеме уақытында көрінетін барлық нәрсе). Байланыс уақытын оңтайландыру арқылы компилятор бүкіл бағдарламаға интерпроцедурлық оңтайландырудың әр түрлі түрлерін қолдана алады, бұл тереңірек талдау, көбірек оңтайландыру және ақыр соңында бағдарламаның өнімділігін жақсартуға мүмкіндік береді. Іс жүзінде LTO әрқашан бүкіл бағдарламаны оңтайландырмайды. Кітапхана функциялары, әсіресе динамикалық байланысты ортақ объектілер, шамадан тыс қайталануды болдырмау және жаңартуға мүмкіндік беру үшін әдейі сақталады. Статикалық сілтемелер LTO тұжырымдамасына табиғи түрде көмектеседі, бірақ ол тек машиналық кодты ғана объекті файлдарына қарағанда, IR объектілерін қамтитын кітапхана архивтерімен жұмыс істейді. Әрине, бағдарламаның өзі кітапхана болған кезде, оңтайландыру DCE-нің бір бөлігі ретінде оларды алып тастауға тырыспай, барлық сыртқы қол жетімді (экспортталған) символдарды сақтайды.

Жалпы алғанда

Бұл мысал өте қарапайым, бірақ күрделіліктері бар. Бұл көбінесе көптеген процедуралардың жағдайы болады, әр түрлі шегерімге немесе бағдарламалық қамтамасыз етуші мәлімделген қасиеттерге ие, бұл компилятордың оңтайландыруларына кейбір артықшылықтарды табуға мүмкіндік береді. Процедураның кез келген параметрін тек оқу, жазу, оқу және жазу немесе мүлдем елемеу мүмкін, бұл уақытша айнымалылар арқылы қорғауға мұқтаж емес тұрақтылар сияқты мүмкіндіктерге әкеледі, бірақ кез-келген шақыруда не болатыны күрделі қарастыруларға байланысты болуы мүмкін. Басқа процедуралар, әсіресе функция тәрізді процедуралар белгілі бір мінез-құлыққа ие болады, олар белгілі бір шақыруларда кейбір жұмыстан аулақ болуға мүмкіндік береді: мысалы, Гамма функциясы, егер бүтін сан параметрімен шақырылса, бүтін сандық факторларды қамтитын есептеуге айналдырылуы мүмкін. Кейбір компьютерлік тілдер параметрлерді пайдалану туралы мәлімдемелер жасауға мүмкіндік береді (немесе тіпті қажет етеді) және айнымалылардың мәндері белгілі бір жиынтыққа (мысалы, 6 < x ≤ 28) шектеледі деп жариялау мүмкіндігін ұсынады, осылайша оңтайландыру процесін өңдеу үшін қосымша шөпті қамтамасыз етеді, сондай-ақ қателерді анықтау үшін бастапқы кодтың үйлесімділігін тексеруді қамтамасыз етеді. Бірақ бұл ешқашан жеткіліксіз, кейбір айнымалыларға қарапайым шектеулер берілуі мүмкін, ал басқаларына күрделі ерекшеліктер қажет: P айнымалысы алғашқы сан болуы керек деп қалай нақтылауға болады және егер солай болса, 1 мәні қосылған ба, жоқ па? Орындаудың күрделілігі: М - ай саны болғандықтан, D айдың күні үшін жарамды диапазондар қандай? Барлық бұзушылықтар бірден тоқтатылуға лайық па? Тіпті осының бәрін де жүзеге асырсақ, қандай пайда болар еді? Ал қандай бағамен? Толық спецификациялар бағдарламаның функциясын басқа формада қайталайтын болады және оларды өңдеуге жұмсалатын уақыттың үстіне, олар қателерге ұшырайды. Оның орнына, тек қана қарапайым ерекшеліктерге рұқсат етіледі, олармен бірге орындалу уақытының аралығын тексеру ұсынылады. Бағдарламаның ешқандай кірісті оқымайтын жағдайларында (мысалы, мысалдағыдай) компилятордың талдауын алға жылжыта отырып, нәтиже басып шығару нұсқауларының сериясынан артық болмайды немесе мүмкін осындай мәндерді тиімді түрде шығаратын кейбір циклдер болуы мүмкін. Ол пропорционалды сандарды құрайтын бағдарламаны таниды ма, оны ең танымал әдіске айналдырады ма, әлде кітапханаға сілтеме жасайды ма? Мүмкін емес! Жалпы, бұған жол бермеу үшін кездейсоқ күрделі қарарлар туындайды (Entscheidungsproblem), және кодты шектеулі жақсартулармен орындаудан басқа амал жоқ.

Тарих

ALGOL сияқты процедуралық тілдер үшін интерпроцедуралық талдау мен оптимизация 1970-жылдардың басында коммерциялық тәжірибеге енген көрінеді. IBM-дің PL/I Optimizing Compiler интерпроцедуралық талдауды процедура шақыруларының және ерекшеліктерінің (PL/I терминдерінде "шарт бойынша") және Фрэн Алленнің мақалаларында жанама әсерлерін түсіну үшін жүргізді. APL бағдарламалау тілін құрастыру жұмыстары міндетті түрде процедурааралық болды. Процедурааралық талдау және оңтайландыру әдістері 1980 және 1990-шы жылдары академиялық зерттеулердің тақырыбы болды. Олар коммерциялық компиляторлар әлемінде 1990 жылдардың басында Convex Computer Corporation ("Convex C4 үшін" Қолданба компиляторы ") және Ardent ("Ardent Titan" компиляторы) компиляторларымен пайда болды. Бұл компиляторлар коммерциялық компиляторда қабылдауға болатын технологияларды жеткілікті жылдам жасай алатындығын көрсетті; кейіннен интерпроцедуралық әдістер бірқатар коммерциялық және коммерциялық емес жүйелерде пайда болды.

Unix- тәрізді

GNU компиляторлар жинағында барлық оңтайландыру деңгейлерінде функциялар бар. Бұл тек бір рет шақырылғандарға ғана қолданылады, бұл шектеу жеңілдетіледі Әдетте бұл тек бір файлдың әрекеті, бірақ сілтеме уақытын оңтайландыру арқылы ол бүкіл бағдарламаға айналады. LTO-да шығарылған объект файлдарында сілтеме кезінде түсіндірілетін компиляторға тән аралық бейнелеу (IR) бар. Бұл статикалық кітапханалармен жақсы жұмыс істейтінін қамтамасыз ету үшін, жаңа GNU линкерлері "линкер плагині" интерфейсіне ие, ол компиляторға қажет болған кезде объект файлдарын машиналық код түріне айналдыруға мүмкіндік береді. Бұл плагин жалпы LTO процесін жүргізуге көмектеседі. "Жиіл LTO" объектісі машина коды мен IR-ді қамтитын болуы мүмкін, бірақ бұл көбірек орын алады. бірақ LLVM оны Rust және басқа LLVM негізделген компиляторларға да мүмкін етеді.

LTO емес опциялар

GCC және Clang IPO-ны әдетте 2-ші деңгейде жүзеге асырады. Алайда, LTO-ны өшіргенде оптималдендіру дәрежесі шектеулі болады, өйткені IPO тек объект файлында ғана болуы мүмкін және статикалық емес функцияларды ешқашан жоюға болмайды. Соңғы мәселенің LTO емес шешімі бар: коммутатор тек статикалық емес, яғни сырттан көрінетін деп болжауға болады. LTO емес тағы бір әдіс - "функционалдық бөлімдер" (GCC және Clang тілдерінде). Әрбір функцияны объект файлдың өз бөлімдеріне орналастыру арқылы, сілтемесіз бөлімдерді алып тастау арқылы (сілтеме жасау опциясын пайдалану арқылы) IR-сіз өлі кодты жоюды орындай алады. Осыған ұқсас нұсқа өзгергіштер үшін бар, бірақ ол нашар кодты шығарады.

Басқа

Intel C/C++ компиляторлары бүкіл бағдарламаның IPO-сына мүмкіндік береді. Бір файл үшін процедурааралық оңтайландыруды іске қосу үшін жалауша - , бағдарламадағы барлық файлдар бойынша процедурааралық оңтайландыруды іске қосу үшін жалауша - Visual Studio-ға интеграцияланған MSVC компиляторы, сонымен қатар бүкіл бағдарламада процедурааралық оңтайландыруды қолдайды. Бүкіл бағдарламаның процедурааралық оңтайландыруын іске асыру үшін компилятордан тәуелсіз интерфейс CMake қасиет арқылы жасалады.