מעבדות התמחות במערכות ווינדוס¶
בחירה שמוסיפה עומק למערכת שכבר בנינו¶
בשלב הזה בוחרים שתי מעבדות מתוך שש האפשרויות שבהמשך. כל מעבדה דורשת שלושים עד חמישים שעות עבודה עצמאית, בנוסף לפרויקטי הפרקים. יחד הן מוסיפות שישים עד מאה שעות. אלה פרויקטי התמחות, ולא הרצאות נוספות, ולכן מבנה הקורס נשאר ארבעה־עשר פרקים ועשר הרצאות בכל פרק.
ההיכרות בפרק האחרון נותנת שפה משותפת, אך אינה מחליפה בניית רכיב אמיתי, חקירת תקלה והוכחת סגירה. אפשר לבחור שתי מעבדות שקשורות זו לזו, כמו תצוגה ושמע, או שתי שכבות שונות, כמו מסנן קבצים ומחולל קוד. בכל מקרה ההגשה צריכה להראות יכולת להבין חוזה חדש מתוך תיעוד ולבדוק אותו במערכת.
נחלק כל מעבדה לארבעה שלבים. נקדיש ארבע עד שש שעות להגדרת חוזה וקריאת המקורות, שתים עשרה עד עשרים שעות למימוש, שמונה עד שתים עשרה שעות לכשל ולחקר חיים, ושש עד שתים עשרה שעות למדידה ולהגשה. אם היקף המימוש גדל, נצמצם תכונות לפני שנבטל את בדיקות הכשל.
ההגשה המשותפת¶
לכל מעבדה נגיש קוד שנבנה מפקודה מתועדת, גרסאות כלים, תסריט הפעלה ודוח שמפריד בין תוצאה שנמדדה לבין תוצאה צפויה. נוסיף תרשים בעלות על המשאבים ומכונת מצבים של הפעלה וסגירה. כל מספר ביצועים ילווה בהגדרת העומס, סביבת ההרצה ומספר החזרות.
הבוחן צריך להיות מסוגל להפעיל את המערכת, להכניס את הכשל המתועד ולראות מדוע התיקון מטפל בסיבה. דוגמה שמציגה תמונה, מנגנת צליל או טוענת דרייבר פעם אחת אינה מספיקה. תנאי הקבלה כוללים גם כשל חלקי באתחול, עצירה בזמן פעילות ושחרור כל משאב שנרכש.
מעבדות קרנל דורשות את סביבת הדרייברים המבודדת מפרק שלושה־עשר, עם ערכת הפיתוח, סמלים ויכולת התאוששות. סימולציה במרחב משתמש יכולה לבדוק את לוגיקת המצב, אך אינה נספרת כבדיקת התקנה, רמת פסיקה, ניתוק או פריקה בקרנל. בדוח נרשום במפורש אילו בדיקות דרשו חומרה או סביבת יעד שלא היו זמינות.
התמחות ראשונה: מצייר עם חיי משאבים מפורשים - D3D12¶
המערכת המבוקשת¶
נבנה יישום חלון שמצייר עצם עם מרקם, משנה את גודל החלון ומחזיק לפחות שתי מסגרות בעבודה. מטרת הפרויקט היא להבין את הגבול בין הכנת פקודות במעבד לבין שימוש במשאבים במעבד הגרפי. נוסיף מדד זמן מעבד להכנת מסגרת ומדד זמן ביצוע גרפי מתוך שאילתות מתאימות, ונציג אותם כמדדים שונים.
נתחיל בהתקן, תור פקודות ושרשרת הצגה. נוסיף מבנה מצב לכל מסגרת שמחזיק מקצה פקודות, אזור נתונים משתנים וערך גדר אחרון שמשתמש בהם. נפריד בין משאב ברירת מחדל, זיכרון העלאה ותיאור המשאב. ההעתקה והציור יקבלו מצבי משאב ומעברים מפורשים.
נגדיר גבול למאגר ההעלאה ולמספר המסגרות הפעילות. אם אין אזור פנוי, נחכה להשלמה המתאימה או נדחה עבודה לפי חוזה ברור. לא נפתור חוסר מקום באמצעות הקצאה חדשה בכל מסגרת בלי מגבלה. בזמן שינוי גודל נמתין לשימושים שרלוונטיים לבאפרים הישנים, נשחרר את ההפניות הנדרשות וניצור משאבי הצגה בגודל החדש.
ניסוי הכשל והמדידה¶
ניצור גרסת מעבדה שמנסה לאפס מקצה פקודות לפני השלמת השימוש בו, ונבדוק את אבחוני שכבת הדיבוג. נחזיר את ההמתנה לפי הגדר ונראה שהאבחון נעלם בלי להוסיף השהיה שרירותית. נוסיף רצף שינויי גודל בזמן ציור וסגירת חלון כאשר מסגרת עדיין בעבודה.
נבחן גם מסלול שבו יצירת משאב נכשלת, ונוודא ששאר המשאבים שנוצרו משתחררים. אובדן התקן צריך לעבור למסלול שגיאה מוגדר עם אבחון מתאים. אין צורך לגרום לאיפוס דרייבר של המחשב כדי להדגים זאת; אפשר להזריק כשל במתאם היצירה ולתעד בנפרד מה טרם נבדק מול התקן אמיתי.
היגיון של פתרון ייחוס¶
הפתרון מחזיק משאבים עד שערך הגדר של ההגשה האחרונה המשתמשת בהם הושלם. שחרור הפניית רכיב במעבד אינו הוכחה שהמעבד הגרפי סיים לקרוא את הזיכרון. גם מחסום מצב משאב אינו המתנת מעבד להשלמה. שני המנגנונים פותרים שאלות שונות ולכן נדרשים במקומות שונים.
נשתמש במימוש התוכנה של סביבת הגרפיקה כאשר אין התקן חומרה מתאים, ונסמן זאת בדוח. תוצאה במימוש תוכנה יכולה להוכיח חלק מחוזי הממשק, אך אינה מדידת ביצועים של כרטיס גרפי. ההגשה תכלול טבלת בעלות לשלוש מסגרות רצופות והסבר מדוע כל אזור זיכרון ממוחזר בדיוק בזמן המותר.
המקורות המרכזיים הם ניהול משאבים באמצעות גדרות וחוזה איפוס מקצה הפקודות.
התמחות שנייה: מנוע שמע מונע אירועים - WASAPI¶
המערכת המבוקשת¶
נבנה מנוע שמנגן אות שנוצר בתוכנה או קובץ מעבדה קצר דרך מצב משותף מונע אירועים. נפריד בין תהליכון בקרה שמטפל במשתמש ובשינויי התקן לבין תהליכון שמע שממלא באפרים. תור הפקודות ומאגר הדגימות יהיו מוגבלים, ובמסלול מילוי הבאפר לא נקצה זיכרון ולא נכתוב קובץ יומן.
נברר את פורמט המיקס ונחליט אם אנחנו תומכים בו ישירות או מוסיפים המרה מפורשת. נחשב מספר בתים לפי מספר מסגרות וגודל מסגרת, ולא לפי הנחה שכל התקן משתמש בשני ערוצים ובמספרים בני שש עשרה סיביות. נבדוק את גודל הבאפר שהוקצה בפועל ונחשב בכל יקיצה כמה מסגרות פנויות לפי הריפוד הנוכחי.
נחבר אירוע עבודה ואירוע עצירה, נמלא באפר ראשוני ונפעיל את הזרם. כל קבלת באפר תסתיים בשחרור מתאים באותו מסלול הביצוע, גם כאשר אין עוד תוכן. נחליט האם סוף הקובץ מוביל לשקט, לניקוז ואז עצירה או למעבר לקובץ הבא, ונכתוב את ההחלטה כחוזה.
ניסוי הכשל והמדידה¶
נוסיף מצב מעבדה שמאחר את אספקת הדגימות, ונמדוד אי רציפות, עומק תור וזמני מילוי. נבדוק החלפת התקן ברירת מחדל, אובדן ההתקן הפעיל וסגירה בזמן המתנה לאירוע. החלפת ברירת מחדל אינה מחייבת שכל זרם קיים כבר בוטל, ולכן המנוע צריך להגדיר אם הוא עובר להתקן החדש או נשאר בקיים כל עוד הוא זמין.
נמדוד בנפרד זמן הכנה במעבד, מידע זמן שמספק מנגנון השמע והשהיה מקצה לקצה אם קיימת מערכת מדידה מתאימה. בדיקת לולאה תוכנתית אינה מוכיחה את זמן ההגעה לרמקול פיזי. לא נכנה מספר שמוחזר מממשק תזמון בשם השהיה כוללת בלי להסביר את תחום המדידה.
היגיון של פתרון ייחוס¶
תהליכון השמע מחזיק את מצב הזרם, קורא פקודות מוגבלות ומעביר מדדים קצרים לתור תצפית. במקרה של התקן לא תקף הוא מפסיק להשתמש באובייקטים הישנים, מסיים את דור הזרם ומבקש מתהליכון הבקרה לבנות דור חדש. אירוע מאוחר מהדור הקודם אינו רשאי להפעיל מחדש את הזרם.
הפתרון מפריד בין סיום ההמתנה לבין סיום השימוש בבאפר. הוא גם בודק את תוצאת האתחול לפני פרסום מוכנות. אם אין התקן שמע בסביבת הבדיקה, נגיש בדיקות מצב ומאגר ונציין שבדיקת זמן והתקן חסרה. בחירה במעבדה זו מחייבת השלמת בדיקת יעד עם נקודת שמע מתאימה לפני קבלה מלאה.
המקור המרכזי הוא מימוש זרם ניגון, יחד עם החוזים של IAudioClient, IAudioRenderClient וממשקי ההודעות על התקנים בגרסת היעד שנבחרה.
התמחות שלישית: התקן נתונים וירטואלי - HID¶
המערכת המבוקשת¶
נבנה התקן וירטואלי שמדווח ערך חיישן סינתטי ומספר רצף בדף שימוש ייעודי ליצרן. ההתקן יהיה מקור נתונים למעבדה, ויישום לקוח יזהה אותו לפי מאפיינים וממשק מתאים. נשתמש במסגרת ההתקנים הווירטואליים ובדרייבר מקור המבוסס על מסגרת הדרייברים של הקרנל.
נגדיר תיאור דוחות ומסמך פורמט. לדוגמה, דוח בן שישים וארבעה בתים יכול להכיל מזהה דוח, מספר רצף, ערך מדידה, מצב ואזור שמור. נסריאל את השדות במפורש ולא נשלח מבנה מהדר גולמי. הלקוח יקרא את יכולות הדוח מן הממשק ויאמת שהאורך והסוג תואמים לפורמט הנתמך.
נבחר מדיניות בעלות על דוחות. אם הדרייבר מנהל את הבאפרים, נממש את הודעת המוכנות לדוח הבא ונגיש לכל הודעה רק את הכמות שהחוזה מאפשר. תור מדידות יהיה מוגבל, וגלישה תסומן במונה ובמספרי הרצף. אין משמעות להצגת רצף מושלם כאשר בפועל מדידות הושמטו.
ניסוי הכשל והמדידה¶
נבדוק לקוח איטי, סגירת לקוח, הסרה בזמן קריאה וחיבור מחדש. הלקוח ישייך כל פתיחה לדור התקן, כך שתשובה מאוחרת לא תתערבב עם ההתקן החדש. נזריק כשל אחרי יצירת מצב הדרייבר ולפני התחלת מסירת הדוחות ונבדוק את הניקוי.
נמדוד קצב דוחות שהופקו, שהוגשו ושנקראו, ואת מספר הדוחות הממתינים. נריץ כמה מחזורי התקנה והסרה באורח ונבדוק שאין בקשות שהושלמו פעמיים או באפרים שנשארו בבעלות לא ברורה. חתימת בדיקה והתקנה באורח אינן אישור להפצת דרייבר למחשבי משתמשים.
היגיון של פתרון ייחוס¶
הפתרון מפריד בין מקור המדידות לבין מתאם הדוחות. מקור המדידות יכול להיבדק במרחב משתמש, אך התיאום עם המסגרת נבדק בדרייבר. בתחילת הסרה נסגור את שער יצירת העבודה, נבטל מקור תזמון, נסיים את פעולות המסגרת לפי החוזה ורק אז נשחרר מצב משותף.
הלקוח אינו מניח ששם מופע מסוים נשאר קבוע. הוא מגלה יכולת, פותח מופע ומטפל בשגיאות כהתפתחות של מחזור החיים. הפתרון מסביר מי מחזיק בדוח בין ההגשה להודעת המוכנות הבאה, במקום להניח שחזרת פונקציה תמיד מחזירה בעלות.
המקורות המרכזיים הם כתיבת מקור התקן וירטואלי וחוזה המוכנות לדוח הבא.
התמחות רביעית: מסנן תצפית למערכת קבצים - Minifilter¶
המערכת המבוקשת¶
נבנה מסנן שמתעד פתיחות וכתיבות על כרך מעבדה ומעביר רשומות לשירות במרחב משתמש. המסנן יתצפת על הפעולות בלי לשנות את תוצאתן. כל רשומה תכיל מזהה פעולה, סוג פעולה, זמן, סטטוס סיום ומידע זמין על היעד, בלי לשמור תוכן קבצים.
נגדיר תור קבוע מראש של רשומות ומדיניות אובדן מפורשת. אם השירות איטי או מנותק, פעולות מערכת הקבצים ימשיכו בהתאם לחוזה התצפית ומונה האובדן יגדל. לא נחכה ללא גבול לתשובת משתמש מתוך מסלול קלט ופלט, ולא נשמור מצביע לבאפר או לשם שחי רק בזמן ההחזרה הנוכחית.
נפריד בין רישום המסנן, הצמדתו לכרך, פתיחת ערוץ התקשורת וחיי החיבור של הלקוח. לתיאור האבטחה של ערוץ התקשורת תהיה מדיניות שמאפשרת רק ללקוח המעבדה המורשה לקרוא נתונים. שימוש בשם נתיב ייכשל בחלק מהקשרים, ולכן חוסר שם יתועד כתוצאה חוקית במקום להפיל את הפעולה.
ניסוי הכשל והמדידה¶
נפעיל עומס של יצירה, כתיבה ושינוי שם בתיקיית בדיקה על כרך המעבדה. נשווה עם המסנן ובלעדיו זמן פעולה, תפוקה ומספר רשומות שאבדו. ננתק את השירות, נמלא את התור ונפרוק את המסנן בזמן פעילות מבוקרת. נבדוק גם כשל בהקצאת רשומת תצפית בלי לשנות את תוצאת פעולת הקובץ.
נזהה את הקשר הביצוע של כל החזרה ונחליט אילו פעולות מותר לבצע בו. אם נדרש עיבוד מאוחר, נעביר רק נתונים שבבעלותנו ונשמור את חיי ההקשר עד סיומו. שימוש בבדיקת דרייברים ובסמלים יתועד יחד עם תצורת האורח.
היגיון של פתרון ייחוס¶
הפתרון אוסף רשומה קצרה במסלול הקריטי ומעביר עיבוד איטי לשכבה מתאימה. מזהה פעולה מחבר בין תחילת הפעולה לתוצאתה, אך אינו משתמש במצביע משוחרר כמזהה מתמשך. כל רשומה מגיעה לאחד משני מצבים סופיים: נמסרה או נספרה כאבודה.
בעת עצירה נסגור חיבורים חדשים, נסיים עבודה פעילה ונשחרר הקשרים לפי חוזי מנהל המסננים. סגירת נקודת ההאזנה לבדה אינה הוכחה שכל הלקוחות הקיימים כבר הסתיימו. נקודת הגובה של המסנן וחבילת ההתקנה ייבחרו לפי מסמכי סביבת הבדיקה, ולא יוצגו כהקצאה תקפה להפצה מסחרית.
המקורות המרכזיים הם דוגמת מסנן התצפית וחוזה התקשורת עם מרחב משתמש.
התמחות חמישית: מדיניות רשת עם ראיות להחלטה - WFP¶
המערכת המבוקשת¶
נבנה מנהל מדיניות במרחב משתמש שמאפשר או חוסם חיבורי ניסוי של תוכנית מוגדרת ליעד ולפורט שהוגדרו. נשתמש בשכבת הרשאת חיבור מתאימה ונכסה בנפרד את שתי גרסאות פרוטוקול האינטרנט. היעד יהיה שרת מעבדה, וכל המסננים יסומנו בזהות ייחודית של הפרויקט.
נפתח מושב דינמי ונוסיף את קבוצת האובייקטים בעסקה אחת. כך כשל באמצע ההתקנה לא ישאיר מחצית מדיניות, וסיום המושב יאפשר ניקוי של האובייקטים הדינמיים. נרשום את מזהי המסננים שהוחזרו ונבנה פעולת הסרה שמכוונת רק לאובייקטים שלנו.
היומן יפריד בין מדיניות שהתכוונו להתקין, תוצאת התקנה, אירוע רשת שנצפה ותוצאת חיבור של לקוח. כאשר אירוע נתמך כולל מזהה מסנן, נקשור אותו למדיניות שלנו. הצלחת חיבור אינה הוכחה שהמסנן שלנו לבדו התיר אותו, וכשל חיבור אינו הוכחה שהמסנן שלנו חסם אותו. נשתמש באירועי חסימה ובניסוי לפני ואחרי כדי לבסס את הייחוס.
ניסוי הכשל והמדידה¶
נבדוק חיבור תואם כלל, חיבור שאינו תואם, כתובת מהגרסה השנייה, כשל הרשאה בהתקנה וסיום פתאומי של תהליך המדיניות. נוודא שהסרת כללי המעבדה מחזירה את מצב הניסוי הקודם בלי לגעת בכללים של מערכת ההפעלה או של יישומים אחרים.
נוסיף מנוי לאירועים בגרסה שמתאימה ליעד ונוודא אילו סוגי אירועים ואפשרויות איסוף נתמכים בפועל. ההחזרה תעתיק רשומה מוגבלת לתור ולא תשמור מצביע לנתוני האירוע לאחר חזרתה. נמדוד קצב אירועים, אובדן מקומי וזמן החלטה שניתן לייחס, ונפריד בין מדידה בצד הלקוח לבין מדידה בנקודת הסינון.
היגיון של פתרון ייחוס¶
הפתרון משתמש במנגנון ניהול המדיניות הקיים כל עוד אין צורך בלוגיקה שרק החזרה בקרנל יכולה לבצע. הוא בודק משקלים, שכבות ושילוב עם מדיניות אחרת במקום להניח שכל כלל היתר עוקף כל חסימה. הוספת רכיב קרנל היא הרחבה נפרדת שדורשת מודל סמכות וחיים חדש.
בסגירה נבטל את מנוי האירועים מחוץ לעסקה ובלי להחזיק מנעול שההחזרה עשויה לרכוש. לאחר שהביטול חזר ונקבע שהחזרות הפעילות הסתיימו, נוכל לשחרר את הקשר המנוי ולסגור את המושב. בדיקה של תור מלא צריכה להראות אובדן תצפית מתועד, ולא שינוי סמוי במדיניות הרשת.
המקורות המרכזיים הם ניהול אובייקטי מדיניות, מנוי לאירועי רשת וסיום המנוי וחיי ההחזרות.
התמחות שישית: מחולל קוד קטן עם פירוק מחסנית - JIT¶
המערכת המבוקשת¶
נבנה מחולל קוד לתהליך שלנו בלבד, עבור ארכיטקטורת המעבדה ומוסכמת הקריאה שלה. בשלב הראשון נקבל ביטוי קטן כמו חיבור שני מספרים ונפיק פונקציה שאפשר להשוות לפענוח ישיר של הביטוי. בשלב השני נפיק פונקציה שאינה פונקציית עלה, מקצה מקום במחסנית וקוראת לפונקציית עזר, כדי שנוכל לבדוק גם מטא נתונים של פירוק מחסנית.
נשתמש בהקצאת דפים ייעודית. בזמן הבנייה הדפים יהיו ניתנים לכתיבה, ולאחר השלמת הקוד נעביר אותם להרשאת ביצוע מתאימה ונבצע את סנכרון מטמון ההוראות הנדרש. לא נניח שמדיניות התהליך מתירה קוד דינמי; אם היא אוסרת זאת, נחזיר חוסר יכולת מוגדר ולא נשנה את מדיניות המערכת כדי להסתיר את הכשל.
נגדיר במפורש סוגי פרמטרים, אוגרים, רוחב תוצאה, יישור מחסנית ושמירת אוגרים. בביטוי שלם נגדיר גם סמנטיקת גלישה כדי שהשוואה לקוד סי פלוס פלוס לא תסתמך על התנהגות לא מוגדרת. כל תזוזה וקפיצה ייבדקו מול גבול אזור הקוד לפני פרסום הפונקציה.
ניסוי הכשל והמדידה¶
נשווה מאות קלטים לפענוח הייחוס, כולל גבולות המספרים. נבדוק כשל הקצאה, כשל שינוי הרשאות וכשל רישום טבלת פונקציות. נוסיף בדיקת פירוק מחסנית מתוך פונקציית העזר ונראה שהמסגרת שנוצרה מופיעה עם כתובת החזרה הצפויה.
ניצור במעבדה תיאור פירוק מחסנית שגוי ונוכיח שהבדיקה מבדילה בינו לבין התיאור הנכון, בלי להסתפק בכך שהחישוב המספרי עדיין מחזיר תוצאה. נמדוד בנפרד זמן יצירת קוד, זמן פרסום וזמן קריאה חוזרת. עלות הידור חד פעמית אינה זמן הביצוע של כל קריאה.
היגיון של פתרון ייחוס¶
לפונקציית עלה פשוטה שלא משנה את המחסנית ולא משתמשת באוגרים שצריך לשמר יש חוזה שונה מפונקציה שקוראת לעזר. הפתרון המתקדם יוצר רשומת פונקציה ומידע פירוק שמתארים את הפרולוג בפועל, ורושם אותם לפני שהקוד נגיש לקוראים. הכתובות היחסיות ייבדקו מול כתובת הבסיס וטווח הייצוג שלהן.
לצורך פרישה נסגור את שער הקריאות החדשות, נמתין לכל הקריאות ולצרכני המטא נתונים שבשליטתנו, נסיר את טבלת הפונקציות ורק אז נשחרר קוד ומידע פירוק. החלפת מצביע פונקציה אטומית אינה לבדה הוכחה שאיש אינו מבצע עוד את הגרסה הישנה. הדוח יציג את מנגנון ההמתנה ואת מבחן התחרות בין קריאה לפרישה.
בדיקה זו ממוקדת במוסכמת הקריאה של יעד אחד. העברה לארכיטקטורה אחרת דורשת מחולל הוראות ומידע פירוק מתאימים, ולא רק שינוי שם היעד בהגדרות הבנייה. גם מנגנוני הגנת זרימת בקרה של התהליך נבדקים כחלק מסביבת ההרצה.
המקורות המרכזיים הם מוסכמות פירוק מחסנית, רישום טבלת פונקציות דינמית והרשאות דפים וסנכרון הוראות.
הגנה על שתי ההתמחויות¶
בסיום נבחר תקלה אחת מכל מעבדה ונציג את המסלול מן הפעולה הגבוהה ועד המנגנון של מערכת ההפעלה. הבוחן ישנה תנאי אחד, כמו צרכן איטי, כשל הרשאה או עצירה מוקדמת, ונצטרך לנבא מה יקרה ואז להראות ראיה. כאשר התחזית שגויה, נסביר איזה חלק במודל חסר ונעדכן את הבדיקה.
קבלה מלאה מחייבת ששני הפרויקטים עומדים בחוזה שלהם ושכל מגבלה ידועה מסומנת. עצם השימוש בממשק מתקדם אינו תחליף להבנת חיים, סמכות, סדר זיכרון ותוצאת כשל. שתי מעבדות עם מימוש מוגדר וראיות ברורות מלמדות יותר ממערכת גדולה שאין דרך להסביר מדוע היא עדיין עובדת.