8.5 זכרון וירטואלי בחומרה תרגול
תרגול - זכרון וירטואלי בחומרה¶
תרגיל 1 - חישוב כתובת פיזית¶
נתונה כתובת וירטואלית: 0x00007F5A3B2C1D08
- פרקו את הכתובת לחמישה חלקים: Sign Extension, PML4 Index, PDPT Index, PD Index, PT Index, Offset. רשמו כל חלק בדצימלי ובהקסדצימלי.
רמז: המרו להקסדצימלי ופרקו לפי הביטים:
- ביטים 47-39: PML4 Index
- ביטים 38-30: PDPT Index
- ביטים 29-21: PD Index
- ביטים 20-12: PT Index
- ביטים 11-0: Offset
-
נניח שה-page table walk מצא שהדף ממופה למסגרת פיזית (page frame)
0x00000001234AB. מהי הכתובת הפיזית הסופית? -
אם במקום דף רגיל (4KB) היינו משתמשים בדף ענק (2MB), איזה חלקים של הכתובת הוירטואלית היו משתנים? מהו הoffset בדף ענק?
תרגיל 2 - התנהגות TLB¶
נתון TLB עם 4 כניסות (fully associative, LRU replacement).
תוכנית ניגשת לכתובות הבאות (דף = 4KB = 0x1000):
- מלאו טבלה:
| גישה | כתובת | מספר דף (VPN) | TLB Hit/Miss | מצב TLB אחרי (VPNs) |
|---|---|---|---|---|
| 1 | 0x1000 | 1 | ? | ? |
| 2 | 0x1004 | 1 | ? | ? |
| ... |
-
כמה TLB hits וכמה misses?
-
כמה page table walks היו נדרשים? כל walk הוא 4 גישות לזכרון - כמה גישות נוספות בסה"כ?
-
אם הדפים היו huge pages (2MB = 0x200000), האם היו פחות misses? חשבו - איזה כתובות עכשיו על אותו דף?
תרגיל 3 - תקורת טבלאות דפים¶
נניח תהליך שמשתמש ב-1GB של זכרון וירטואלי רציף (כתובות 0x0 עד 0x3FFFFFFF).
- כמה דפים של 4KB צריך?
- כמה כניסות ב-PT (Page Table) צריך? כמה טבלאות PT?
- כמה כניסות ב-PD (Page Directory) צריך? כמה טבלאות PD?
- כמה כניסות ב-PDPT צריך?
- כמה כניסות ב-PML4 צריך?
- חשבו את הזכרון הכולל שטבלאות הדפים תופסות. כמה אחוז מה-1GB?
רמז: כל טבלה היא עמוד (4KB) עם 512 כניסות של 8 בתים.
- חזרו על החישוב עם דפים ענקיים של 2MB. כמה זכרון חוסכים?
תרגיל 4 - השוואת דפים רגילים מול ענקיים¶
כתבו תוכנית שמקצה מערך גדול (1GB) וסורקת אותו ברצף. השוו בין שלוש גרסאות:
גרסה 1 - דפים רגילים:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define SIZE (1024L * 1024 * 1024) // 1GB
int main() {
char *buf = malloc(SIZE);
if (!buf) { perror("malloc"); return 1; }
// חימום - גרום לכל הדפים להיות ממופים
memset(buf, 0, SIZE);
struct timespec start, end;
// סריקה רציפה
clock_gettime(CLOCK_MONOTONIC, &start);
long sum = 0;
for (long i = 0; i < SIZE; i += 4096) { // קפיצות של דף
sum += buf[i];
}
clock_gettime(CLOCK_MONOTONIC, &end);
double elapsed = (end.tv_sec - start.tv_sec)
+ (end.tv_nsec - start.tv_nsec) / 1e9;
printf("regular pages, stride 4096: %.6f sec (sum=%ld)\n",
elapsed, sum);
// סריקה רציפה עם stride קטן
clock_gettime(CLOCK_MONOTONIC, &start);
sum = 0;
for (long i = 0; i < SIZE; i += 64) { // קפיצות של cache line
sum += buf[i];
}
clock_gettime(CLOCK_MONOTONIC, &end);
elapsed = (end.tv_sec - start.tv_sec)
+ (end.tv_nsec - start.tv_nsec) / 1e9;
printf("regular pages, stride 64: %.6f sec (sum=%ld)\n",
elapsed, sum);
free(buf);
return 0;
}
-
הריצו את התוכנית. מדוע סריקה עם stride של 4096 (גודל דף) איטית יותר יחסית מ-stride 64? (רמז: חשבו על TLB misses)
-
חשבו: בסריקה עם stride 4096, כמה TLB misses מתרחשים? (1GB / 4KB = ?)
-
(אופציונלי - דורש הרשאות root) הריצו עם
madvise(buf, SIZE, MADV_HUGEPAGE)אחרי ה-malloc כדי לבקש huge pages, ובדקו אם הביצועים משתפרים. -
הסבירו: למה בסיסי נתונים (כמו PostgreSQL) מוגדרים לרוב עם huge pages? אילו מאפיינים של בסיסי נתונים הופכים את זה ליעיל?