לדלג לתוכן

8.5 - זכרון וירטואלי בחומרה - תרגול

תרגול - זכרון וירטואלי בחומרה

תרגיל 1 - חישוב כתובת פיזית

נתונה כתובת וירטואלית: 0x00007F5A3B2C1D08

  1. פרקו את הכתובת לחמישה חלקים: 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

  1. נניח שה-page table walk מצא שהpage ממופה למסגרת פיזית (page frame) 0x00000001234AB. מהי הכתובת הפיזית הסופית?

  2. אם במקום page רגיל (4KB) היינו משתמשים בpage ענק (2MB), איזה חלקים של הכתובת הוירטואלית היו משתנים? מהו הoffset בpage ענק?


תרגיל 2 - התנהגות TLB

נתון TLB עם 4 כניסות (fully associative, LRU replacement).

תוכנית ניגשת לכתובות הבאות (page = 4KB = 0x1000):

0x1000, 0x1004, 0x2000, 0x3000, 0x1008, 0x4000, 0x5000, 0x1000, 0x2000
  1. מלאו טבלה:
גישה כתובת מספר page (VPN) TLB Hit/Miss מצב TLB אחרי (VPNs)
1 0x1000 1 ? ?
2 0x1004 1 ? ?
...
  1. כמה TLB hits וכמה misses?

  2. כמה page table walks היו נדרשים? כל walk הוא 4 גישות לזכרון - כמה גישות נוספות בסה"כ?

  3. אם הpages היו huge pages (2MB = 0x200000), האם היו פחות misses? חשבו - איזה כתובות עכשיו על אותו page?


תרגיל 3 - תקורת טבלאות pages

נניח process שמשתמש ב-1GB של זכרון וירטואלי רציף (כתובות 0x0 עד 0x3FFFFFFF).

  1. כמה pages של 4KB צריך?
  2. כמה כניסות ב-PT (Page Table) צריך? כמה טבלאות PT?
  3. כמה כניסות ב-PD (Page Directory) צריך? כמה טבלאות PD?
  4. כמה כניסות ב-PDPT צריך?
  5. כמה כניסות ב-PML4 צריך?
  6. חשבו את הזכרון הכולל שטבלאות הpages תופסות. כמה אחוז מה-1GB?

רמז: כל טבלה היא עמוד (4KB) עם 512 כניסות של 8 בתים.

  1. חזרו על החישוב עם pages ענקיים של 2MB. כמה זכרון חוסכים?

תרגיל 4 - השוואת pages רגילים מול ענקיים

כתבו תוכנית שמקצה מערך גדול (1GB) וסורקת אותו ברצף. השוו בין שלוש גרסאות:

גרסה 1 - pages רגילים:

#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; }

    // warm-up - force all pages to be mapped
    memset(buf, 0, SIZE);

    struct timespec start, end;

    // sequential scan
    clock_gettime(CLOCK_MONOTONIC, &start);
    long sum = 0;
    for (long i = 0; i < SIZE; i += 4096) {  // jumps of a page
        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);

    // sequential scan with small stride
    clock_gettime(CLOCK_MONOTONIC, &start);
    sum = 0;
    for (long i = 0; i < SIZE; i += 64) {  // jumps of a 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;
}

  1. הריצו את התוכנית. מדוע סריקה עם stride של 4096 (גודל page) איטית יותר יחסית מ-stride 64? (רמז: חשבו על TLB misses)

  2. חשבו: בסריקה עם stride 4096, כמה TLB misses מתרחשים? (1GB / 4KB = ?)

  3. (אופציונלי - דורש הרשאות root) הריצו עם madvise(buf, SIZE, MADV_HUGEPAGE) אחרי ה-malloc כדי לבקש huge pages, ובדקו אם הביצועים משתפרים.

  4. הסבירו: למה בסיסי נתונים (כמו PostgreSQL) מוגדרים לרוב עם huge pages? אילו מאפיינים של בסיסי נתונים הופכים את זה ליעיל?