Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ふつうのLinuxプログラミング-プロセスとハードウェア

11cbdce6fef8ae507d51b96dca4a0ec5?s=47 sksat
June 09, 2020

 ふつうのLinuxプログラミング-プロセスとハードウェア

研究会の輪講でやったやつ.多少がんばった&評価も高めだったし使いまわせそうなので上げておく.

11cbdce6fef8ae507d51b96dca4a0ec5?s=128

sksat

June 09, 2020
Tweet

More Decks by sksat

Other Decks in Programming

Transcript

  1. #11 プロセスと ハードウェア B2 sksat

  2. おさらい:デジタルデータの表現 ・ビット(bit):情報の最小単位 ・0/1, yes/no, ON/OFF, +/-, N/S ・2進数の1桁 ・バイト(byte):8bit ・電子計算機ではデータをだいたい

    1〜数バイト単位で処理 ※実は1byte != 8bit.まあほとんどは8bitだが...(明示的に8bitだと言う場合はオクテット)
  3. コンピュータの構造(迫真) :thinking_think: ホンマか?

  4. 皆さんのお手元のThinkPad X230

  5. バラバラ事件 これを こうして こうじゃ

  6. マザーボード HDD メモリ CPU ファン

  7. メモリ ・データをたくさん置いておける (1,2,4,8,16,32,64...GB) ・1次記憶・主記憶 ・揮発性:電源切るとデータが消える ・アドレス(番地)を指定してデータを読み書き ・byteごと data 〜 0x0000

    0x0001 0x0002 0x0003 0x0004 0xffff 0xfffe 0xfffd 0xfffc 0xfffb
  8. メモリの読み書き 0xaf 0xbe 0xad 0xde 〜 0x0000 0x0001 0x0002 0x0003

    0x0004 0xffff 0xfffe 0xfffd 0xfffc 0xfffb CPU \addr=0x002のデータが1byteホシイ/ 0xab \addr=0xfffeに0xabを入れたい/ 0xad 0xab
  9. バス ・メモリ読み込み ・CPU:アドレス→アドレスバス ・メモリ:memory[addr] -> データバス ・メモリ書き込み ・CPU:アドレス→アドレスバス   書くデータ→データバス

    ・メモリ:memory[addr] <- データバス
  10. レジスタ ・CPUの中にも記憶領域がある ・レジスタは小さい(8〜64bit) ・メモリよりはるかに高速 ・メモリが作業机ならレジスタは手とか ・用途によって色々ある x86のレジスタ

  11. HDD/SSD ・2次記憶装置 ・不揮発性:電源切ってもデータが残る! ・OS/プログラムはここに保存 ・起動したらメモリに読み出してから動作 ・容量がデカい:数百GB〜数TB ・ブロックデバイス:「ブロック (512byteとか)」ごとに読み書き

  12. 記憶装置 記憶容量: 2次記憶(HDD/SSD) >>> 1次記憶(メモリ) >>>>>>> レジスタ ・ぜんぶ2次記憶でいいじゃん アクセス速度:レジスタ >>>>>>>  1次記憶 >>>> 2次記憶 ・それだと遅すぎる!!!!! ・レジスタはCPUの内部なので超高速 容量当たりの価格: レジスタ >>>  1次記憶 >>> 2次記憶

    ・でも2次記憶装置は安い ・2次記憶でもHDDは低速安価大容量,SSDは高速高価低容量(比較的)
  13. メモリのアクセス速度 ・メモリ:数十〜数百サイクル ・昔はCPUの動作速度が大したことなかったのでなんとかなった ・今:CPU「俺の”速さ”についてこられるかな?」 ・int a = 1 + 2; ← a,

    1, 2がレジスタかメモリ上かで数十〜数百倍速度が変わってしまう!? ・コンパイラの最適化でできる限りレジスタが使われるようになってる ・めでたしめでたし・・・とはいかない ・思い出すシリーズ:レジスタはクソ小さい ・じゃあどうすんねん
  14. キャッシュメモリ ・レジスタとメモリの中間の存在 ・もちろんメモリより低容量高価格だが高速 ・レジスタとメモリの間に挟む レジスタ キャッシュメモリ メモリ 3次キャッシュ 2次キャッシュ ・最近は2,

    3, 4次キャッシュなんてものも
  15. キャッシュメモリのしくみ ・発想:アクセスしそうなデータがいいかんじに キャッシュに載っているとうれしい! メモリ キャッシュメモリ addr=0x01, data=0xbe addr=0x03, data=0xde addr=0x05,

    data=0xba addr=0x09, data=0x1f 0x00: 0xef 0x01: 0xbe 0x02: 0xad 0x03: 0xde 0x04: 0xbe 0x05: 0xba 0x06: 0xfe 0x07: 0xca 0x08: 0x8b 0x09: 0x1f 0x0a: 0x00 addr=0x0a, data=0x00
  16. キャッシュメモリのしくみ(2) ・「アクセスしそうなデータ」とは? ・時間的局所性:同じアドレスに何度もアクセスする ・空間的局所性:アクセスしたところの近くにアクセスする ・方式がいくつかある:ダイレクトマップ,セットアソシアティブ,フルアソシアティブ

  17. デバイスとのやりとり ・入出力命令 ・入力:ちょっとN番のデバイスから値を取ってきて ・出力:ちょっとN番のデバイスにこれをセットして ・割り込み:デバイス「カンカンカンカン!!!入力!!!!おきてー!!!!!」 ・MMIO

  18. MMIO ・Memory Mapped I/O ・メモリとデバイスが繋がっている (!?) ・マイコンだとよくある ・PCだとVRAM(Video RAM) ・「(x=10,

    y=20)を紫に」とかを入出力命令でやってたら遅すぎる ・メモリの一部の領域がディスプレイと接続 VRAM 0xA0000 0xAFFFF
  19. 「プログラム」の正体 ・プログラムもデータ(バイナリ) ・CPUへの命令の集まり ・「機械語」

  20. 機械語 ・CPUはバカ ・int a = 1 + 2; ← こんなの難しすぎてわからん ・面接官「あなたは何ができるんですか?」

    ・CPU「計算がとても速くできるくらいです ...」 ・思い出すシリーズ:電子計算機 ・機械語:CPUが理解できる「言葉」 ・いくつか[要出典]の命令 ?
  21. 機械語の種類 ・算術命令:add, sub, mul, divなど ・add eax, 0x05:EAXレジスタの値に5を足す ・論理演算命令:and, or,

    not, xorなど ・ビットシフト ・メモリの読み書き ・入出力命令 ・ジャンプ命令:実行位置を変更
  22. プログラムの実行 ・電源投入 ・2次記憶→メモリ ・実行開始! ・どうやって?

  23. プログラム実行のしくみ add r0, 5 sub r1, [0x20] inc r1 add

    r0, r1 jmp -2 実行中 PC: 0x01 r0: 0x05 r1: 0x00 memory[0x20] = 0x03 メモリ
  24. プログラム実行のしくみ add r0, 5 sub r1, [0x20] inc r1 add

    r0, r1 jmp -2 実行中 PC: 0x02 r0: 0x02 r1: 0x00 memory[0x20] = 0x03 メモリ
  25. プログラム実行のしくみ add r0, 5 sub r1, [0x20] inc r1 add

    r0, r1 jmp -2 実行中 PC: 0x03 r0: 0x02 r1: 0x01 memory[0x20] = 0x03 メモリ
  26. プログラム実行のしくみ add r0, 5 sub r1, [0x20] inc r1 add

    r0, r1 jmp -2 実行中 PC: 0x04 r0: 0x03 r1: 0x01 memory[0x20] = 0x03 メモリ
  27. プログラム実行のしくみ add r0, 5 sub r1, [0x20] inc r1 add

    r0, r1 jmp -2 実行中 PC: 0x02 r0: 0x03 r1: 0x01 memory[0x20] = 0x03 メモリ
  28. プログラム実行のしくみ add r0, 5 sub r1, [0x20] inc r1 add

    r0, r1 jmp -2 実行中 PC: 0x03 r0: 0x03 r1: 0x02 memory[0x20] = 0x03 メモリ
  29. プログラムカウンタ ・「次に実行する命令」や「今実行している命令」の アドレスを指すレジスタ ・ジャンプ命令:プログラムカウンタの値を変える命令 絶対ジャンプ:アドレスを指定してジャンプする 相対ジャンプ:「N個前/後の命令」にジャンプする ・前にジャンプ → 繰り返し処理を実現 ・条件ジャンプ命令:「比較結果が0だったらジャンプ」 ・条件分岐の実現(条件分岐命令とも)

  30. 様々なコンピュータアーキテクチャ ・コンピュータの基本的な構造は大体同じ ・スマホもバラせばCPU・バス・メモリ・ディスク・外部装置 ・PCの/bin/bashをスマホにコピーしたら動くか?  → 動かない ・何故か? ・CPUの種類が違う ・PCはx86,スマホはarm ・機械語の種類・フォーマットが全然違う

  31. RISCとCISC ・アーキテクチャ設計の2つの思想 ・RISC:命令が固定長 ・CISC:命令が可変長

  32. 代表的なアーキテクチャ(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:おぢさんがすきなやつ
  33. 64bitアーキテクチャ ・「これは16bitアーキテクチャ,こっちは32bitアーキテクチャ」とか言ったりする ・32bitアーキテクチャは汎用レジスタ・メモリアドレスのサイズが 32bit ・0xffffffff ≒ 4 * 1024 *

    1024 * 1024 ・表現できるのが約4GB(4GiB) <- アドレス空間の大きさ ・今は32/64bitアーキテクチャが主流
  34. マルチタスク

  35. ところで

  36. 選ばれたのは,Ryzen™でした ・最近3600から3700Xに ・個人でも8C16TのCPUが安価に手に入る時代... ・すりっぱほしい

  37. しかし実際は ・プロセス数>>>>CPUコア数 ・無理があろうと思われます

  38. 同時に動いているとでも?それは残像だ ・「時分割」処理 ・短い時間で区切って実行タスクを切り替える ・適度に高速に切り替えられれば人間からは同時に動いているように見える ・TSS:Time Shareing System CPU1 時間→ 端

    末 ゲ | ム ブ ラ ウ ザ カ | ネ ル ゲ | ム ブ ラ ウ ザ 端 末 カ | ネ ル ゲ | ム 端 末 カ | ネ ル ゲ | ム ブ ラ ウ ザ ゲ | ム 端 末 ゲ | ム
  39. スケジューリング ・プロセスには優先度がある ・音の再生とかは優先度高め ・niceコマンドで設定できる ・プロセスの動作をいいかんじに管理しないといけない ・スケジューラ(ディスパッチャ) ・スケジューラの設計で性能が全然変わってくる

  40. プロセスのメモリ ・諸々のアドレス(開始アドレスとか)がまちまちだとダルい ・関数呼び出し,アドレスを指定したジャンプ (絶対ジャンプ)がやりにくい ・事前にアドレスを覚えておく or 相対ジャンプでなんとかする (位置独立コード) ・他プロセスとの競合 ・そんなんやってらんねえ!!!!

    ・じゃあどうするか? → 仮想メモリ
  41. 仮想メモリ ・プロセスから見える仮想的なメモリ空間 ・プロセスからは0x00〜の広大なメモリが全部自分のものとして扱える ・どうやって? ・アドレス変換:仮想のアドレス  → 実際のアドレス(物理アドレス) ・実際の読み書きは物理アドレスで行われる ・実際にプロセスからアクセスできるか (存在しているか,権限があるか )は別の話

  42. 物理アドレス・論理アドレス ・プロセスは幻想に浸ったままアドレスを指定してメモリを読み書きできる 物理アドレス:実際のアドレス 論理アドレス:幻想のアドレス ・物理アドレス ⇔ 論理アドレス が自動的に行われる ・MMU:Memory Management Unit ※x86の場合物理アドレス →リニアアドレス→論理アドレス

    プロセス 俺はアドレス0x00にアクセスしている ... addr=0x00 MMU addr=0x1000 メモリ ふふふ...こっちがアドレスを 書き換えてるとも知らずに ...
  43. 仮想メモリの種類 ・セグメンテーション:今はほとんど使われない ・「〜から〜までのメモリ空間」みたいなのを設定 ・ページング ・メモリを「ページ」という単位で切り分ける ・それぞれのページを仮想メモリ空間の一部に対応させる ・昔はバンク切り替えとかもあった (仮想記憶とは呼ばない)

  44. ページング ・1ページは4KBとか ・メモリをページ毎に切る ・論理アドレス空間内に割り当て ・対応するページが存在する必要は無い ・必要になってから物理ページを確保して対応させてもいい (デマンドページング) ・対応するページが物理メモリ上にある必要は 無い

  45. ページングと2次記憶 ・メモリにアクセス→存在しない!?→ページイン 存在しない!?:ページフォルト ・メモリがいっぱい or 今これいらねえな→2次記憶に突っ込む 2次記憶に突っ込む:ページアウト ・うまいことやると高速化できる ・やることはキャッシュの時と同じ ・ただしこっちの制御はOS

    2次記憶 メモリ ページ ページ ページ ページ ページイン ページアウト
  46. メモリマップトファイル ・”ド”の表記も多いけど”ト”の方が正しいとかなんとか (まあ元の発音からしてそう ) ・ファイルをメモリ領域のように扱える ・ファイルは使ってたらそりゃメモリの中にあるやろがい ・ファイルをプロセスのメモリ空間の中に(仮想的に)割り当てる ・*addr = ‘A’;

    とかできる
  47. 共有メモリ ・メモリを他のプロセスと共有できると  → たのしい!!!!!! ・同じページ(群)を復数のプロセスのメモリ空間内に割り当てる ・巨大なデータを復数プロセスで扱いたいときとか ・アクセス競合には気をつけよう! プロセス プロセス メモリ

  48. アドレス空間の構造 ・text:プログラムそのもの.機械語 ・data:文字列,明示的に初期化される変数 (グローバル変数や関数内の static変数) ・bss:初期化の必要が無い変数. ELFなどではサイズ情報だけ(ロード時に確保される) ・heap:動的に確保する領域 ・stack:関数呼び出しで積まれていくデータの領域.関数の引数やローカル変数.

  49. プロセスのメモリ確保 ・text, data:そのままメモリに載せればいい ・bss:サイズが確定している→ロード時にそれだけ確保してやればいい ・stack:仮想アドレスのめちゃくちゃ後ろから始めれば使い切ることないやろ (鼻ホジ) ・heap:システムコール呼ぶしかねえ

  50. 動的なメモリ確保 ・システムコール:brk/sbrk ・mmapを使うことも ・メモリを確保してプロセスの仮想メモリ空間内に割り当てる ・やったね! ・でも遅い(システムコールは大体遅い )

  51. malloc() ・libc(C言語の標準ライブラリ)の関数 ・malloc()で確保,free()で開放 ・内部でbrk/sbrk/mmapを呼んで大きめのメモリ領域を確保 ・細かい領域の割り当ては malloc()が行う ・高速!ヽ(゚∀゚)メ(゚∀゚)メ(゚∀゚)ノ ・色々なアルゴリズム・実装がある (性能がめちゃくちゃ変わってくる )

  52. いろいろなmalloc ・glibc malloc: ふつうこれ ・K&R malloc: いにしえ ・dlmalloc: 移植性が高い(自作OSでお世話になる) ・jemalloc:

    FreeBSDのlibc,マルチコア環境での性能, Facebook ・tcmalloc: Google ・mimalloc: Microsoft
  53. プログラムができるまで

  54. プログラムができるまで コンピュータ黎明期:機械語を書けばええ(パンチカード,コアロープメモリ, ...) いま:int main(int argc, char **argv){ printf(“hello, world!”);

    return 0; } ・ソースコード(人間が理解できるもの) → 機械語 ・コンパイル型言語:コンパイラで事前に機械語にしておく ・インタプリタ型言語:インタプリタが解釈しながら実行 ・C/C++はコンパイル型言語 ・C/C++コンパイラ:gcc, clang, icc, aocc, ...
  55. プリプロセス ・#から始まるアレを処理する アレ:プリプロセッサディレクティブ マクロとも ・基本的に単純な(ソースコードの)書き換え ・#define -> 値に書き換えられる ・#include -> ファイルの中身がそのまま展開される

    ・gcc -E a.c / cpp a.c でプリプロセスだけできる ・定数/関数の定義 ← 毎回同じものを定義するのはめんどい → ヘッダとしてまとめて,プリプロセス時にそのまま展開してくれればいい → #include Linux「えっ,マクロで関数が作れるのか.使いまくったろ」  C++「templateだいすき!ヘッダに実装を書くプラよ〜」 ctags「ア゜」 C++20「C++の最新の妹です.兄が迷惑をおかけしました. moduleです.STLはまだです.」
  56. コンパイル ・匠の手によりC言語のソースコードをアセンブリに変換 ・匠:コンパイラ ・アセンブリ言語:機械語と 1対1対応 BEFORE AFTER

  57. アセンブル ・アセンブリ言語のソースコードをバイナリ (機械語列)に変換 ・変換するプログラム:アセンブラ ・バイナリフォーマット:ELF,COFF,a.out ・ベタなバイナリは扱いにくい これはディスアセンブルだけど ...

  58. リンク ・ELFとか:機械語列以外のデータがいろいろ付いてる ・大抵ソースコードのファイルは複数 ・後でくっつけないといけない ・「のりしろ」に相当するデータ ・リンク:「のりしろ」を見てファイルをくっつける ・リンク前のELFなどのファイル(.o)をオブジェクト・ファイルとよぶ

  59. ライブラリのリンク ・みんなよく使う便利関数とかをライブラリとして切り出しておく ・あとからリンクする→かんたんに過去の資産が使えてべんり!

  60. ダイナミック(動的)リンク ・ライブラリをリンクするとファイルサイズが大きくなる (それはそう) ・めちゃくちゃ色々なプログラムが使うライブラリ ・同じライブラリの分だけストレージが膨れ上がっていく ・無駄すぎる ・ライブラリは1つだけ入れておいて実行時にリンクしてしまえばいいのでは!? (天才) ・リンクローダ/ローダ

  61. どっちのリンク使えばええねん ・大体動的リンクでいい ・libcだって動的リンク ・Golang「せやろか」

  62. ダイナミックロード ・ダイナミックリンクのようなことをプロセスが自分でやる ・API:dlopen ・インタプリタとか

  63. プログラムができるまで:まとめ C ソ | ス コ | ド ア セン

    ブリ ソ | ス コ | ド Cコンパイラ アセンブラ オ ブ ジェ クト ファ イ ル リンカ コンパイル 元のCソースコード プ リ プ ロ セ ス アセンブル C ソ | ス コ | ド ア セン ブリ ソ | ス コ | ド Cコンパイラ アセンブラ オ ブ ジェ クト ファ イ ル コンパイル アセンブル 静的ライブラリ リンク 実 行 バ イ ナ リ フ ァ イ ル ローダ 動的リンク プ ロ セ ス イ メ | ジ 動的ライブラリ これはメモリ上
  64. プログラムができるまで:まとめ C ソ | ス コ | ド ア セン

    ブリ ソ | ス コ | ド Cコンパイラ アセンブラ オ ブ ジェ クト ファ イ ル リンカ コンパイル 元のCソースコード プ リ プ ロ セ ス アセンブル C ソ | ス コ | ド ア セン ブリ ソ | ス コ | ド Cコンパイラ アセンブラ オ ブ ジェ クト ファ イ ル コンパイル アセンブル 静的ライブラリ リンク 実 行 バ イ ナ リ フ ァ イ ル ローダ 動的リンク プ ロ セ ス イ メ | ジ 動的ライブラリ これはメモリ上 広義での「コンパイル」
  65. まとめ ・コンピュータはCPU・バス・メモリ・2次記憶・外部装置!w   GPU...?知らない子ですね ... ・記憶装置:レジスタ,キャッシュ,メモリ, SSD,HDD,... ・プログラム = 機械語の塊 ・コンピュータアーキテクチャには色々ある: x86,arm,RISC-V,PowerPC,MIPS,... ・TSS:高速に処理を切り替えてマルチタスクを実現 ・仮想メモリ:アドレス変換で仮想的なプロセス専用のメモリを扱える

    ・メモリ確保のAPI:システムコールで大きく確保,内部は malloc/freeで管理 ・ソースコード→アセンブリ→オブジェクトファイル→実行形式ファイル ・どうしてこの内容を1章にしてしまったんですかねぇ ...