Кіріспе
Деректерді өңдеу тізбегі – есептеу техникасында, деректер тізбегі деп те аталатын, бір элементтің шығысы келесі элементтің кірісі болатын, қатарластырылған деректерді өңдеу элементтерінің жиынтығы. Тізбектің элементтері көбінесе параллель немесе уақыт бөлігімен орындалады. Элементтер арасында белгілі бір көлемде буферлік жад жиі орналастырылады. Компьютерге қатысты тізбектерге мыналар жатады: орталық процессорларда (CPU) және басқа микропроцессорларда бір схемамен бірнеше нұсқауларды бірінен соң бірін орындауға мүмкіндік беретін, классикалық RISC тізбегі сияқты нұсқау тізбегі. Схемалар әдетте кезеңдерге бөлінеді, әр кезең бір уақытта бір нұсқаудың белгілі бір бөлігін өңдеп, жартылай нәтижелерді келесі кезеңге жібереді. Кезеңдердің мысалдары – нұсқауларды декодтау, арифметикалық/логикалық операциялар және тіркеліштерді алу. Олар суперскалярлық орындау, операндтарды жіберу, болжамдық орындау және реттіліксіз орындау технологияларымен байланысты. Көптеген графикалық процессорларда (GPU) кездесетін графикалық тізбектер, бірнеше арифметикалық блоктардан немесе толыққанды CPU-лардан тұрады, олар әртүрлі рендеринг кезеңдерін іске асырады (перспективалық проекция, терезелерді қию, түс және жарық есептеу, рендеринг және т.б.). Бағдарламалық тізбектер – есептеу процестерінің тізбегінен (командалар, бағдарламаны іске қосу, тапсырмалар, жіптер, процедуралар және т.б.) тұрады, тұжырымдамалық тұрғыдан параллель орындалады, бір процестің шығыс ағыны келесі процестің кіріс ағыны ретінде автоматты түрде беріледі. Unix жүйелік шақыруы pipe осы тұжырымдаманың классикалық мысалы болып табылады. HTTP тізбегі – бір TCP қосылымы арқылы бірнеше HTTP сұраныстарын беру әдісі, алдыңғы сұраныстың аяқталуын күтпей жаңа сұраныс жіберу. Кейбір операциялық жүйелер бірнеше бағдарламаны тізбектей орындау үшін UNIX сияқты синтаксис ұсына алады, бірақ соңғысын нақты тізбектей орындаудың орнына қарапайым сериялық орындау ретінде іске асырады, яғни келесі бағдарламаны бастамас бұрын әр бағдарламаның аяқталуын күтеді.
In computing, a pipeline, also known as a data pipeline, is a set of data processing elements connected in series, where the output of one element is the input of the next one. The elements of a pipeline are often executed in parallel or in time sliced fashion. Some amount of buffer storage is often inserted between elements. Computer related pipelines include:
Instruction pipelines, such as the classic RISC pipeline, which are used in central processing units (CPUs) and other microprocessors to allow overlapping execution of multiple instructions with the same circuitry. The circuitry is usually divided up into stages and each stage processes a specific part of one instruction at a time, passing the partial results to the next stage. Examples of stages are instruction decode, arithmetic/logic and register fetch. They are related to the technologies of superscalar execution, operand forwarding, speculative execution and out of order execution. Graphics pipelines, found in most graphics processing units (GPUs), which consist of multiple arithmetic units, or complete CPUs, that implement the various stages of common rendering operations (perspective projection, window clipping, color and light calculation, rendering, etc.). Software pipelines, which consist of a sequence of computing processes (commands, program runs, tasks, threads, procedures, etc. ), conceptually executed in parallel, with the output stream of one process being automatically fed as the input stream of the next one. The Unix system call pipe is a classic example of this concept. HTTP pipelining, the technique of issuing multiple HTTP requests through the same TCP connection, without waiting for the previous one to finish before issuing a new one. Some operating systems may provide UNIX like syntax to string several program runs in a pipeline, but implement the latter as simple serial execution, rather than true pipelining—namely, by waiting for each program to finish before starting the next one.
Тұжырымдама және мотивация
Құбырландыру – күнделікті өмірде жиі кездесетін ұғым. Мысалы, автомобиль зауытының құрастыру желісінде әрбір нақты тапсырма – қозғалтқышты орнату, капотты орнату және дөңгелектерді орнату сияқты – көбінесе жеке жұмыс станциясымен орындалады. Станциялар өз тапсырмаларын параллель түрде, әрқайсысы әртүрлі машинада орындайды. Бір машина бір тапсырмадан өткеннен кейін келесі станцияға жылжып өтеді. Тапсырмаларды орындауға қажетті уақыттың айырмашылығы "буферлеу" (станциялар арасында бір немесе бірнеше машинаны сақтап тұру) және/немесе "тоқтату" (келесі станция бос болғанға дейін алдыңғы станцияларды уақытша тоқтату) арқылы өтеуге болады. Егер бір машинаны құрастыру үшін үш тапсырма қажет болса, олар 20, 10 және 15 минутты алады делік. Егер үш тапсырманы да бір станция орындаса, зауыт әр 45 минут сайын бір машина шығарады. Бірақ үш станциядан тұратын құбырландыру желісін пайдаланса, зауыт 45 минутта бірінші машинаны шығарып, содан кейін әр 20 минут сайын жаңа машина шығарады. Осы мысал көрсеткендей, құбырландыру жалғастыру уақытын (бір элементтің жүйе арқылы өтуіне кеткен жалпы уақыт) қысқарта алмайды. Дегенмен, ол жүйенің өнімділігін арттырады, яғни бірінші элементтен кейін жаңа элементтерді өңдеу жылдамдығын арттырады.
Кезеңдерді теңестіру
Құбырдың өнімділігі ең баяу бөлігінен жақсы болмайтындықтан, жобалаушы жұмыс пен ресурстарды кезеңдерге тең бөлуге тырысуы керек, осылайша әр кезең өз міндетін орындауға бірдей уақыт жұмсайды. Жоғарыдағы автомобиль құрастыру мысалында, егер үш жұмыс 15 минуттан алса, 20, 10 және 15 минут емес, онда жалпы уақыт 45 минутты құрайды, бірақ жаңа автомобиль әр 15 минут сайын, 20 минут емес, дайын болады.
Буферлеу
Идеал жағдайда, егер барлық өңдеу элементтері синхронды жұмыс істесе және өңдеуге бірдей уақыт кетсе, онда әрбір элемент алдыңғысы шығарғандай бір сағат циклында қабылданады. Осылайша, элементтер құбыр арқылы тұрақты жылдамдықпен ағып өтеді, су арнасындағы толқындар сияқты. Мұндай «толқын құбырларында» деректерді сақтаудан басқа, кезеңдер арасында синхрондау немесе буферлеу қажет емес. Жалпы алғанда, құбыржол кезеңдері арасында буферлеу өңдеу уақыты тұрақсыз болғанда немесе құбыржол бойында элементтер жасалғанда немесе жойылғанда қажет болады. Мысалы, экранға көрсетілетін үшбұрыштарды өңдейтін графикалық құбыржолда, әрбір үшбұрыштың көрінуін тексерген элемент, егер ол көрінбесе, үшбұрышты жоюы мүмкін, немесе егер олар жартылай жасырылған болса, элементтің екі немесе одан көп үшбұрышты бөліктерін шығаруы мүмкін. Буферлеу сонымен қатар, бірінші сатыға элементтерді беру және соңғы сатының нәтижесін алу жылдамдықтарындағы айырмашылықтарды өтеу үшін де қажет. Екі саты арасындағы буфер – екі саты арасында тиісті синхрондау және сигнал беру логикасы бар қарапайым аппараттық тізілім болуы мүмкін. А сатысы деректерді тізілімге сақтағанда, ол келесі В сатысына «деректер қол жетімді» сигналын жібереді. В осы деректерді пайдаланғаннан кейін, ол А сатысына «деректер алынды» сигналын жібереді. А сатысы тоқтап, келесі дерек элементін тізілімге сақтау алдында осы сигналды күтеді. В сатысы «деректер қол жетімді» сигналын күтеді, егер ол келесі элементті өңдеуге дайын болса, бірақ А сатысы оны әлі бермеген болса. Егер элементтің өңдеу уақыты өзгеріп тұрса, бүкіл құбыржол сол элементтің және одан бұрынғы барлық элементтердің кіріс буферлеріндегі элементтерді өңдеуді күтіп, тоқтауы мүмкін. Мұндай құбыржол тоқталу жиілігін осы кезеңнің кіріс буферінде бірден көп элементке орын беріп азайтуға болады. Мұндай көп элементтік буфер әдетте бірінші кірген, бірінші шыққан кезек ретінде іске асырылады. Алдыңғы саты кезек толғанда тоқтауы мүмкін, бірақ көбірек буферлік орындар берілгенде осы оқиғалардың жиілігі азаяды. Кезек теориясы өңдеу уақытының өзгеруіне және қажетті өнімділікке байланысты қажетті буферлік орындардың санын анықтай алады.
Сызықтық емес құбырлар
Егер кейбір кезең басқаларына қарағанда әлдеқайда ұзаққа созылса (немесе созылуы мүмкін) және оны жылдамдату мүмкін болмаса, дизайнер сол міндетті параллель түрде орындау үшін екі немесе одан көп өңдеу элементтерін, жалғыз кіріс буферімен және жалғыз шығыс буферімен жабдықтауы мүмкін. Әрбір элемент ағымдағы дерек элементін өңдеуді аяқтаған соң, оны ортақ шығыс буферіне жібереді және ортақ кіріс буферінен келесі дерек элементін алады. Бұл "сызықтық емес" немесе "динамикалық" құбыр желісінің концепциясы, мысалы, бір кезекте тұрған клиенттерге екі немесе одан көп кассир қызмет көрсететін дүкендерде немесе банктерде көрініс табады.
Элементтер арасындағы байланыстылық
Кейбір қолданбаларда Y элементін А сатысымен өңдеу, алдыңғы X элементін құбырдың кейінірек B сатысымен өңдеудің нәтижесіне немесе әсеріне байланысты болуы мүмкін. Бұл жағдайда А сатысы Y элементін X элементі B сатысын асып өткенге дейін дұрыс өңдей алмайды. Мұндай жағдай нұсқаулық құбыржолдарда жиі кездеседі. Мысалы, Y арифметикалық нұсқаулық болсын, ол бұрынғы X нұсқаулықпен өзгертілген деп есептелетін регистрдің мазмұнын оқиды. A нұсқаулық операндаларын алатын, ал B нұсқаулықты көрсетілген регистрге жазатын саты болсын. Егер A сатысы Y нұсқауын X нұсқауы B сатысына жетпей өңдеуге тырысса, онда регистрде әлі де ескі мән болуы мүмкін және Y нұсқаулығының нәтижесі дұрыс болмайды. Мұндай қақтығыстарды дұрыс басқару үшін құбыр желісі оларды анықтап, тиісті әрекеттерді жасайтын қосымша схемамен немесе логикамен жабдықталуы керек. Мұны істеудің стратегиялары: Тоқтату: Әсер еткен барлық сатылар, мысалы, А, тәуелділік шешілгенге дейін тоқтатылады, яғни қажетті ақпарат қол жетімді болғанға дейін және/немесе қажетті күйге қол жеткізілгенге дейін. Элементтерді қайта реттеу: А сатысы Y элементін тоқтатудың орнына, кіріс ағынындағы кез келген кейінгі Z элементін іздеуге болады, ол бұрынғы элементтермен күтуде емес. Нұсқаулық құбыржолдарында бұл техника реттіліксіз орындау деп аталады. Болжау және кері қайту: Элементтен-элементке тәуелділіктің маңызды мысалы – нұсқаулық құбыры арқылы шартты тармақталу нұсқаулығы X-ті өңдеу. Құбырдың бірінші сатысы А, пайдалануға тиісті келесі Y нұсқауын алады, ол X өзінің операндын алып, тармақталу орындалатын болады ма, жоқ па, анықтағанға дейін өз міндетін орындай алмайды. Бұл көптеген сағат циклдарын қажет етуі мүмкін, себебі X операнды, өз кезегінде, негізгі жадтан деректерді алатын алдыңғы нұсқауларға байланысты болуы мүмкін. X аяқталуын күтіп тоқтатудың орнына, А сатысы тармақталу орындалатын болады ма, жоқ па, деп болжап, келесі Y нұсқауын алуға болады. Егер кейіннен болжау дұрыс емес болып шықса (мұндай жағдай сирек болатынын үміттенеміз), жүйе кері қайтып, дұрыс таңдауды қайта бастауы керек. Яғни, машинаның күйіне А сатысы мен одан кейінгі сатыстарда жасалған барлық өзгерістер осы болжамға негізделген, X-тен кейінгі нұсқаулар құбырдан шығарылып тасталуы керек, ал А сатысы дұрыс нұсқаулық мекенжайымен қайта іске қосылуы керек. Бұл тармақ болжау стратегиясы – спекулятивті орындаудың ерекше жағдайы.
Stalling: Every affected stage, such as A, is halted until the dependency is resolved—that is, until the required information is available and/or the required state has been achieved. Reordering items: Instead of stalling, stage A may put item Y aside and look for any subsequent item Z in its input stream that does not have any dependencies pending with any earlier item. In instruction pipelines, this technique is called out of order execution. Guess and backtrack: One important example of item to item dependency is the handling of a conditional branch instruction X by an instruction pipeline. The first stage A of the pipeline, that fetches the next instruction Y to be executed, cannot perform its task until X has fetched its operand and determined whether the branch is to be taken or not. That may take many clock cycles, since the operand of X may in turn depend on previous instructions that fetch data from main memory. Rather than halt while waiting for X to be finished, stage A may guess whether the branch will be taken or not, and fetch the next instruction Y based on that guess. If the guess later turns out to be incorrect (hopefully rarely), the system would have to backtrack and resume with the correct choice. Namely, all the changes that were made to the machine's state by stage A and subsequent stages based on that guess would have to be undone, the instructions following X already in the pipeline would have to be flushed, and stage A would have to restart with the correct instruction pointer. This branch prediction strategy is a special case of speculative execution.
Типтік бағдарламалық жасақтамалардың орындалуы
Дерек құбырлары тиімді іске асырылуы үшін, жұмысты қолжетімді CPU өзектеріне жіберу үшін CPU жоспарлау стратегиясы, сондай-ақ құбыр желісінің сатылары жұмыс істейтін дерек құрылымдарын пайдалану қажет. Мысалы, UNIX-тің туындылары операциялық жүйеде іске асырылған құбырларды пайдалана отырып, әртүрлі процестердің стандартты кіріс-шығысын байланыстыратын командаларды құбыржолға қосуы мүмкін. Төменгі деңгейдегі тәсілдер сатыларда жұмысты жоспарлау үшін операциялық жүйе ұсынатын жіптерге (threads) сүйене алады: жіптер жиынтығына негізделген немесе әр сатыға бір жіпке негізделген іске асырулар қолданылады және бар. Бірнеше орындау жіптерін қажет етпейтін, демек қосымша CPU өзектерін қажет етпейтін, мысалы, coroutine негізделген аямен дөңгелек жоспарлаушыны (round robin scheduler) пайдаланатын кооперативтік көп тапсырмалылыққа негізделген басқа да стратегиялар бар. Мұндай жағдайда, әрбір саты өзінің жеке coroutine-імен құрылуы мүмкін, ал одан кейін өзінің айналымдық тапсырмасын аяқтағаннан кейін бақылауды жоспарлаушыға қайтарады. Бұл тәсіл процестің сатылары олардың уақытын тиімсіз пайдаланбауы үшін мұқият бақылауды талап етуі мүмкін.
Шығындар мен кемшіліктер
Құбырлы жүйе әдетте бірден бір топтап орындалатын жүйеге қарағанда көбірек ресурстарды (схема элементтері, өңдеу бірліктері, компьютерлік жад және т.б.) қажет етеді, себебі оның кезеңдері осы ресурстарды бөлісе алмайды, сондай-ақ элементтер арасында буферлеу және қосымша синхронизациялық логика қажет болуы мүмкін. Бұған қоса, бөлек өңдеу элементтері арасындағы деректерді беру, әсіресе ұзын құбырларда, жайлап кетуді (latency) арттыруы мүмкін. Егер әртүрлі деректерді өңдеу арасында тәуелділіктер болса, әсіресе оларды өңдеу үшін болжау және кері қайту стратегиясы қолданылса, құбырлы өңдеудің қосымша күрделігі жоғары болуы мүмкін. Шындығында, күрделі командалар жиынтығы үшін осы стратегияны іске асыру құны, RISC және VLIW сияқты компьютерлік архитектураны қарапайымдастыруға бағытталған радикалды ұсыныстарға әкелді. Компиляторларға командалық құбырдың өнімділігін арттыру үшін машиналық командаларды қайта құру міндеті жүктелді.
Жаңа технологиялар
Рас, соңғы жылдары қолданбаларға және олардың негізгі жабдықтарына қойылатын талаптар күрт өсті. Мысалы, үлкен деректердің көлемі мен әртүрлілігіне байланысты, деректерді қатар-қатар қарап шығатын бір түйінді қолданбалармен құбыржолдар құру енді мүмкін емес. Алайда, Hadoop немесе соңғы кезде Apache Spark сияқты деректерді талдау жүйелерінің пайда болуы үлкен деректер жиынтығын бірнеше өңдеу түйініне таратуға мүмкіндік берді, соның арқасында қолданбалар бұрынғыдан бірнеше есе артық тиімділікке қол жеткізе алады. Бүгінде бұның салдары – осылай таратылған өңдеуді пайдаланатын орта деңгейдегі компьютердің өзі үлкен деректер құбыржолдарын құру және іске қосу мүмкіндігіне ие.