概要
ソフトの性能を引き出すためには、自分が開発しているのがどのレイヤーなのかを理解することは極めて重要です。
フレームワーク、ライブラリを使うような場合、特に性能に影響します。
しかし最初はOSが提供しているI/Fがどれなのかが分からなかったり、一つ一つその仕組みを調べていくのは結構大変だったりします。本記事ではその例をいくつか挙げながら説明しようと思います。
OSとユーザーの境界はどこにあるか
Windowsとlinuxの例で説明します。
Windowsはwin32API1がOSとユーザーの境界です。実行バイナリとしてはkernel32.dllなどが機能を提供しています。
kernel32.dllをdumpbin2などで調べると、その下にntdll.dllなどのdllがいることがわかります。ユーザーに使わせるものとして位置づけられているのはwin32apiのようです。
裏取りができていないのですが、CPUをカーネルモードに移行させる命令を発行するのはntdll.dllであるそうです。公式ドキュメント的には、ユーザーモードドライバというのもそれにあたるようですが、ntdll.dllに含まれているんですかね。
linuxはシステムコールです。manコマンドでドキュメントが見られます。ググっても普通にでてきます。
macは未調査です。
ユーザー空間で動作する大概のソフトウェアはOSの機能を利用します。これはすなわち、win32APIやシステムコールを呼び出しているということです。
具体例
以下では具体例を列挙します。
自分がメインで開発しているのはWin32 APIかCの標準ライブラリを呼び出す層のソフトなので、「新卒のときに知りたかった」のはそこの部分です。しかし他の層のソフトを開発している方もいると思いますので、拾い読みしてもらえればと思います。
なお、以降はWindows、C言語に絞って話します。他の言語やフレームワークだとどうか、の記事も追って書ければと思っています。
標準入出力
ターミナル上で入出力するときは大体標準入出力を使うと思います。Cだとprintfとかscanf, C++だとstdinとかです。
そもそもターミナルはどういうソフトか、というところは以前の記事を見ていただければと思います。
中身はどうなっているかというと、printfやscanfは標準ライブラリの関数で、visual studioならucrt.libなどの静的ライブラリファイルに処理が埋め込んであります。
このucrt.lib内の処理がWin32APIを呼び出してターミナルに文字を表示したり読み込んだりします。
ここで呼び出される具体的にはWriteFileやReadFileです。※ターミナルに入出力される情報はファイルとして扱える仕組みになっています。
以上のことから分かるように、直接WriteFileやReadFileを呼び出した方が速いです。
ファイル入出力
では普通の、ストレージ上のファイルはどうでしょうか。こちらも標準入出力と同じで、標準ライブラリの関数としてはfread、fwriteがあります。内部でWin32APIのReadFile、WriteFileを呼び出しています。
動的確保
コンパイル時点ではサイズがわからない領域をメモリ上に確保し利用することをメモリ動的確保といいます。
こちらも標準ライブラリのmallocで行うのが定番です。内部ではWin32APIのHeapallocを呼び出しています。VirtualAllocやLocalAllocなどもあるようですが、違いはやや難しいので割愛します。
OpenGL(調査中)
標準ライブラリばかりになってしまったので、それ以外のも1つだけ挙げておきます。(と言っても調査中ですが)
OpenGLの関数を呼び出すとOPENGL32.dllに処理が移ります。OPENGL32.dllはWindowsに付属しています。
OPENGL32.dll自体はいつロードされるのかというと、プロセスを立ち上げたときです。
そのほか、わかっていないこと
- 現状分かっていないのは、OPENGL32.dllの処理内でカーネルモードに移行することがあるのか?という点です。
- また、linuxだとどの辺の事情が違うか?
- freeglutはどのようにOpenGLの関数を呼び出すのか?
以前、OS(カーネル)の中のGPUドライバの位置づけについても調べたのですが、Windowsはクローズドソースなので調査しづらく、linuxなどで調べる必要がありました。今回はそちらの内容は割愛します。
その他、わかっていないこと
- ソケット通信API(winsock)
書ききれていない部分もありましたが、最後までお読みいただきありがとうございました。