שלבים מקדימים - התקנת התוכנות המתאימות (אם עשיתם את ממ"ן 01 אז יש לכם את הכל כבר) והעברת התיקייה xv6-02 למכונה הוירטואלית. פרטים נוספים כאן.
רקע - קונטיינר ב-xv6 הוא מרחב משתמש מבודד בתוך מערכת ההפעלה, המשמש להפרדה בין קבוצות תהליכים וליצירת סוג של וירטואליזציה ברמת מערכת ההפעלה. קונטיינר מורכב מאחד או יותר תהליכים המופרדים משאר המערכת.
קונטיינר מתבסס על מספר מנגנונים:
PID namespace – כל קונטיינר מקבל עץ תהליכים עצמאי. לכל תהליך יש מזהה פנימי הנראה רק מתוך הקונטיינר, ומזהה חיצוני שמערכת האם רואה.
Mount namespace – מערכת הקבצים הנראית מתוך הקונטיינר יכולה להיות שונה מזו שמחוצה לו: עיגון (mount) בתוך קונטיינר לא ייראה מבחוץ, ולהפך
ניהול משאבים באמצעות cgroups, שמאפשרים להגביל ולנהל את משאבי המערכת של הקונטיינר, כגון שימוש ב-CPU ובזיכרון.
במרחב המשתמש קיימת תוכנת שורת פקודה בשם pouch, המאפשרת ליצור ולנהל קונטיינרים ב-xv6 בצורה פשוטה ונוחה. הפקודה pouch start c1 מתחילה קונטיינר בשם c1, עם הפקודה pouch connect מתחברים אל הקונטיינר, עם הפקודה pouch disconnect מתנתקים ממנה, והפקודה pouch destroy c1 מוחקת קונטיינר בשם c1.
מידע נוסף שלא צריך עבור הממ"ן נמצא כאן (קישור מהממ"ן)
המשימה - להוסיף את פקודה ps (קיצור של processes), שהוספנו בממ"ן הקודם, והפעם עם תמיכה בקונטיינרים וגם הדפסת cputime.
תוכלו להפעיל את מערכת ההפעלה xv6 ולראות שאם מנסים לבצע את הפקודה ps מקבלים שהיא לא הצליחה.
תוכלו גם להריץ את make qemuss משורת הפקודה באותה תיקייה כדי לראות איך מערכת ההפעלה אמורה להתנהג אחרי שהוספתם את הפקודה. (תמונה 1)
תמונה (1) הרצת הפקודה אחרי תיקונים
שלב ראשון -
קישורים (כמו בממ"ן הקודם): מדריך בגיטהאב, סרטון ביוטיוב
עקבו אחר המדריך/סרטון בדומה לממ"ן 01 ובצעו את השינויים. הפעם מותר (וצריך) לשנות את הקובץ syscall.h, אז השינויים הם כפי במדריך/סרטון. להעתיק את הקבצים עצמם לא יעבוד כיוון שמערכת ההפעלה שנתונה לכם בממ"ן הזה שונה ממערכת ההפעלה בממ"ן הקודם.
שימו לב:
את השינוי ב-proc.c (הפונקציה cps1XX) העתיקו מהקבצים ששיניתם בממ"ן 01.
בMakefile שמו את UPROGS בהערה אז הוסיפו בסוף השורה (לפני שההערה מתחילה) את _ps (בדומה ל_init)
fs.img: mkfs README $(INTERNAL_DEV) _init #$(UPROGS)
אם תריצו עכשיו תראו שהפונקציה exit שבקובץ ps.c מצריכה עכשיו int כארגומנט - אפשר להכניס 0, שבדרך כלל מסמן שתוכנית הסתיימה בהצלחה
(תזכורת: הוספנו קובץ בשם ps.c ושינינו את הקבצים: syscall.h, syscall.c, defs.h, user.h, proc.c, ps.c, sysproc.c, usys.S)
כעת אם ננסה להריץ את הפקודה ps נקבל תוצאה כמו בתמונה (2)
תמונה (2) הרצת הפקודה עם השינויים כמו בממ"ן הקודם
שלב שני -
שימו לב למבנה (struct) בשם proc בקובץ proc.h כדי להבין מהם השמות של המשתנים שנרצה להשתמש בהם.
נבצע כמה שינויים בקובץ proc.c, בפונקציה cps1XX.
הכותרת החדשה:
cprintf("name \t pid \t state \t \t extpid \t ppid \t size \t cputime \n");
הpid מגיע ממשתנה עם שם קצת שונה ממה שהוא היה בממ״ן הקודם
אם הstate הוא UNUSED דלגו ללולאה הבאה. הstate צריך להיות מודפס כבמצב RUNNING אם הוא RUNNING וSLEEPING אחרת.
הextpid מגיע ממערך הpids - כניסה 0 זה הpid של התהליך הנוכחי בnamespace הנוכחי. כניסה 1 זה בNS רמה אחת מעל, אם אין כזה דבר (התהליך לא בתוך קונטיינר) אז יהיה בו את הערך 0. במערכת ההפעלה שקיבלתם, תמיכה בקונטיינרים לא מופעלת, כלומר כלומר אין קונטיינר בתוך קונטיינר, ואפשר להתבסס על זה בפתרון המטלה.
את הppid צריך למצוא דרך מערך הpids של האבא, ולהדפיס את הpid שלו מהNS שהוא נמצא בו (הבינו על איזו כניסה מדובר לפי מה שהוסבר על extpid)
הcputime מאוד קל למצוא בתוך המבנה של struct proc
סיכום ובדיקה -
לסיכום, הקבצים להגשה הם: defs.h , user.h , sysproc.c , usys.S , syscall.c , syscall.h , proc.c , ps.c, Makefile
בכל קובץ קוד שמגישים אמורים לשים בראש הקובץ, בהערה, תיאור של הקובץ (נראה ששם הקובץ מספיק) וגם שם הסטודנט ומספר ת"ז.
בדיקה סופית - מריצים את הפקודה הבאה אחרי כיבוי של ה QEMU וגם make clean ו make, בלי להפעיל שוב את המכונה, כדי שהבדיקות יקבלו מכונה נקייה.
הטסטר לא יציב - יש בטסטר הרבה בדיקות. אם כולן נכשלות כנראה שיש טעות בפתרון שלהם או ששכחתם להריץ make clean ואז make לפני שהרצתם את הטסטר. אם רק 1 או 2 מהבדיקות נכשלות זה לא אומר שיש בעיה בפתרון שלהם, ופתרונות תקינים בדרך כלל מכשילים את הטסטר פעם או פעמיים.
./runtests.exp my.log
בעיה נפוצה: אין גישה לקובץ runtests.exp. במקרה הזה מריצים את השורה הבאה כדי לתת הרשאות -
chmod +x runtests.exp
רקע - דוקר זאת פלטפורמה המאפשרת הרצת תוכנה בסביבה מבודדת (קונטיינר) הכוללת את הרכיבים הנוספים והמשאבים הדרושים להרצתה.
הפעלת קונטיינר מתבססת על Image שניתן ליצור באופן עצמאי או למשוך (pull) ממאגר קיים. יצירת ה־Image מתבצעת על בסיס Dockerfile, שנכתב בהתאם לכללים ולסינטקס של Docker. לאחר יצירת ה־Image, ניתן להריץ את האפליקציה בתוך קונטיינר Docker על כל מערכת שבה מותקן Docker.
הערה: Docker פועל באופן טבעי בסביבת Linux. ב־Windows קיימת תמיכה ב־Docker רק באמצעות WSL2 (שכבת לינוקס לווינדוס)
את החלק הזה של המטלה ניתן לבצע בשתי דרכים:
מומלץ – עבודה בסביבה וירטואלית מקוונת (GitHub Codespaces) - סביבה זו מאפשרת עבודה ללא התקנות מקומיות וללא שימוש במכונה וירטואלית, והיא סביבה מוכרת ונוחה לשימוש.
עבודה במכונה וירטואלית לאחר התקנת Docker - אבל השיטה הזאת דורשת הרבה מקום אחסון (לפחות באיזור 25GB), ו-Image בסיסי יכול לתפוס מעל 600MB - מומלץ לבחור באפשרות הראשונה.
הוראות -
עקבו אחרי ההוראות בקובץ "פירוט ביצוע משימת "DOCKER.docx" שנמצא בתיקייה של הממ"ן, maman02.
בסעיף 1 חלק 3, אם אחרי יצירת repository חדש בגיטהאב לא מופיע לכם לחצן הקוד הירוק תנסו לחכות דקה או שתיים ולטעון מחדש את העמוד, או להוסיף קובץ ואז לחכות דקה או שתיים. גם התעלמו ממה שכתוב לבטל מחיקה אוטומטית ולהשאיר כיבוי אוטומטי.
טעות בהוראות - סעיף 6, חלק 5 - הפקודה docker run יוצרת קונטיינר חדש ולכן אמורים להשתמש כאן בImage ID ולא בContainer ID (כפי שעשינו בסעיף 5 ניתן לראות את מזהי הImageים עם הפקודה docker images.)
מוזמנים לצפות בסרטון הבא בו אני אבצע את המבוקש שלב אחר שלב, פרט לשינויים הנדרשים בDockerfile, שעליהם הסברתי מה צריך לעשות.
להגשה:
ה Dockerfile כקובץ נפרד.
פקודות וצילומי מסך של שלבים 5 ו 6 ותשובות על השאלות הבאות עם הסברים קצרים:
האם פקודת docker build יוצרת קונטיינר?
איזו פקודה ב xv6 מקבילה ל docker run ?
איזו פקודה ב docker מקבילה ל pouch destroy ב xv6 ?
מה הבדל בין Image ל Container, והאם כל מה שב Image בהכרח ירוץ אחרי יצירת Container ?
האם Dockerfile מכיל פקודות או רק הגדרות? הוא משפיע ישירות על Image או על Container?
העתקתי לכאן את השאלות מהממ"ן, השאלות די פשוטות אחרי שרואים את ההרצאות או קוראים את המדריך על פרק 3 - ניהול זיכרון.
הערה שלי - התשובה מופיעה במדריך הלמידה
התייחסו לאלגוריתם פינוי דפים Not Recently Used – NRU.
א. הסבירו את משמעות סיבית M בשביל האלגוריתם וסיבת ההשפעה שלה על ביצועים של מנגנון הדפדוף.
ב. הסבירו איזה גורם ובאיזה נסיבות מדליק את הסיביות M ו R ואיזה גורם ובאיזה נסיבות מכבה אותן.
האם גודל ותוכן שלדף של קבוצות עבודה (Working set) של תהליך נשארים אותו דבר לאורך חיי התהליך? נמקו.
טבלת הדפים של תהליך במערכת עם זיכרון וירטואלי נראית כך. כל המספרים הם דצימליים, מתחילים מאפס, וכל הכתובות הן כתובות של בייט בזיכרון. גודל הדף הוא 1024 בתים.
א. לאילו כתובות פיזיות, אם ניתן לחשב, ימופו הכתובות הוירטואליות הבאות: 942, 2211, 5399.
ב. האם יש שגיאות בטבלת הדפים, אם כן מה הן ומה מידת השפעתן האפשרית על ריצת התהליך.
ג. האם הכתובת הפיזית המתאימה לכתובות הוירטואליות 942 תשתנה אם גודל הדף יהיה 2048 בתים?
א. תארו את ההליך תרגום כתובת לוגית בעלת 32 סיביות לכתובת פיזית כשבמערכת גודל דפי זיכרון היא 4MB (4 מגה בית).
ב. חשבו את גודל טבלת הדפים בהנחה שאורך שורה בטבלה הוא 4B (4 בית) ושכל תהליך מקבל את מרחב זיכרון הווירטואלי המרבי.
מגישים זיפ יחיד בשם ex02 עם הקבצים -
כל הקבצים ששיניתם בחלק א' של שאלה 1 (סה"כ 9 קבצים)
קובץ הDockerfile מחלק ב' של שאלה 1
קובץ עם התשובות לכל שאר השאלות שקוראים לו ex02.docx או ex02.pdf בהתאם לסוג הקובץ