לדלג לתוכן

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 frame) 0x00000001234AB. מהי הכתובת הפיזית הסופית?

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


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

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

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

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

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

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


תרגיל 3 - תקורת טבלאות דפים

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

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

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

  1. חזרו על החישוב עם דפים ענקיים של 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;
}

  1. הריצו את התוכנית. מדוע סריקה עם stride של 4096 (גודל דף) איטית יותר יחסית מ-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? אילו מאפיינים של בסיסי נתונים הופכים את זה ליעיל?