研究会の輪講でやったやつ.多少がんばった&評価も高めだったし使いまわせそうなので上げておく.
#11プロセスとハードウェアB2 sksat
View Slide
おさらい:デジタルデータの表現・ビット(bit):情報の最小単位・0/1, yes/no, ON/OFF, +/-, N/S・2進数の1桁・バイト(byte):8bit・電子計算機ではデータをだいたい1〜数バイト単位で処理※実は1byte != 8bit.まあほとんどは8bitだが...(明示的に8bitだと言う場合はオクテット)
コンピュータの構造(迫真):thinking_think:ホンマか?
皆さんのお手元のThinkPad X230
バラバラ事件これをこうして こうじゃ
マザーボードHDDメモリCPUファン
メモリ・データをたくさん置いておける(1,2,4,8,16,32,64...GB)・1次記憶・主記憶・揮発性:電源切るとデータが消える・アドレス(番地)を指定してデータを読み書き・byteごとdata〜0x00000x00010x00020x00030x00040xffff0xfffe0xfffd0xfffc0xfffb
メモリの読み書き0xaf0xbe0xad0xde〜0x00000x00010x00020x00030x00040xffff0xfffe0xfffd0xfffc0xfffbCPU\addr=0x002のデータが1byteホシイ/0xab\addr=0xfffeに0xabを入れたい/0xad0xab
バス・メモリ読み込み・CPU:アドレス→アドレスバス・メモリ:memory[addr] -> データバス・メモリ書き込み・CPU:アドレス→アドレスバス 書くデータ→データバス・メモリ:memory[addr]
レジスタ・CPUの中にも記憶領域がある・レジスタは小さい(8〜64bit)・メモリよりはるかに高速・メモリが作業机ならレジスタは手とか・用途によって色々あるx86のレジスタ
HDD/SSD・2次記憶装置・不揮発性:電源切ってもデータが残る!・OS/プログラムはここに保存・起動したらメモリに読み出してから動作・容量がデカい:数百GB〜数TB・ブロックデバイス:「ブロック(512byteとか)」ごとに読み書き
記憶装置記憶容量: 2次記憶(HDD/SSD) >>> 1次記憶(メモリ) >>>>>>> レジスタ・ぜんぶ2次記憶でいいじゃんアクセス速度:レジスタ >>>>>>> 1次記憶 >>>> 2次記憶・それだと遅すぎる!!!!!・レジスタはCPUの内部なので超高速容量当たりの価格: レジスタ >>> 1次記憶 >>> 2次記憶・でも2次記憶装置は安い・2次記憶でもHDDは低速安価大容量,SSDは高速高価低容量(比較的)
メモリのアクセス速度・メモリ:数十〜数百サイクル・昔はCPUの動作速度が大したことなかったのでなんとかなった・今:CPU「俺の”速さ”についてこられるかな?」・int a = 1 + 2; ← a, 1, 2がレジスタかメモリ上かで数十〜数百倍速度が変わってしまう!?・コンパイラの最適化でできる限りレジスタが使われるようになってる・めでたしめでたし・・・とはいかない・思い出すシリーズ:レジスタはクソ小さい・じゃあどうすんねん
キャッシュメモリ・レジスタとメモリの中間の存在・もちろんメモリより低容量高価格だが高速・レジスタとメモリの間に挟むレジスタキャッシュメモリメモリ3次キャッシュ2次キャッシュ・最近は2, 3, 4次キャッシュなんてものも
キャッシュメモリのしくみ・発想:アクセスしそうなデータがいいかんじにキャッシュに載っているとうれしい!メモリキャッシュメモリaddr=0x01, data=0xbeaddr=0x03, data=0xdeaddr=0x05, data=0xbaaddr=0x09, data=0x1f0x00: 0xef0x01: 0xbe0x02: 0xad0x03: 0xde0x04: 0xbe0x05: 0xba0x06: 0xfe0x07: 0xca0x08: 0x8b0x09: 0x1f0x0a: 0x00addr=0x0a, data=0x00
キャッシュメモリのしくみ(2)・「アクセスしそうなデータ」とは?・時間的局所性:同じアドレスに何度もアクセスする・空間的局所性:アクセスしたところの近くにアクセスする・方式がいくつかある:ダイレクトマップ,セットアソシアティブ,フルアソシアティブ
デバイスとのやりとり・入出力命令・入力:ちょっとN番のデバイスから値を取ってきて・出力:ちょっとN番のデバイスにこれをセットして・割り込み:デバイス「カンカンカンカン!!!入力!!!!おきてー!!!!!」・MMIO
MMIO・Memory Mapped I/O・メモリとデバイスが繋がっている(!?)・マイコンだとよくある・PCだとVRAM(Video RAM)・「(x=10, y=20)を紫に」とかを入出力命令でやってたら遅すぎる・メモリの一部の領域がディスプレイと接続VRAM0xA00000xAFFFF
「プログラム」の正体・プログラムもデータ(バイナリ)・CPUへの命令の集まり・「機械語」
機械語・CPUはバカ・int a = 1 + 2; ← こんなの難しすぎてわからん・面接官「あなたは何ができるんですか?」・CPU「計算がとても速くできるくらいです...」・思い出すシリーズ:電子計算機・機械語:CPUが理解できる「言葉」・いくつか[要出典]の命令?
機械語の種類・算術命令:add, sub, mul, divなど・add eax, 0x05:EAXレジスタの値に5を足す・論理演算命令:and, or, not, xorなど・ビットシフト・メモリの読み書き・入出力命令・ジャンプ命令:実行位置を変更
プログラムの実行・電源投入・2次記憶→メモリ・実行開始!・どうやって?
プログラム実行のしくみadd r0, 5sub r1, [0x20]inc r1add r0, r1jmp -2実行中PC: 0x01r0: 0x05r1: 0x00memory[0x20] = 0x03メモリ
プログラム実行のしくみadd r0, 5sub r1, [0x20]inc r1add r0, r1jmp -2実行中PC: 0x02r0: 0x02r1: 0x00memory[0x20] = 0x03メモリ
プログラム実行のしくみadd r0, 5sub r1, [0x20]inc r1add r0, r1jmp -2実行中PC: 0x03r0: 0x02r1: 0x01memory[0x20] = 0x03メモリ
プログラム実行のしくみadd r0, 5sub r1, [0x20]inc r1add r0, r1jmp -2実行中PC: 0x04r0: 0x03r1: 0x01memory[0x20] = 0x03メモリ
プログラム実行のしくみadd r0, 5sub r1, [0x20]inc r1add r0, r1jmp -2実行中PC: 0x02r0: 0x03r1: 0x01memory[0x20] = 0x03メモリ
プログラム実行のしくみadd r0, 5sub r1, [0x20]inc r1add r0, r1jmp -2実行中PC: 0x03r0: 0x03r1: 0x02memory[0x20] = 0x03メモリ
プログラムカウンタ・「次に実行する命令」や「今実行している命令」のアドレスを指すレジスタ・ジャンプ命令:プログラムカウンタの値を変える命令絶対ジャンプ:アドレスを指定してジャンプする相対ジャンプ:「N個前/後の命令」にジャンプする・前にジャンプ → 繰り返し処理を実現・条件ジャンプ命令:「比較結果が0だったらジャンプ」・条件分岐の実現(条件分岐命令とも)
様々なコンピュータアーキテクチャ・コンピュータの基本的な構造は大体同じ・スマホもバラせばCPU・バス・メモリ・ディスク・外部装置・PCの/bin/bashをスマホにコピーしたら動くか? → 動かない・何故か?・CPUの種類が違う・PCはx86,スマホはarm・機械語の種類・フォーマットが全然違う
RISCとCISC・アーキテクチャ設計の2つの思想・RISC:命令が固定長・CISC:命令が可変長
代表的なアーキテクチャ(ISA)・x86:CISC.皆さんのお手元のPCに多分入ってる.Core 〜とかRyzen 〜とか.・Arm:RISC(などと主張しており).スマホに入ってる.マイコンのCortex-M*とかもある.・RISC-V:RISC.UCB発のオープンなアーキテクチャ.最近はマイコンも出てきた.・MIPS:RISC.今はもう...・PowerPC:RISC.昔のAppleが使ってた.なんかPerseveranceに入ってるらしい.・SPARC:RISC. .京はSPARC64.・SuperH:RISC.日立製作所.組み込み向け.日本の人工衛星には結構入ってるらしい.・PDP-11:おぢさんがすきなやつ
64bitアーキテクチャ・「これは16bitアーキテクチャ,こっちは32bitアーキテクチャ」とか言ったりする・32bitアーキテクチャは汎用レジスタ・メモリアドレスのサイズが32bit・0xffffffff ≒ 4 * 1024 * 1024 * 1024・表現できるのが約4GB(4GiB) ・今は32/64bitアーキテクチャが主流
マルチタスク
ところで
選ばれたのは,Ryzen™でした・最近3600から3700Xに・個人でも8C16TのCPUが安価に手に入る時代...・すりっぱほしい
しかし実際は・プロセス数>>>>CPUコア数・無理があろうと思われます
同時に動いているとでも?それは残像だ・「時分割」処理・短い時間で区切って実行タスクを切り替える・適度に高速に切り替えられれば人間からは同時に動いているように見える・TSS:Time Shareing SystemCPU1時間→端末ゲ|ムブラウザカ|ネルゲ|ムブラウザ端末カ|ネルゲ|ム端末カ|ネルゲ|ムブラウザゲ|ム端末ゲ|ム
スケジューリング・プロセスには優先度がある・音の再生とかは優先度高め・niceコマンドで設定できる・プロセスの動作をいいかんじに管理しないといけない・スケジューラ(ディスパッチャ)・スケジューラの設計で性能が全然変わってくる
プロセスのメモリ・諸々のアドレス(開始アドレスとか)がまちまちだとダルい・関数呼び出し,アドレスを指定したジャンプ(絶対ジャンプ)がやりにくい・事前にアドレスを覚えておく or 相対ジャンプでなんとかする(位置独立コード)・他プロセスとの競合・そんなんやってらんねえ!!!!・じゃあどうするか? → 仮想メモリ
仮想メモリ・プロセスから見える仮想的なメモリ空間・プロセスからは0x00〜の広大なメモリが全部自分のものとして扱える・どうやって?・アドレス変換:仮想のアドレス → 実際のアドレス(物理アドレス)・実際の読み書きは物理アドレスで行われる・実際にプロセスからアクセスできるか(存在しているか,権限があるか)は別の話
物理アドレス・論理アドレス・プロセスは幻想に浸ったままアドレスを指定してメモリを読み書きできる物理アドレス:実際のアドレス論理アドレス:幻想のアドレス・物理アドレス ⇔ 論理アドレス が自動的に行われる・MMU:Memory Management Unit※x86の場合物理アドレス →リニアアドレス→論理アドレスプロセス俺はアドレス0x00にアクセスしている ...addr=0x00 MMU addr=0x1000メモリふふふ...こっちがアドレスを書き換えてるとも知らずに...
仮想メモリの種類・セグメンテーション:今はほとんど使われない・「〜から〜までのメモリ空間」みたいなのを設定・ページング・メモリを「ページ」という単位で切り分ける・それぞれのページを仮想メモリ空間の一部に対応させる・昔はバンク切り替えとかもあった(仮想記憶とは呼ばない)
ページング・1ページは4KBとか・メモリをページ毎に切る・論理アドレス空間内に割り当て・対応するページが存在する必要は無い・必要になってから物理ページを確保して対応させてもいい(デマンドページング)・対応するページが物理メモリ上にある必要は無い
ページングと2次記憶・メモリにアクセス→存在しない!?→ページイン存在しない!?:ページフォルト・メモリがいっぱい or 今これいらねえな→2次記憶に突っ込む2次記憶に突っ込む:ページアウト・うまいことやると高速化できる・やることはキャッシュの時と同じ・ただしこっちの制御はOS2次記憶メモリページページページページページインページアウト
メモリマップトファイル・”ド”の表記も多いけど”ト”の方が正しいとかなんとか(まあ元の発音からしてそう)・ファイルをメモリ領域のように扱える・ファイルは使ってたらそりゃメモリの中にあるやろがい・ファイルをプロセスのメモリ空間の中に(仮想的に)割り当てる・*addr = ‘A’; とかできる
共有メモリ・メモリを他のプロセスと共有できると → たのしい!!!!!!・同じページ(群)を復数のプロセスのメモリ空間内に割り当てる・巨大なデータを復数プロセスで扱いたいときとか・アクセス競合には気をつけよう!プロセスプロセスメモリ
アドレス空間の構造・text:プログラムそのもの.機械語・data:文字列,明示的に初期化される変数(グローバル変数や関数内のstatic変数)・bss:初期化の必要が無い変数.ELFなどではサイズ情報だけ(ロード時に確保される)・heap:動的に確保する領域・stack:関数呼び出しで積まれていくデータの領域.関数の引数やローカル変数.
プロセスのメモリ確保・text, data:そのままメモリに載せればいい・bss:サイズが確定している→ロード時にそれだけ確保してやればいい・stack:仮想アドレスのめちゃくちゃ後ろから始めれば使い切ることないやろ(鼻ホジ)・heap:システムコール呼ぶしかねえ
動的なメモリ確保・システムコール:brk/sbrk・mmapを使うことも・メモリを確保してプロセスの仮想メモリ空間内に割り当てる・やったね!・でも遅い(システムコールは大体遅い)
malloc()・libc(C言語の標準ライブラリ)の関数・malloc()で確保,free()で開放・内部でbrk/sbrk/mmapを呼んで大きめのメモリ領域を確保・細かい領域の割り当てはmalloc()が行う・高速!ヽ(゚∀゚)メ(゚∀゚)メ(゚∀゚)ノ・色々なアルゴリズム・実装がある(性能がめちゃくちゃ変わってくる)
いろいろなmalloc・glibc malloc: ふつうこれ・K&R malloc: いにしえ・dlmalloc: 移植性が高い(自作OSでお世話になる)・jemalloc: FreeBSDのlibc,マルチコア環境での性能,Facebook・tcmalloc: Google・mimalloc: Microsoft
プログラムができるまで
プログラムができるまでコンピュータ黎明期:機械語を書けばええ(パンチカード,コアロープメモリ,...)いま:int main(int argc, char **argv){ printf(“hello, world!”); return 0; }・ソースコード(人間が理解できるもの) → 機械語・コンパイル型言語:コンパイラで事前に機械語にしておく・インタプリタ型言語:インタプリタが解釈しながら実行・C/C++はコンパイル型言語・C/C++コンパイラ:gcc, clang, icc, aocc, ...
プリプロセス・#から始まるアレを処理するアレ:プリプロセッサディレクティブ マクロとも・基本的に単純な(ソースコードの)書き換え・#define -> 値に書き換えられる・#include -> ファイルの中身がそのまま展開される・gcc -E a.c / cpp a.c でプリプロセスだけできる・定数/関数の定義 ← 毎回同じものを定義するのはめんどい→ ヘッダとしてまとめて,プリプロセス時にそのまま展開してくれればいい→ #include Linux「えっ,マクロで関数が作れるのか.使いまくったろ」 C++「templateだいすき!ヘッダに実装を書くプラよ〜」ctags「ア゜」 C++20「C++の最新の妹です.兄が迷惑をおかけしました.moduleです.STLはまだです.」
コンパイル・匠の手によりC言語のソースコードをアセンブリに変換・匠:コンパイラ・アセンブリ言語:機械語と1対1対応BEFORE AFTER
アセンブル・アセンブリ言語のソースコードをバイナリ(機械語列)に変換・変換するプログラム:アセンブラ・バイナリフォーマット:ELF,COFF,a.out・ベタなバイナリは扱いにくいこれはディスアセンブルだけど...
リンク・ELFとか:機械語列以外のデータがいろいろ付いてる・大抵ソースコードのファイルは複数・後でくっつけないといけない・「のりしろ」に相当するデータ・リンク:「のりしろ」を見てファイルをくっつける・リンク前のELFなどのファイル(.o)をオブジェクト・ファイルとよぶ
ライブラリのリンク・みんなよく使う便利関数とかをライブラリとして切り出しておく・あとからリンクする→かんたんに過去の資産が使えてべんり!
ダイナミック(動的)リンク・ライブラリをリンクするとファイルサイズが大きくなる(それはそう)・めちゃくちゃ色々なプログラムが使うライブラリ・同じライブラリの分だけストレージが膨れ上がっていく・無駄すぎる・ライブラリは1つだけ入れておいて実行時にリンクしてしまえばいいのでは!?(天才)・リンクローダ/ローダ
どっちのリンク使えばええねん・大体動的リンクでいい・libcだって動的リンク・Golang「せやろか」
ダイナミックロード・ダイナミックリンクのようなことをプロセスが自分でやる・API:dlopen・インタプリタとか
プログラムができるまで:まとめCソ|スコ|ドアセンブリソ|スコ|ドCコンパイラ アセンブラ オブジェクトファイルリンカコンパイル元のCソースコードプリプロセスアセンブルCソ|スコ|ドアセンブリソ|スコ|ドCコンパイラ アセンブラ オブジェクトファイルコンパイル アセンブル静的ライブラリリンク実行バイナリファイルローダ動的リンクプロセスイメ|ジ動的ライブラリこれはメモリ上
プログラムができるまで:まとめCソ|スコ|ドアセンブリソ|スコ|ドCコンパイラ アセンブラ オブジェクトファイルリンカコンパイル元のCソースコードプリプロセスアセンブルCソ|スコ|ドアセンブリソ|スコ|ドCコンパイラ アセンブラ オブジェクトファイルコンパイル アセンブル静的ライブラリリンク実行バイナリファイルローダ動的リンクプロセスイメ|ジ動的ライブラリこれはメモリ上広義での「コンパイル」
まとめ・コンピュータはCPU・バス・メモリ・2次記憶・外部装置!w GPU...?知らない子ですね...・記憶装置:レジスタ,キャッシュ,メモリ,SSD,HDD,...・プログラム = 機械語の塊・コンピュータアーキテクチャには色々ある:x86,arm,RISC-V,PowerPC,MIPS,...・TSS:高速に処理を切り替えてマルチタスクを実現・仮想メモリ:アドレス変換で仮想的なプロセス専用のメモリを扱える・メモリ確保のAPI:システムコールで大きく確保,内部はmalloc/freeで管理・ソースコード→アセンブリ→オブジェクトファイル→実行形式ファイル・どうしてこの内容を1章にしてしまったんですかねぇ...