More Related Content Similar to 仮想記憶入門 BSD-4.3を例題に Similar to 仮想記憶入門 BSD-4.3を例題に (20) More from magoroku Yamamoto More from magoroku Yamamoto (20) 仮想記憶入門 BSD-4.3を例題に2. 今日の内容
• 過去:UNIX v6, 未来:4.4BSDとの関連
• 仮想記憶の空間構成
• スワッピングとページング
• 4.3BSDを例にした仮想記憶管理の解析
• 参考資料
– Freebsd-53-kernel-mm.pptx 七誌さん
9. 4.3BSDを理解する意味
• UNIXの系譜では第2世代の最後
– 第一世代 UNIX v{6|7} 切り替え型
– 第二世代 UNIX 32v~4.3BSD 常駐型
– 第三世代 Mach, 4.4BSD他 +広義の単一レベル記憶
• 仮想空間にvnode,offsetで表現可能なファイルをマップ可能になる
• 次の事項の理解に有用
– MMUの仕組み
– ページングの原理と実装
– 実メモリ管理
• UNIX v{6|7}の構成の変化は少なく連続性がある
– ファイル構成・関数構成
20. スワッピング
• スワップアウト
– 最も優先度の低いプログラムを選択し
– プログラムをスケジュールの対象から外す
– プログラムのメモリ全体をスワップデバイスに退避(write)
• スワップイン
– 実行するプロセスがスワップアウトさせていたら
– メモリを確保-不足したら他のプロセスをスワップアウト
– スワップデバイスに退避してあるメモリイメージをメモリに復元
(read)
– プログラムをスケジュールの対象に含める
• スワッピングとページングは明確に区別せずに使われる
場合があるので注意
22. ページング
• ページアウト
1. メモリが不足
2. 最近使われていない物理メモリ(ページ)を特定
3. 物理メモリが仮想メモリとして利用されていたら変換対象から
外す
4. 物理メモリをページングデバイスに退避
• ページイン
1. 割り当て済の仮想メモリをプログラムが参照
2. アドレス変換例外で割り込みが発生しOSに制御が移る
3. OSが該当プロセス+アドレスから退避済の物理メモリ(ページ)
を特定する
4. 物理メモリを読み込んで仮想メモリから変換可能とする
5. 割り込みから復帰
23. ページングの特徴
• 一般的な運用では
– 仮想空間の総量 > 物理メモリ
– 物理メモリの奪い合い
– メモリ参照に局所性が有る場合
• ゆっくり奪い合う→変換例外とその対応のコストは無視できる
– メモリ参照に局所性が無い場合
• はげしく奪い合う→変換例外とその対応コストが無視できない
• 局所的な参照を前提として使われていないメモリの特
定が必要
– 最近利用されていないメモリは将来も利用されない可能
性が高い
– どうやって?
24. LRU - Least Recently Used
• 「最近使われていないメモリは、将来も使わ
れない可能性が高い」事を前提とする
• メモリの参照頻度を記録して、最近使われて
いないメモリを予想する
– 近年のCPUは参照の有無をアドレス変換表にHW
が記録する
• X86, ARMなど (除くVAX-11)
• 多くは1bit(参照の有無)のみを記録
27. 4.3BSD VAX-11の空間構成
• 32bit = 4Gbyteの空間を4分割(4セグメント)
unused
kernel
User stack
User Text
User Data
0x4000.000
0x0000.000
0x8000.000
0xC000.000
0xFFFF.FFFF
P0
P1
System
Reserved
• P0,P1 にUserプログラム
• P1にはKernel Stack・Uも配置
• System リージョンにカーネルを配置
• copy{in|out}は同一空間の転送
1142 /*
1143 * Copy specified amount of data from user space into the kernel
1144 * Copyin(from, to, len)
1145 * r1 == from (user source address)
1146 * r3 == to (kernel destination address)
1147 * r5 == length
1148 */
1149 .align 1
1150 JSBENTRY(Copyin, R1|R3|R5)
1151 cmpl r5,$(NBPG*CLSIZE) # probing one page or less ?
1152 bgtru 1f # no
1153 prober $3,r5,(r1) # bytes accessible ?
1154 beql ersb # no
1155 movc3 r5,(r1),(r3)
1156 /* clrl r0 # redundant */
1157 rsb
30. セグメント用のレジスタ
• root/machine/mtpr.h
18 #define P0BR 0x8 /* p0 base register */
19 #define P0LR 0x9 /* p0 length register */
20 #define P1BR 0xa /* p1 base register */
21 #define P1LR 0xb /* p1 length register */
22 #define SBR 0xc /* system segment base register */
23 #define SLR 0xd /* system segment length register */
unused
kernel
User stack
Kernal stack
User Text
User Data
P0BR
P1BR
SBR
P0LR
P1LR
SLR
31. セグメントレジスタの設定
• root/GENERIC/sys/vmmac.h
88 #define setp0br(x) (u.u_pcb.pcb_p0br = (x), mtpr(P0BR, x))
89 #define setp0lr(x) (u.u_pcb.pcb_p0lr = ¥
90 (x) | (u.u_pcb.pcb_p0lr & AST_CLR), ¥
91 mtpr(P0LR, x))
92 #define setp1br(x) (u.u_pcb.pcb_p1br = (x), mtpr(P1BR, x))
93 #define setp1lr(x) (u.u_pcb.pcb_p1lr = (x), mtpr(P1LR, x))
94 #define initp1br(x) ((x) - P1PAGES)
UNIX v6がuにアドレス変換レジスタの内容を持っていたのと同じ
33. 構造:cmap
• h/cmap.h
27 struct cmap
28 {
29 unsigned short c_next, /* index of next free list entry */
30 c_prev, /* index of previous free list entry */
31 c_hlink; /* hash link for <blkno,mdev> */
32 unsigned short c_ndx; /* index of owner proc or text */
33 unsigned int c_page:21, /* virtual page number in segment */
34 c_lock:1, /* locked for raw i/o or pagein */
35 c_want:1, /* wanted */
36 c_intrans:1, /* intransit bit */
37 c_free:1, /* on the free list */
38 c_gone:1, /* associated page has been released */
39 c_type:2, /* type CSYS or CTEXT or CSTACK or CDATA */
40 :4, /* to longword boundary */
41 c_blkno:24, /* disk block this is a copy of */
42 c_mdev:8; /* which mounted dev this is from */
43 };
34. Cmapの初期化
• root/vax/machdep.c
105 v = (caddr_t)(0x80000000 | (firstaddr * NBPG));
106 #define valloc(name, type, num) ¥
107 (name) = (type *)v; v = (caddr_t)((name)+(num))
108 #define valloclim(name, type, num, lim) ¥
109 (name) = (type *)v; v = (caddr_t)((lim) = ((name)+(num)))
110 valloclim(inode, struct inode, ninode, inodeNINODE);
111 valloclim(file, struct file, nfile, fileNFILE);
112 valloclim(proc, struct proc, nproc, procNPROC);
113 valloclim(text, struct text, ntext, textNTEXT);
114 valloc(cfree, struct cblock, nclist);
115 valloc(callout, struct callout, ncallout);
116 valloc(swapmap, struct map, nswapmap = nproc * 2);
117 valloc(argmap, struct map, ARGMAPSIZE);
118 valloc(kernelmap, struct map, nproc);
119 valloc(mbmap, struct map, nmbclusters/4);
120 valloc(namecache, struct namecache, nchsize);
177 ncmap = (maxmem*NBPG - ((int)(v + bufpages*CLBYTES) &~ 0x80000000)) /
178 (CLBYTES + sizeof(struct cmap)) + 2;
179 valloclim(cmap, struct cmap, ncmap, ecmap);
パラメタを参照して各構造を
割り当て(v6では配列だった)
現在のvからmaxmemまでの
アドレスに応じたcmapを確保
35. ページの割り当て:memall()
• sys/vm_mem.c
159 /*
160 * Allocate memory -
161 *
162 * The free list appears as a doubly linked list
163 * in the core map with cmap[0] serving as a header.
164 */
165 memall(pte, size, p, type)
/* */
166 register struct pte *pte;
167 int size;
168 struct proc *p;
169 {
186 for (i = size; i > 0; i -= CLSIZE) {
210 case CDATA:
211 rpte = dptopte(rp, c->c_page);
212 break;
213
222 switch (type) {
233 case CDATA:
234 c->c_page = vtodp(p, ptetov(p, pte));
235 c->c_ndx = p->p_ndx;
236 break;
272 pf = cmtopg(curpos);
273 for (j = 0; j < CLSIZE; j++)
274 *(int *)pte++ = pf++;
275 c->c_free = 0;
276 c->c_gone = 0;
277 if (c->c_intrans || c->c_want)
278 panic("memall intrans|want");
279 c->c_lock = 1;
280 c->c_type = type;
281 }
282 splx(s);
283 return (size);
284 }
37. 構造:pte
• vax/pte.h
20 struct pte
21 {
22 unsigned int pg_pfnum:21, /* core page frame number or 0 */
23 :2,
24 pg_vreadm:1, /* modified since vread (or with _m) */
25 pg_swapm:1, /* have to write back to swap */
26 pg_fod:1, /* is fill on demand (=0) */
27 pg_m:1, /* hardware maintained modified bit */
28 pg_prot:4, /* access control */
29 pg_v:1; /* valid bit */
30 };
pfnumV prot M 0 soft
59 #define PG_NOACC 0
60 #define PG_KW 0x10000000
61 #define PG_KR 0x18000000
62 #define PG_UW 0x20000000
63 #define PG_URKW 0x70000000
64 #define PG_URKR 0x78000000
38. 処理:pageout()
• sys/vm_page.c +696
696 loop:
705 (void) splbio();
706 if (bclnlist != NULL) {
707 (void) spl0();
708 cleanup();
709 goto loop;
710 }
711 sleep((caddr_t)&proc[2], PSWP+1);
712 (void) spl0();
713 count = 0;
714 pushes = 0;
715 while (nscan < desscan && freemem < lotsfree) {
720 if (checkpage(fronthand, FRONT))
721 count = 0;
722 if (checkpage(backhand, BACK))
723 count = 0;
724 cnt.v_scan++;
725 nscan++;
726 if (++fronthand >= maxhand) {
727 fronthand = 0;
728 cnt.v_rev++;
729 if (count > 2) {
735 goto loop;
736 }
737 count++;
738 }
739 if (++backhand >= maxhand)
740 backhand = 0;
741 }
742 goto loop;
proc[2]はpager,メモリが不足すると
wakeupされる
Fronthand.backhandを++しながら一
定のpageをスキャンする
fronthand
backhand
maxhand/0
39. cmap[hand]がcheckの対象
処理:checkpage()
• sys/vm_page.c +774
774 c = &cmap[hand];
775 if (c->c_lock || c->c_free)
776 return (0);
777 switch (c->c_type) {
779 case CSYS:
780 return (0);
782 case CTEXT:
783 xp = &text[c->c_ndx];
784 rp = xp->x_caddr;
785 v = tptov(rp, c->c_page);
786 pte = tptopte(rp, c->c_page);
787 break;
789 case CDATA:
790 case CSTACK:
791 rp = &proc[c->c_ndx];
792 while (rp->p_flag & SNOVM)
793 rp = rp->p_xlink;
794 xp = rp->p_textp;
795 if (c->c_type == CDATA) {
796 v = dptov(rp, c->c_page);
797 pte = dptopte(rp, c->c_page);
798 } else {
799 v = sptov(rp, c->c_page);
800 pte = sptopte(rp, c->c_page);
801 }
802 break;
803 }
cmapのc_typeに用途が記録
実メモリcmap[hand]が参照している
pteを特定
41. 処理:checkpage()
• sys/vm_page.c +813
813 if (pte->pg_v) {
814 if (whichhand == BACK)
815 return(0);
816 pte->pg_v = 0;
817 if (anycl(pte, pg_m))
818 pte->pg_m = 1;
819 distcl(pte);
820 if (c->c_type == CTEXT)
821 distpte(xp, (unsigned)vtotp(rp, v), pte);
822 if ((rp->p_flag & (SSEQL|SUANOM)) == 0 &&
823 rp->p_rssize <= rp->p_maxrss)
824 return (0);
825 }
42. 処理:checkpage()
• sys/vm_page.c +850
850 if (dirtycl(pte)) {
856 if (rp->p_flag & (SLOCK|SWEXIT))
857 return (0);
858 /*
859 * Limit pushes to avoid saturating
860 * pageout device.
861 */
862 if (pushes > maxpgio / RATETOSCHEDPAGING)
863 return (0);
864 pushes++;
882 loop2:
883 (void) splbio();
884 if (bclnlist != NULL) {
885 (void) spl0();
886 cleanup();
887 goto loop2;
888 }
889 if (bswlist.av_forw == NULL) {
890 bswlist.b_flags |= B_WANTED;
891 sleep((caddr_t)&proc[2], PSWP+2);
892 (void) spl0();
900 goto top;
901 }
902 (void) spl0();
904 MLOCK(c);
905 uaccess(rp, Pushmap, &pushutl);
909 pte->pg_m = 0;
910 distcl(pte);
911 if (c->c_type == CTEXT) {
912 xp->x_poip++;
913 distpte(xp, (unsigned)vtotp(rp, v), pte);
914 } else
915 rp->p_poip++;
916 v = kluster(rp, v, pte, B_WRITE, &klsize, klout,
(daddr_t)0);
917 if (klsize == 0)
918 panic("pageout klsize");
919 daddr = vtod(rp, v, &pushutl.u_dmap,
&pushutl.u_smap);
920 (void)swap(rp, daddr, ptob(v), klsize * ctob(CLSIZE),
921 B_WRITE, B_DIRTY, swapdev, pte->pg_pfnum);
929 return (1); /* well, it'll be free soon */
930
931 }
43. アドレス変換例外
• machine/trap.c
58 trap(sp, type, code, pc, psl)
59 int sp, type;
60 unsigned code;
61 int pc, psl;
73 switch (type) {
75 default:
76 printf("trap type %d, code = %x, pc = %x¥n", type, code, pc);
77 type &= ~USER;
78 if ((unsigned)type < TRAP_TYPES)
79 panic(trap_type[type]);
80 panic("trap");
82 case T_PROTFLT+USER: /* protection fault */
83 i = SIGBUS;
84 break;
119
120 case T_PAGEFLT: /* allow page faults in kernel mode */
121 case T_PAGEFLT+USER: /* page fault */
122 i = u.u_error;
123 pagein(code, 0);
124 u.u_error = i;
125 if (type == T_PAGEFLT)
126 return;
127 goto out;
44. 処理:pagein()
• sys/vm_page.c
68 pagein(virtaddr, dlyu)
100 vsave = v = clbase(btop(virtaddr));
101 p = u.u_procp;
108 pte = vtopte(p, v);
198 bnswap = bncache = bn = vtod(p, v, &u.u_dmap,
&u.u_smap);
199 dev = swapdev;
219 opte = *pte;
311 pte->pg_prot = opte.pg_prot;
314 distcl(pte);
377 /*
378 * Fill from swap area. Try to find adjacent
379 * pages to bring in also.
380 */
381 v = kluster(p, v, pte, B_READ, &klsize,
382 (type == CTEXT) ? kltxt :
383 ((p->p_flag & SSEQL) ? klseql : klin), bn);
384 splx(sk);
385 /* THIS COULD BE COMPUTED INCREMENTALLY... */
386 bncache = bn = vtod(p, v, &u.u_dmap, &u.u_smap);
387 }
388
389 distcl(pte);
390 swerror = swap(p, bn, ptob(v), klsize * ctob(CLSIZE),
391 B_READ, B_PGIN, dev, 0);
!NOTICE!
45. 第三世代UNIX
• Mach由来の仮想記憶に置き換え
– 仮想記憶は
• f(vnode, offset) → (p, vaddr)
• f(p, vaddr) → (vnode,offset)
– 広範囲に影響
• 共用テキスト
• 共有メモリ
• バッファキャッシュ
• Demand loading
• ForkのCopy On Write化
• Linux,Solaris,BSDで実装は異なるが、考え方は同じ