커널 기능이 커널 공간보다 사용자 공간에서 더 빠르게 재구현되는 이유는 무엇입니까?

커널 기능이 커널 공간보다 사용자 공간에서 더 빠르게 재구현되는 이유는 무엇입니까?

나는 책을 읽고 있습니다블로그 게시물그리고 다음 문장을 주목하세요.

그런 다음 그는 매우 놀라운 말을 했습니다. Seastar HTTP 프레임워크에서 그들은 자체 TCP 스택을 작성하여 모든 것을 몇 배 더 빠르게 만들었습니다. 무엇? !

성능상의 이유로 커널 기능이 사용자 공간에서 다시 구현되는 이유를 이해하려고 노력하고 있습니다. 나는 기능이 (많은) 특권 명령을 실행하기 때문에 정확하게 커널에 존재한다고 가정합니다. 그렇지 않으면 기능이 단순히 사용자 공간 프로그램으로 구현될 수 있습니다. 따라서 사용자 공간의 네트워크 스택과 같은 커널 기능을 다시 구현하려는 경우(gVisor가 수행하는 작업)네트워크 스택예) 결국 많은 시스템 호출을 커널로 다시 호출해야 하므로 많은 오버헤드가 발생하지 않습니까?

전통적으로 커널의 일부였던 기능을 사용자 공간에서 다시 구현하면 많은 시스템 호출을 수행할 필요가 없습니까? 그렇다면 예를 들어 네트워크 스택에서 어떻게 작동합니까? send()예를 들어 자주 수행해야 할 수도 있습니다.recv()

나는 사용자 공간에서 기능을 다시 구현하면 다음과 같은 두 가지 잠재적 이점이 있다는 것을 이해합니다.

  • 커널에 추가한 내용에 의존하지 않습니다(이는 힘든 프로세스처럼 보입니다).
  • 사용자 공간에서 재구현된 레거시 커널 기능에서 취약점이 발견되면 이는 "단지" 권한이 없는 사용자 공간 프로세스일 뿐입니다.

하지만 저는 이 문제의 성능 측면에 더 관심이 있습니다.

답변1

그 중 일부는 시스템 호출 경계를 넘는 일부 트립을 피하기 위한 것입니다.

이는 사실이지만 반면에 Linux 시스템 호출 인터페이스는 매우 일반적이고(즉, 다양한 유형의 애플리케이션과 시스템을 처리해야 함) 매우 제한적입니다(시스템 호출 매개변수는 현재 요청에만 특정함). 커널은 일반적으로 코드가 다음에 무엇을 할 것인지 거의 모릅니다.

find예를 들어 보겠습니다 . getdents, 등 의 시스템 호출에 많은 시간을 소비합니다 opendir. 이를 사용하여 많은 작업을 수행할 수 있지만 find일반적인 명령줄은 다음과 같습니다.

find . -name 'report_201[89].txt' -print -quit

프로그램 find은 많은 디렉토리를 열고 많은 파일 이름을 읽습니다. 이 파일 이름을 사용자 공간 기능에 제공하여 파일 이름 이 또는 fnmatch인지 확인합니다 .report_2018.txtreport_2019.txt

그러나 이것이 .일부 최신 파일 시스템에 있다고 가정해 보겠습니다. 이러한 디렉토리는 실제로 B-트리 또는 해시 테이블입니다. 커널이 우리가 찾고 있는 파일 이름을 알고 있다면 많은 처리 시간을 절약할 수 있습니다.

우리가 이것을 보고 있다고 가정해 봅시다 git status. 시스템 호출을 추적하면 많은 lstat호출이 발생합니다. 하지만 실제로 알아내려고 하는 것은사용자가 파일 시스템을 변경했습니까?git커널은 기본적으로 답을 알고 있지만 커널이 알고 싶어하는 것을 알려줄 방법이 없습니다 . 따라서 모든 것을 자체적으로 확인해야 합니다(다소 영리한 방법으로 확인하지만).

여기서 전반적인 주제는 커널 API가 애플리케이션별인 경우 상황이 더 효율적이라는 것입니다. 하지만 디자인 관점에서 보면 정말 다양한 애플리케이션이 있기 때문에 말도 안 되는 일입니다. 더 넓은 커널 인터페이스를 유지하는 것은 매우 선형적인 복잡성을 가질 수 있습니다. 하지만 이것이 바로 사용자 공간에서 더 많은 문제를 해결함으로써 (일부 문제의 경우) 효율성을 향상시킬 수 있는 이유입니다.

답변2

즉, 커널은 다양한 상황/애플리케이션/하드웨어를 처리해야 합니다. 하드웨어 및/또는 애플리케이션 통신 요구 사항을 이해하면 스택 재구현을 완료할 수 있습니다. 그런 다음 해당 우주에 대한 코드를 작성하면 됩니다.

UDP를 통해 주기적으로 데이터를 전송하는 작은 감지 장치가 있다고 가정해 보겠습니다. 대부분의 값이 서버에 도달하도록 고정된 UDP/IP 패킷을 생성할 수 있습니다(IP, 포트, 대상 포트 및 주소, 메시지 길이, 플래그 등을 알고 있으면 읽기만 변경하면 됩니다).

단지 이를 위해 전체 IP 코어 스택을 실행하는 것은 과도하고 느리며 아마도 실현 가능하지도 않을 것입니다(간단한 Arduino에서 실행하기예를 들어).

하지만 더 넓은 대답은 더 복잡하므로 다음 문서를 추천합니다.Linux 커널의 TCP 스택을 사용하는 이유링크는 인용하신 글 하단에 있습니다.

관련 정보