Самый быстрый системный вызов Linux


В системе Intel x86-64, которая поддерживает syscall и sysret Какой" самый быстрый " системный вызов из 64-разрядного пользовательского кода на ядре vanilla?

В частности, это должен быть системный вызов, который осуществляет syscall/sysret пользователь переход ядра1, но делает наименьший объем работы сверх этого. Ему даже не нужно делать сам syscall: какой-то тип ранней ошибки, которая никогда не отправляется в конкретный вызов на стороне ядра, хорош, пока он не замедляется. путь из-за этого.

Такой вызов может быть использован для оценки необработанных syscall и sysret накладных расходов независимо от любой работы, выполняемой вызовом.


1 в частности, это исключает вещи, которые кажутся системными вызовами, но реализуются в VDSO (например, clock_gettime) или кэшируются средой выполнения (например, getpid).

4 5

4 ответа:

Тот, который не существует, и поэтому возвращается-ENOSYS быстро.

Из arch / x86 / entry / entry_64.S:

#if __SYSCALL_MASK == ~0
    cmpq    $__NR_syscall_max, %rax
#else
    andl    $__SYSCALL_MASK, %eax
    cmpl    $__NR_syscall_max, %eax
#endif
    ja  1f              /* return -ENOSYS (already in pt_regs->ax) */
    movq    %r10, %rcx

    /*
     * This call instruction is handled specially in stub_ptregs_64.
     * It might end up jumping to the slow path.  If it jumps, RAX
     * and all argument registers are clobbered.
     */
#ifdef CONFIG_RETPOLINE
    movq    sys_call_table(, %rax, 8), %rax
    call    __x86_indirect_thunk_rax
#else
    call    *sys_call_table(, %rax, 8)
#endif
.Lentry_SYSCALL_64_after_fastpath_call:

    movq    %rax, RAX(%rsp)
1:

Используйте недопустимый номер системного вызова, чтобы диспетчерский код просто возвращался с
eax = -ENOSYS вместо отправки в функцию обработки системных вызовов вообще.

Если только это не заставляет ядро использовать медленный путь iret вместо sysret / sysexit. Это может объяснитьизмерения , показывающие недопустимое число, которое на 17 циклов медленнее, чем syscall(SYS_getpid), потому что обработка ошибок glibc (установка errno), вероятно, не объясняет этого. Но из моего чтения исходного кода ядра, Я не вижу никаких причин, почему бы ему не использовать sysret при возврате -ENOSYS.


Этот ответ для sysenter, не syscall. Вопрос первоначально сказал:sysenter / sysret ( что было странно, потому что sysexit идет с sysenter, а sysret идет с syscall). Я ответил на основе sysenter для 32-битного процесса на ядре x86-64.

Родной 64-битный syscall обрабатывается более эффективно внутри ядра. (Обновление; с исправлениями смягчения Meltdown / Spectre, он все еще депеши через C do_syscall_64 в 4.16-rc2).


My Что произойдет, если вы используете 32-битный int 0x80 Linux ABI в 64-битном коде? Q&A дает обзор ядра точки входа системных вызовов из режима compat в ядро x86-64 (entry_64_compat.S). Этот ответ просто берет соответствующие части этого.

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

int 0x80 и sysenter имеют разные точки входа. Ты ищешь ... entry_SYSENTER_compat. AFAIK, sysenter всегда идет туда, даже если вы выполняете его в 64-битном процессе пользовательского пространства. Точка входа Linux выдвигает константу __USER32_CS в качестве сохраненного значения CS, поэтому она всегда будет возвращаться в пользовательское пространство в 32-разрядном режиме.

После нажатия регистров, чтобы построить struct pt_regs в стеке ядра, есть TRACE_IRQS_OFF крюк (не знаю, сколько инструкций это составляет to), то call do_fast_syscall_32, который записан в C. (собственная 64-битная syscall диспетчеризация выполняется непосредственно из asm, но 32-битные системные вызовы compat всегда отправляются через C).

do_syscall_32_irqs_on в arch/x86/entry/common.c это довольно легкий вес: просто проверка, отслеживается ли процесс (я думаю, что именно так strace может перехватывать системные вызовы через ptrace), затем

   ...
    if (likely(nr < IA32_NR_syscalls)) {
        regs->ax = ia32_sys_call_table[nr]( ... arg );
    }

    syscall_return_slowpath(regs);
}

AFAIK, ядро может использовать sysexit после возврата этой функции.

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

Если вы хотите действительно протестировать sysenter / sysexit без всех этих дополнительных накладных расходов, вам нужно будет модифицировать Linux, чтобы поставить гораздо более простую точку входа без проверки трассировки или выталкивания / выталкивания всех зарегистрирует.

Вы, вероятно, также захотите изменить ABI, чтобы передать обратный адрес в регистре (как syscall делает сам по себе) вместо сохранения в стеке пользовательского пространства, который делает текущий sysenter ABI Linux; он должен get_user() прочитать значение EIP, к которому он должен вернуться.


Если все эти накладные расходы являются частью того, что вы хотите измерить, вы определенно все настроены с eax, который дает вам -ENOSYS; в худшем случае вы получите один дополнительный промах ветви из диапазона-проверьте, если ветвь предикторы являются горячими для этой ветви, основанной на обычных 32-разрядных системных вызовах.

Некоторые системные вызовы даже не проходят через переход user->kernel, читай vdso(7).

Я подозреваю, что этиVDSO системные вызовы (например, Время(2), ...) являются самыми быстрыми. Вы можете утверждать, что нет никаких" реальных " системных вызовов.

Кстати, вы можете добавить фиктивный системный вызов к вашему ядру (например, некоторый системный вызов, всегда возвращающий 0, или системный вызов hello world, см. Также this) и измерить его.

В этот бенчмарк Брендана Грегга (связанный с этой записью в блоге, которая представляет интерес для чтения по теме) close(999) (или какой-то другой fd, не используемый) рекомендуется.