Причина за неволни превключвания на контекста

Опитвам се да профилирам многонишкова програма, която съм написал на малко по-голяма машина (32 ядра, 256 GB RAM). Забелязах, че между стартиранията производителността на програмата може да варира драстично (70-80%). Изглежда не мога да намеря причината за тази огромна разлика в производителността на програмата, но анализирайки резултата от помощната програма „време“ при голям брой изпълнения, забелязах, че броят на неволните превключвания на контекста корелира силно с производителност на програмата (очевидно по-малко превключвания на контекст водят до по-добра производителност и обратно).

Има ли някакъв добър начин да се определи какво причинява това превключване на контекста? Ако мога да открия виновника, тогава може би ще мога да се опитам да отстраня проблема. Имам обаче няколко конкретни ограничения за инструментите, които мога да използвам. Първо, нямам root привилегии на машината, така че всички инструменти, изискващи такива привилегии, са изключени. Второ, това е доста старо ядро ​​(RHEL5, ядро ​​2.6.18), така че някои от стандартните неща за perf-събития може да не присъстват. Както и да е, всякакви предложения за това как да се задълбочим в причината за това превключване на контекста ще бъдат много оценени.

Актуализация: Реших да тествам програмата си на различна (и по-малка) машина. Другата машина е 4-ядрен (с хиперзаглавие) Linux кутия с 8 Gb RAM и много по-ново ядро ​​--- 3.2.0 срещу 2.6.18 на другата машина. На новата машина не мога да възпроизведа бимодалния профил на производителност. Това ме кара да вярвам, че проблемът се дължи или на хардуерен проблем (както беше предложено в коментарите), или на особено патологичен случай на ниво ядро, който оттогава е коригиран. Моята текуща най-добра хипотеза е, че това може да е резултат от факта, че новата машина има ядро ​​с напълно справедлив планировчик (CFS), докато старата машина няма. Има ли начин да тествате тази хипотеза (да кажете на новата машина да използва различен/по-стар планировчик), без да се налага да компилирате стара версия на ядрото за новата машина?


person nomad    schedule 23.06.2013    source източник
comment
Под неволни превключвания на контекста имате ли предвид някакъв друг процес, който е искал да се изпълни, или МОЯТ процес е направил нещо, което е накарало системата да го спре, докато системата е свършила някаква работа, например изчакване някои файлови данни да бъдат заредени от диск или мрежа?   -  person Mats Petersson    schedule 24.06.2013
comment
Знаете ли за pthread_cond_t?   -  person Varvarigos Emmanouil    schedule 24.06.2013
comment
@MatsPetersson да - „Първо, нямам root права на машината“ не предполага изключителното му използване.   -  person Martin James    schedule 24.06.2013
comment
Помолете системния администратор, който има привилегия, за да разбере.   -  person Martin James    schedule 24.06.2013
comment
Това, че не сте сами, не означава непременно, че няма достатъчно ресурс на машината, за да изпълни задачата ви. Но ако други хора споделят машината, тогава е трудно - освен ако, разбира се, можете да поискате от администраторския персонал да ви даде известно право да повишавате приоритета на задачите си над задачите на други хора или нещо друго от този сорт. Ако на дадена машина има конкуриращи се задачи, машината ще споделя ресурсите на процесора между задачите - така работи многопотребителска система...   -  person Mats Petersson    schedule 24.06.2013
comment
Въпреки че нямам администраторски привилегии, аз съм сам на машината (поне бях, когато направих предишното си профилиране). Другите потребители с достъп до машината са членове на нашата сравнително малка изследователска група, така че ако имам нужда от известно време, за да направя анализ на ефективността, мога да ги помоля за самостоятелно използване на машината за известно време. Фактът, че това се случва, когато съм сам на машината, предполага, че може би има прекъсващ системен процес, който причинява прекъсванията, но не знам как да проверя със сигурност.   -  person nomad    schedule 24.06.2013
comment
Под неволни превключвания на контекста имам предвид, че според операционната система това не е резултат от отстъпването или изчакването на моята обработка, а по-скоро резултат от това, че операционната система принудително изпреварва моя процес за някаква друга цел.   -  person nomad    schedule 24.06.2013
comment
Как разбра, че не се поддаваш и не чакаш? Вашата програма разпределя ли памет, извършва ли системни извиквания или използва библиотека, която ги изпълнява? Вашата програма свързана ли е с I/O памет?   -  person DanielKO    schedule 24.06.2013
comment
Опитахте ли да направите тест в top, докато програмата ви работи? Каквото и да ви изпреварва, вероятно използва много CPU....   -  person Tony Delroy    schedule 24.06.2013
comment
@DanielKO -- Помощната програма time всъщност разгражда контекстните превключвания чрез доброволно/неволно. Дефиницията на неволни контекстни превключвания тук е, когато вашият процес е изпреварен от операционната система по някаква причина, различна от това, че доброволно се отказва от контрола (напр. предаване/изчакване). Това може да се случи, когато неговият отрязък от време изтече и има процес с по-висок приоритет, който трябва да бъде изпълнен, и вероятно при редица други условия.   -  person nomad    schedule 24.06.2013
comment
О, забравих, че времето на GNU има тези допълнителни неща. Какъв е броят на дребните грешки в страницата? Освен това и другите неща, които попитах.   -  person DanielKO    schedule 24.06.2013
comment
Моето предположение - другите потребители са планирали големи cron задачи.   -  person Martin James    schedule 24.06.2013
comment
@DanielKO -- Програмата не разпределя памет динамично, а разпределя предварително фиксирано количество памет. Той чете във файл от диска и брои # срещания на фиксирани поддуми, които се срещат във файла, така че се извършва значителен I/O. Въпреки това тествах I/O частта на програмата изолирано и това не е тясното място (мога да прочета повече поддуми, отколкото мога да обработя). Освен това производителността изглежда еднаква, когато правя само I/O (т.е. не виждам голям брой неволни контекстни превключвания, водещи до влошена производителност).   -  person nomad    schedule 24.06.2013
comment
@TonyD -- Да; Гледах „отгоре“, докато програмата работи и странното е, че не изглежда, че в системата се случват много други неща; най-вече само неща на системно ниво (и т.н. dbus-daemon, greceptor (той изпълнява клъстерен софтуер ROCKS) и някои други различни неща с ниско натоварване).   -  person nomad    schedule 24.06.2013
comment
@DanielKO -- Програмата отчита ~3920000 незначителни грешки на страници на изпълнение (разликата тук е малка) и 0 големи грешки на страници на изпълнение. Броят на грешките в страницата изглежда независим от това дали получавам добра или лоша производителност.   -  person nomad    schedule 24.06.2013
comment
Извършва ли някаква атомна операция? Това не е евтино с много процесори. Иначе този проблем все още е твърде абстрактен. Трябва да трансформирате вашата програма в минималистичен примерен код и да го публикувате. Или ще откриете проблема сами, или хората ще открият основен недостатък в дизайна на алгоритъма.   -  person DanielKO    schedule 24.06.2013
comment
@DanielKO -- Всъщност, да, правя атомни операции. Броят на поддумите се съхранява в голям масив от атомни цели числа (std::atomic‹uint32_t›). Не разбирам защо понякога това би причинило проблем с производителността, но не и други. Профилът на изпълнение всъщност е странен, тъй като има два режима; бързо и бавно и всяко изпълнение на програмата попада в едно от тях (т.е. никога не се изпълнява на ниво между времето за бързо и бавно изпълнение). Има ли начин да надникна по-дълбоко в атомите, за да видя дали причиняват проблем?   -  person nomad    schedule 24.06.2013
comment
Първото нещо, за което трябва да внимавате, е фалшивото споделяне. Не мога да разясня твърде много в това пространство, но вижте stackoverflow.com/questions/10143676/ и глава 4 от perfbook kernel.org/pub/linux/kernel/people/paulmck/perfbook/ . Освен това може да е хардуерен проблем; Веднъж съм работил с 264-ядрена SGI UV машина, която от време на време се забавяше поради хардуерен срив, подобно на вашия сценарий с два режима.   -  person DanielKO    schedule 24.06.2013
comment
Интересното е, че виждам много подобен профил на производителност, ако премахна действителните атомни записи от кода; така че програмата просто чете във файла и извършва известна обработка на поддумите (напр. изчисляване на хеш функция). Много странно.   -  person nomad    schedule 24.06.2013
comment
Жалко, че сте загрижени за Linux, а не за Solaris/Mac OS/FreeBSD - DTrace би свършил кратка работа с разследване като това. Вижте тази серия публикации в блога за подробности: pt1, pt2, pt3, pt4   -  person Dan    schedule 01.07.2013
comment
Благодаря @gerty3000! Всъщност съм загрижен и за производителността на Mac OS, но просто нямам достъп до толкова много машини, които да тествам на тази платформа. Всъщност би било интересно да се види дали този проблем изобщо се появява в OSX, тъй като предполагам, че планировчикът е напълно различен и ако това е източникът на проблема, може да няма никакъв проблем в OSX.   -  person nomad    schedule 01.07.2013
comment
Колко често се изпълнява? Възможно ли е понякога файлът да е кеширан, а понякога не? Ръчно ли четете файла в паметта или използвате mmap?   -  person kfsone    schedule 01.07.2013
comment
Дисперсията, която докладвах, е за много последователни изпълнения. Изпълнението обаче се редува между бърз и бавен режим. Файлът се анализира от нишка за четене, която запълва едновременна опашка с двоен край, и след това данните се изтеглят от опашката от други нишки за обработка. Не мисля обаче, че това е свързано с кеширането на файлове, тъй като режимите на производителност изглежда изчезват, когато не се обработват в нишките за обработка на данни (т.е. когато просто прочета файла).   -  person nomad    schedule 01.07.2013


Отговори (6)


Споменахте, че има 32 ядра, но какво е точното разположение на хардуера? напр. колко пакета има машината, колко ядра, как се споделя кешът и т.н. За споделяне на този вид информация аз лично обичам да споделям изхода на likwid-topology -g.

Както и да е, има една част от недетерминизма във вашето изпълнение: афинитет на нишка. Операционната система присвоява SW нишките да работят на конкретни HW нишки по някакъв начин, без да взема предвид познанията за това как нишките комуникират (просто защото няма тези знания). Това може да причини всякакви ефекти, така че за възпроизводими изпълнения е добра идея да се уверите, че сте закачили вашите SW нишки към HW нишки по някакъв начин (може да има и оптимален начин, но досега аз говоря само за детерминизъм).

За фиксиране (известно още като афинитет) можете или да използвате изрични извиквания на Pthread, или да опитате друг инструмент от пакета Likwid, наречен likwid-pin - вижте тук.

Ако това не ви осигури постоянни резултати, стартирайте добър профилиращ инструмент (напр. Intel VTune) върху вашето работно натоварване, като се уверите, че сте заснели по-бързо и по-бавно изпълнение и след това сравнете резултатите. Във VTune можете да използвате функцията за сравнение, която показва два профила един до друг.

person Alexey Alexandrov    schedule 02.07.2013
comment
Благодаря за предложението Всъщност се опитах да задам афинитета на моите нишки директно с помощта на pthreads (и работи), но все още виждам променливостта на производителността. Това ме кара да вярвам, че проблемът най-вероятно е резултат от старото ядро ​​/ планировчик. Въпреки това не знаех за инструментите на likwid и те изглеждат много полезни. Освен това убедих администратора да създаде група sudoers, за да мога действително да използвам тези инструменти за профилиране. Мисля, че само това предложение може да си струва наградата. - person nomad; 03.07.2013
comment
Благодаря за наградата! Интересно е, че афинитетът не подобри възпроизводимостта. Това, което бих се опитал да видя след това (въпреки че използвам профайлър) е дали променливостта идва от времето на потребителя или времето на ядрото. За това трябва да е достатъчна само помощната програма за „време“. Като по-задълбочено гмуркане в проблемите с планирането бих направил VTune с Advanced Hotspots с включени стекове (което събира информация за превключване на контекста) или възможностите за проследяване на график на ftrace. Едно важно нещо, което трябваше да попитам, е колко време отнема натоварването ви. Казахте 80% променливост - но дали е 5 секунди срещу 9 секунди или 5 ms срещу 9 ms? - person Alexey Alexandrov; 03.07.2013
comment
Променливостта е в доста голям период от време (напр. 120 срещу 200 секунди). Ако се случи само при много високи разделителни способности (напр. 5ms срещу 9ms), вероятно нямаше да се притеснявам толкова за това и нямаше да съм сигурен, че не е просто грешка в измерването. - person nomad; 04.07.2013
comment
120 срещу 200 секунди е наистина интересно. Имате ли някаква зависимост от честотната лента на мрежата във вашето работно натоварване? Това може да бъде толкова трудно, колкото четенето на голямо количество данни от мрежов дял. В зависимост от натоварването на мрежата можете да получите различна скорост. Но това няма да ви даде двумодален резултат. Както и да е, когато откриете крайната причина, би било много полезно да знаете каква е тя - дръжте ни в течение, ако имате възможност! :) - person Alexey Alexandrov; 04.07.2013

Вярвам, че вашият проблем всъщност е проблем с графика.

Човек не може да избегне нечий процес да бъде изпреварван от процесора, но проблемът е, че ако една нишка е изпреварена и след това следващият му квант завършва на различен процесор, или по-конкретно на процесор с различен L2 cache, тогава всичките му достъпи до паметта ще доведат до пропуски в кеша и ще накарат данните да бъдат извлечени от паметта. От друга страна, ако нишката бъде планирана на същия процесор, има вероятност нейните данни все още да са достъпни в cahce, например осигурявайки много по-бърз достъп до паметта.

Имайте предвид, че това поведение е най-вероятно да се случи, когато имате все повече и повече ядра. И тъй като това е нещо като "случайно" къде вашата нишка ще завърши на следващия си квант, тогава това би обяснило случайността на производителността.

Има инструменти за профилиране, които ви позволяват да регистрирате къде са планирани вашите теми, като например perf за Linux. Обикновено тези инструменти са специфични за топологията, в която изпълнявате вашата програма. За съжаление никой друг не ми идва на ум в момента. Има и начини да кажете на операционната система да планира нишки на едни и същи (или съседни) процесори, така че те ще се възползват от по-малко пропуски в кеша. За това можете да проверите този SO въпрос

Бих предложил да попитате вашия администратор кои инструменти като тези имате предвид, за да можете да направите правилно профилиране и присвояване на вашия график на нишки.

person cgledezma    schedule 01.07.2013

Споменавате бимодален профил на производителност, който виждате на една машина, а не на друга. Ужасно е, но това е нормално, дори и за еднонишкови приложения.

Проблемът е, че има твърде много фактори в Linux система (всяко ядро, независимо от използвания планировчик), които влияят на производителността на приложението. Започва с рандомизация на адреси и завършва с микроскопични разлики във времето, ескалиращи до огромни закъснения при превключване на контекста между процесите.

Linux не е система в реално време. Той просто се опитва да бъде възможно най-ефективен в средния случай.

Има няколко неща, които можете да направите, за да сведете до минимум разликата в производителността:

Намалете броя на нишките до необходимия минимум. Не разделяйте различните аспекти на проблема си на теми. Просто разделете на нишки, когато наистина е необходимо, например за захранване на процесорите с независими (!) задачи за обработка на числа. Опитайте се да направите възможно най-много причинно-следствена работа в една нишка. Вашите нишки трябва да изискват възможно най-малко комуникация помежду си. По-специално не трябва да имате модели на заявка/отговор между нишките, където закъсненията се натрупват.

Да приемем, че вашата операционна система може да прави само около 1000 контекстни превключвания между нишки/процеси в секунда. Това означава няколко от 100 транзакции заявка/отговор в секунда. Ако направите бенчмарк на Linux и откриете, че можете да направите много повече, игнорирайте това.

Опитайте се да намалите отпечатъка от жизненоважни данни в паметта. Разпределените данни са склонни да изхвърлят кеша с много фин и труден за обяснение ефект върху производителността.

person Johannes Overmann    schedule 01.07.2013

Можете да проследите източника на контекстни превключватели в ядрото, като използвате ftrace (използвайки трасиращият sched_switch). Освен това използването на perf може да ви помогне да стесните други показатели (кеш пропуски, и т.н.).

Как се променя променливостта на производителността, когато увеличите програмата си от 1 нишка до 32 (и възможно повече)?

Възможно ли е вашата програма да има споделени данни (или някакъв друг ресурс), за които се борят отделните нишки? Така че те изпитват състояние на състезание, което е по-голямо, когато има повече паралелно изпълнение (следователно променливата производителност)? Освен процесорно време, за какви ресурси се борят нишките на вашата програма?

Мисля, че ще трябва да компилирате старото ядро ​​на вашата 4-ядрена машина. Това би било не само добро образователно упражнение, ако още не сте го направили, но би било ценно за изолиране на променливи в този проблем. Ако трябваше да направите това, аз също бих се опитал да съпоставя точната дистрибуция, тъй като проблемът ви може да не е ограничен само до ядрото. Може също да е нещо в потребителското пространство или може би просто в опциите за компилиране на ядрото (което следователно ще бъде съпоставено в същата версия на дистрибуцията).

Може да искате да разгледате използването на профилиращ инструмент, като gprof. Може да ви даде представа за (потенциалното) тясно място. Например, ако чакате системно повикване за запис или нещо от този род.

Ето няколко статии, които могат да ви помогнат да предизвикате една или две идеи:

http://halobates.de/lk09-scalability.pdf

http://pdos.csail.mit.edu/papers/linux:osdi10.pdf

Допълнителен източник: Защо едно неволно превключване на контекст на секунда?

person Homer6    schedule 28.06.2013
comment
И накрая, винаги можете да подадете петиция за надграждане на ядрото. :-) - person Homer6; 28.06.2013
comment
Благодаря за линковете. Мисля, че сте прав, че наистина може да се наложи да прекомпилирам старото ядро ​​за другата машина. - person nomad; 03.07.2013
comment
Освен това тези видео лекции съдържат много добри инструменти и техники, които могат да бъдат полезни във вашия случай: ocw.mit.edu/courses/electrical-engineering-and-computer-science/ - person Homer6; 04.07.2013
comment
@nomad Актуализирах това, за да препратка към инструмента ftrace, който ще ви даде допълнителна представа за превключванията на контекста. - person Homer6; 13.07.2013

В многонишкова програма, прикрепете нишка към определен номер на процесора и проверете дали виждате подобрение в производителността.

person Anand Rathi    schedule 02.07.2013

Най-добрият залог, когато става въпрос за разсрочване, е да използвате Kernel Profiler/logger Ftrace. Това трябва да ви покаже кои нишки се изместват от други нишки. За съжаление манипулаторите на прекъсвания от долната половина не са правилно етикетирани, така че може да бъде трудно да ги дешифрирате.

person doron    schedule 02.07.2013