/ / Защо е std :: mutex толкова бавен за OSX? - c ++, multithreading, macos

Защо std :: mutex толкова бавен за OSX? - c ++, multithreading, macos

Имам следния критерий: https://gist.github.com/leifwalsh/10010580

По същество се завърта k нишки и след това всяка нишка прави около 16 милиона / k заключване / увеличаване / отключване цикли, с помощта на spinlock и а std::mutex, На OSX, на std::mutex е опустошително по-бавен от spinlock, когато се твърди, докато на Linux той е конкурентен или малко по-бързо.

OSX:

spinlock 1:     334ms
spinlock 2:     3537ms
spinlock 3:     4815ms
spinlock 4:     5653ms
std::mutex 1:   813ms
std::mutex 2:   38464ms
std::mutex 3:   44254ms
std::mutex 4:   47418ms

Linux:

spinlock 1:     305ms
spinlock 2:     1590ms
spinlock 3:     1820ms
spinlock 4:     2300ms
std::mutex 1:   377ms
std::mutex 2:   1124ms
std::mutex 3:   1739ms
std::mutex 4:   2668ms

Процесорите са различни, но не че различен (OSX е процесор Intel Core i7-2677M CPU @ 1.80GHz, Linux е процесор Intel Core i5-2500K CPU @ 3.30GHz), това изглежда като проблем с библиотеката или ядрото. Някой знае ли източникът на забавянето?

За да изясня моя въпрос, разбирам, че "тамса различни mutex реализации, които се оптимизират за различни неща и това не е проблем, това се очаква ".Този въпрос е: какви са действителните различия в изпълнението, които причиняват това? Или, ако това е хардуерен въпрос (може би кеш е само много по-бавно на MacBook), че е приемливо също.

Отговори:

11 за отговор № 1

Просто измервате избора на библиотеката за търговия с пропуски за справедливост. Стандартът е силно изкуствен и наказва всеки опит да се осигури изобщо никаква справедливост.

Изпълнението може да направи две неща. Тя може да позволи на една и съща нишка да получите mutex два пъти подред, или тя може да промени коя нишка получава mutex. Този показател силно наказва промяната в нишките, защото контекстният превключвател отнема време и защото пинг-понг на мутекса и val от кеш в кеш паметта отнема време.

Най-вероятно това просто показва различнитекомпромиси, които трябва да направят реализациите. Той силно възнаграждава реализациите, които предпочитат да връщат мутекса обратно към нишката, която го е задържала последно. Базата за сравнение дори възнаграждава реализациите, които правят CPU за отпадъци. Той дори възнаграждава реализациите, които изпускат процесора, за да се избегнат контекстни превключватели, дори когато има друга полезна работа, която CPU може да направи, и не наказва реализацията за междуядрен трафик, което може да забави други несвързани нишки.

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

Безумно, това е безсмислен критерий, който не е в състояние да идентифицира проблем.

Специфичното обяснение е почти със сигурноствнедряването на Linux е spinlock / futex хибрид, докато OSX реализацията е конвенционална, еквивалентна на заключването на обект на ядрото. Заключването на част от изпълнението на Linux благоприятства разрешаването на същата нишка, която току-що пусна mutex да го заключи отново, което вашият бенчмарк силно възнаграждава.


3 за отговор № 2

Дейвид Шварц е по същество правилен, с изключение накоментара за производителност / адаптивност. Всъщност е много по-бърз на Linux, защото използва futex и режийният разход на разговор е много по-малък. Това означава, че в неосъществения случай, той просто прави функционален разговор, атомна работа и се връща. Ако повечето от вашите ключалки са неосъществени (което обикновено е типичното поведение, което ще видите в много програми в реалния свят), придобиването на ключалка е основно безплатно. Дори в твърдия случай, това е функция за функция, syscall + атомно + добавяне на 1 конец към списък (системата е скъпата част от операцията). Ако мутексът бъде пуснат по време на системния сетълмент, функцията се връща незабавно, без да се вмъква в чакащ списък.

На OSX няма futex. Придобиването на мутекс изисква винаги говорейки с ядрото. Освен това, OSX е хибриден микроерус. Това означава да говорите с ядрото, трябва да го изпратите съобщение. Това означава, че правите сортиране на данни, системите, копирате данните в отделен буфер. След това в някакъв момент ядрото идва, разглобява данните и получава заключване и ви връща съобщение. По този начин в неосъществения случай това е много тежък тегло. В спорния случай това зависи от това колко дълго сте блокирали чакането на ключалката: колкото по-дълго чакате, толкова по-евтино е работата с заключване, когато се амортизира през цялото време на изпълнение.

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


2 за отговор № 3

Трябва да използвате едно и също изпълнение на STL и в двете системи. Това може да е проблем в libc ++ или в pthread_mutex _ * ().

Това, което другите плакати говорят за мутексбрави, които са конвенционални на OS X, е пълна лъжа. Да, ключалките Mach и семафорите изискват системни повиквания за всяка операция. Но освен ако изрично не използвате приложния програмен интерфейс за маскиране или семафи, тогава те не се използват в молбата ви.

Линуксът на OS X използва __psynch_ * BSD системаобаждания, които дистанционно съответстват на Linux futexes. В неизвестния случай, libpthread не прави системно повикване за придобиване на мутекс. Използва се само инструкция като cmpxchg.

Източник: libpthread изходния код и моите собствени познания (аз съм разработчик на Дарлинг).