Системные вызовы накладные расходы

Я только начал изучать системные вызовы. Я хотел бы знать, что вызывает издержки, когда системный вызов сделан.

Например, если мы рассмотрим функцию getpid(), когда для getpid () выполняется системный вызов, я предполагаю, что если элемент управления находится в данный момент в дочернем процессе, то необходимо выполнить переключение контекста, чтобы войти в родительский процесс, чтобы получить pid., Может ли это способствовать накладным расходам?

Кроме того, когда вызывается getpid(), будет некоторая передача метаданных через границу пользовательского пространства, а также вход и выход из ядра. Так будет ли постоянное переключение между пользовательским пространством и ядром вызывать некоторые издержки?

3 ответа

Решение

Например, если мы рассмотрим функцию getpid(), когда для getpid () выполняется системный вызов, я предполагаю, что если элемент управления находится в данный момент в дочернем процессе, то необходимо выполнить переключение контекста, чтобы войти в родительский процесс, чтобы получить pid.,

Здесь не нужно переключать контекст на дочерний процесс - ядро ​​должно иметь в своем распоряжении все необходимые данные. В большинстве случаев ядро ​​переключает контексты только на процесс пользовательского пространства в планировщике или при возврате из системного вызова.

Также, когда вызывается getpid(), происходит передача метаданных через границу пользовательского пространства, а также вход и выход из ядра. Так будет ли постоянное переключение между пользовательским пространством и ядром вызывать некоторые издержки?

Да, если getpid() часто звонили, накладные расходы наверняка накапливались. Есть несколько доступных подходов, которые могут избежать этих издержек для простых системных вызовов "getter", таких как getpid() а также gettimeofday(); Одним из таких подходов, который когда-то использовался в Linux, было сохранение (известного) результата системного вызова на специальной странице памяти. (Этот механизм был известен как vsyscall.)

Я сделал несколько более точных тестов на Linux 86-64 (скомпилирован с -O3):

ns    relative(rounded) function
4.89  1      regular_function  //just a value return
6.05  1      getpid   //i think this one has got to be cached
17.7  4      sysconf(_SC_PAGESIZE)
22.6  5      getauxval(AT_EUID)
25.4  5      sysconf(_SC_NPROCESSORS_ONLN)
27.1  6      getauxval(AT_UID)
54.1  11     gettimeofday
235   48     geteuid
261   53     getuid
264   54     getppid
314   64     sysconf(_SC_OPEN_MAX)
622   127    pread@0 // IO funcs benchmarked with 1 bytes quantities
638   130    read    // through a 1 Gigabyte file
1690  346    write
1710  350    pwrite@0

Самые дешевые "системные вызовы" - это те, которые проходят через вспомогательный вектор (~20–30 нс). Вызовы посередине (~250–310 нс) должны наиболее точно отражать среднюю нагрузку, поскольку с ними не нужно много работать в ядре.

Для сравнения, пары malloc+free с запросами небольшого размера (<64 байта => без системных вызовов) стоят около 70-80 нс (см. Мой ответ в разделе Стоимость статического выделения памяти по сравнению с динамическим выделением памяти в C).

Простите за обобщение (а не за каждое предложение).

Вызов системной службы (такой как возврат информации о процессе) имеет оболочку режима пользователя. Эта оболочка вызывает исключение, которое маршрутизируется через системную диспетчерскую таблицу, которая вызывает системную службу режима ядра.

Переключение в режим ядра требует чего-то похожего на переключение контекста процесса. Например, он требует перехода от пользовательского стека к стеку ядра (и других системных зависимых изменений).

Вызывающий процесс предоставляет буфер возврата в пользовательском режиме. Системная служба системы проверит, чтобы убедиться, что это допустимый буфер режима пользователя, прежде чем записывать данные ответа в целях безопасности.

Библиотечная функция, такая как getpid, которая возвращает только информацию о текущем процессе, может не требовать переключения в режим ядра.

Другие вопросы по тегам