DCSIMG
הבלוג של צביקה פאר

הבלוג של צביקה פאר

בבלוג זה אני אנסה לשתף את הקוראים בחקירת מגוון טכנולוגיות נפוצות פחות או יותר

Compute Shader Hello world

עיבוד אות מורכב כדוגמת עיבוד אות וידיאו ב live,או משימות בעלות הרבה מאוד חשובים  ניתנות לביצוע היום ב  cpu .יתרה מזאת גם במערכות של smart phones ניתן לבצע היום עיבוד וידיאו ב Live לא מזמן בתערוכה של smart phones הוצגה אפליקציה שיודעת לנתח אות וידיאו לטובת זיהוי מכשולים בנהיגה.ניתן למצא הרבה דוגמאות למימוש video processing ב android באמצעות ספריית open cv .

כאשר המשימה מאוד מורכבת וכבדה חישובית כבר לא ניתן לבצע אותה באמצעות ה cpus במחשבים רגילים .דוגמא לאפליקציה כזו הינה NBodyGravityCS11 שב Directx sdk .הדוגמא מדמה תנועת כוכבים בגלקסיה כאשר כל תנועת כל כוכב מושפעת מכוח הכבידה של כל שאר הכוכבים .

1

כמות החישובים ב Demo  הזה הינה עצומה כאשר מנסים לבצע את החישובים הללו באופן הרגיל באמצעות ה Cpu גם במחשב חזק מאוד האפליקציה נתקעת ב 100% Cpu עבור כל ה cpu processors .

אחת הטכנולוגיות החדשות שנוספו ב Directx 11 הינה DirectCompute.טכנולוגיה זו  באה לתת כלים למפתח שרוצה להשתמש ביכולות של GPU לביצוע הרבה חישובים מקבילים במהירות .

כאשר מריצים את ה Demo באמצעות DirectCompute ה Demo עובד חלק ללא צריכה של cpu

2

 

שימוש ב gpu לצורך ביצוע חישובים לא החל ב directx 11 אלא כבר ב directx 9 ישנן הרבה אפליקציות שמשתמשות בgpu .יחד עם זאת השימוש בgpu שלא לצורכי גרפיקה לא היה דבר פשוט לכן נוצרו מעטפות כדוגמת Cuda שהינה המפורסמת מבניהם שאפשרה לכתוב ב c  מספר פונקציות ו cuda  דאגה לבצע את ההמרה לצורך הרצה על הgpu .

כיום בשוק קיימים מספר sdk לצורך ביצוע חישובים באמצעות ה gpu  כדוגמת DirectCompute, CUDA, CAL, OpenCL, LRB Native

אנו בחרנו ב DirectCompute מבין כולם מהסיבה של הקרבה ל Direct3D ו לhlsl שהינן טכנולוגיות בהן אנו מנוסים ומכירים אותם .

ה GPU מורכב מ 32 Hyper threaded cores אשר יוצרים 1000 יחידות של ALUs כל יחידה כזו יכולה להריץ במקביל 100 threads לכן ה GPU יכול להגיע ל 100000 Threads שרצים במקביל בניגוד לכמות של thread ים בודדים (בהתאם למספר ה cpu ים) שיכולים לרוץ על Cpu ים במקביל .המטרה של התכנת הינה לכתוב את האלגוריתם כך שמספר ה thread הרב ינוצלו .

Hello world

בתוכנית של ה Hello world שלנו אני מעונין להדגים שימוש ב Direct Compute לצורך עיבוד תמונה .

הבסיס לתכונית שלנו הינה סדרת המאמרים בנושא עיבוד תמונה שנמצאת כאן. בסדרה הזו נעשה העיבוד באמצעות ה Cpu ואני העביר את העיבוד של התמונה ל GPU .

6

7

אנו מתחיל ב Filter הפשוט ביותר GrayScale כאשר את הקוד של העיבוד תמונה שמשתמש ב CPU כרגע יוחלף בקוד שיפעיל את ה GPU לצורך זה .

 

3

כמובן שאין לזה שום יתרון להמיר את ה קוד ל DirectCompute והמטרה שלנו הינה לימוד המטרה שלנו הינה לימוד הטכנולוגיה .

שלב 1 בניית ה Demo

אחרי הורדנו את הDemo המרנו אותו ל .net 4.0 אנו ניצור ++C ספריה של Cli אשר תבצע את הקריאות ל DirectCompute .

9

הספרייה שמבצעת את עיבוד התמונה ב GPU מורכבת מ 5 חלקים :

  1. אתחול ה Direct compute טעינת ה Shader .
  2. בניית ה Buffer של הנתונים והעתקת  ה Bitmap ל Buffer של ה DirectCompute .
  3. טעינתה Buffer ל Shader  והרצת ה Shader .
  4. ה shader שהינו הקוד שרץ ב GPU.
  5. העתקת התמונה המעובדת מה Shader

איתחול ה Direct compute טעינת ה Shader .

קוד סטנדרטי שטוען את ה Directx dll מביא לנו את ה interface ID3D11Device , ID3D11DeviceContext של Directx11 .

טעינת הShader מתוך קובץ מתבצעת באמצעות קריאה לפונקציה : CreateComputeShader בדומה לטעינת shader עבור rendering pipeline .

בניית ה Buffer של הנתונים והעתקת ה Bitmap ל Buffer של ה DirectCompute.

Structured Buffers

לצורך העברת הנתונים ל GPU אנו נשתמש ב structured buffer שהינו סוג חדש של buffer המאפשר קריאה וכתיבה של structs לתוכו באמצעות index בדומה למערך בשפה עלית .

ב Direct compute משתמשים בשני סוגי Resource views שהוגדרו ל DX11:

Unordered Access Views או בקיצור UAV

הינו סוג חדש של resource view המאפשר קריאה וכתיבה על ידי ה shader בו זמנית . ניתן לטעון עד 8 Uavs ל Shader בו זמנית הטעינה מתבצעת באמצעות פקודת : CSSetUnorderedAccessViews. ה Uav משמש בעיקר לצורך אגירת תוצאות החישובים ושימוש חוזר בהם אם יש צורך .

ב Shader  ה UAV מיוצג על ידי RWStructuredBuffer

Structed resource view  או בקיצור SRV

הינו ה resource view שמשמש אותנו לצורך וטעינת הimage לshader מיוצג ב Shader באמצעות : StructuredBuffer

ב Demo אנו מגדירים שני SRV ים יצירת ה Structured Buffers מתבצעת באמצעות הפקודה CreateStructuredBuffer

18

הנוהל CreateStructuredBuffer מוגדר כך

12

יש לשים לב הד לדגלים של ה BindFlag שמגדירים את ה Buffer כunordered access ולדגל של ה MiscFlag שמגדיר את ה Buffer כ Structed.

לצורך הדוגמא בלבד אנו עוברים ידנית על השורות והעמודות של ה Bitmap ומעתיקים אותן ל input strutactured buffer.

יצירת ה SRV

13

יצירת ה UAV

14

 

טעינתה Buffer ל Shader והרצת ה Shader

שלב ההרצה מתחלק ל 3 חלקים והוא מתבצע באמצעות ה DeviceContext

1.טעינת ה Srv , ה Uav ו הShader ל Device

19

2.הרצת הShader באמצעות קריאה לפונקציה Dispatch.הפרמטרים של הפונקציה הינם מייצגים את מספר ה Group ים שמוקצים לצורך הרצת ה Shader .

20

חישוב מספר הthread ים הכללי מבוצע בצורה הבאה

15

16

3.ניקוי הנתונים שנטענו .

 

ה Computed Shader

ה Shader מכיל את ה קוד שנטען ומורץ ב GPU בדומה לShader גרפי שרץ ב pipline Direct3D .מכיוון שאנו עובדים ב structed mode (רק לצורך הדוגמא !!! באפליקציה אמיתית רצוי במקרה של עיבוד תמונה או וידיאו להשתמש ב Row buffer ) אנו צריכים להגדיר את מבנה ה Struct של הנתונים :

5

 

אנו מגדירים שני Buffers עם מידע מסוג BGRBufType

1.לData נכנס :

StructuredBuffer<BGRBufType> Buffer0 : register(t0);

זהו Read only buffer המכיל את כל ה struct של התמונה שצריכה לעבור עיבוד .ניתן לפנות לכל אחד מה index ים שלו כמו ל array בצורה הבאה : [Buffer0[index.

ה Buffer משוייך ל Texture register מספר 0

2.ל Data יוצא :

RWStructuredBuffer<BGRBufType> BufferOut : register(u0);

זהו Read write buffer המכיל את כל ה Data היוצא מה Shader של ה image שעבר עיבוד .

ה Buffer משוייך לregister An unordered access resource מספר 0 .

void CSMain( uint3 DTid : SV_DispatchThreadID )

הינה ה פונקציה ה ראשית של ה Shader היא מקבלת כפרמטר את מספר ה thread הנוכחי שכרגע מורץ

Numthreads – הינו Attribute שמגדיר את מספר ה Threadים בכל group המוקצים לביצוע הפונקציה , ביחד עם הפרמטרים של פקודת dispatch אשר מריצה את הפונקציה ניתן לחשב כמה threadים בסה"כ ירוצו

8

יש לשים לב לפרמטר x של ה DTid הפרמטר הזה מייצג את מספר הthread שכרגע מורץ ,הן ה attribute והן הקריאה לפונקציית ה Dispatch של ה shader מכוונות לכך שהוא יכיל את ה range של 0 עד למספר ה pixel ים אותם יש לעבד .(הערך של theNUM_ELEMENTS )

 

העתקת התמונה המעובדת מה Shader

על מנת לקרא את הbuffer עם התמונה המעובדת מה GPU אנו צריכים להעתיק את ה UAV שעודכן על ידי ה Shader ל resource שה cpu יוכל לקרא ממנו הפעולה מתבצעת בצורה הבאה :

10

11

יוצרים Buffer עם Access flag  לקריאה מה CPU ומעתיקים אליו את ה UAV .

לסיכום :

הצגתי כאן Hello world המדגים שימוש ב Computed shader לצורך עיבוד תמונה

הקוד ל Demo נמצא כאן יש לעדכן את המיקום של shader בהתאם למיקום במחשב .

17

מידע נוסף:

http://msdn.microsoft.com/en-us/library/windows/desktop/ff471566(v=vs.85).aspx

http://www.microsoftpdc.com/2009/P09-16

בחירת טכנולוגיה לפרויקט גמר בנושא משחק תלת מימד


נשאלתי שאלה לגבי פרויקט גמר של תואר בלימודי  מדעי המחשב בנושא גרפיקה תלת ממדית. השואלת רצתה לכתוב משחק בגרפיקה תלת ממדית כעבודת גמר והתענינה באיזה טכנולוגיה לבחור .כמו כן ביקשה הפניות לאתרים שיכניסו אותה לנושא .היא העלתה 2 אפשרויות : Direct3D  או wpf  תוך כדי ציון שהיא יודעת לתכנת ב  #C .

כאשר בוחרים בטכנולוגיה לפרויקט הגמר צריכים להתחשב במספר גורמים:

  1. הזמן העומד לרשות הסטודנט בד"כ זה לא מישרה מלאה עם שעות נוספות לחצי שנה
  2. הידע בתכנות שהסטודנט בא איתו
  3. הידע בתלת מימד שבד"כ מסתכם בקורס או סמינריון
  4. העובדה שבנוסף לחלק של ה render הגרפי יש גם עבודה בחלק הלוגי של המשחק .

השוואה בין טכנולוגיות :

לפי דעתי אפשר לשקול גם את OpenGL והן XNA .

123

DirectX 

הינה הטכנולוגיה החזקה מבין כול שאר האפשריות  אבל כמו שלא נלמד לטוס שעורים ראשונים על  F22 Raptor  כך להתחיל ללמוד את הטכנולוגיה המורכבת הזו לצורך עבודת גמר זו קפיצה מאוד גדולה .Directx  עבודת רק על windows  .אין בה  fixed pipline  והתכנת מחויב לקפוץ ל Shaders  מהHello world הראשון כלומר ללמוד hlsl  עם כל ההתעסקות ב semantics  וכד .DXUT  - הינה מעטפת שלא מומלץ להתקרב אליה וכמו כן אין תמיכה ב format ים סטנדרטים של meshes   כגון : obj  .ב Directx12  הבנתי שהנקודה הזו תשתפר . Directx  הינה c++ oriented   ונסיון לכתוב בה בשפות אחרות  זה די שבירת שיניים .מבחינת גירסאות כאן הבחירה הינה בין שתיים : 9 או 11 כאשר 9 הינה הפשוטה ותומכת ב fixed pipeline

OpenGL 

אינני מכיר לעומק (כפי שאני מכיר את DirectX סה"כ ביצעתי בה שני פרויקטים בינוניים ) מההכרות שלי לפי דעתי היא יותר נוקשה מ DirectX ברם היתרון שלה שבניגוד לשאר הטכנולוגית היא איננה   Microsoft  oriented   אלא מאוד cross    platform  ניתן לכתוב ל android  , Linux  , windows  .

OpenGL איננה C++ oriented  אלא אפשר לכתוב בה במגוון שפות python ,java c++ etc. ל openGL מספר גירסאות לא כולם נתמכות בכל ה device ים הגירסה האחרונה OpenGL 4.2 מכילה feathers מתקדמים כגון tessealtion  וכד

WPF

לפי דעתי מתאים יותר לכתיבה של גרפיים תלת ממדיים אין גישה ל vertex shader  .

XNA 

בהרבה יותר פשוטה מה DirectX  ,ובהרבה יותר מוגבלת היא תואמת את Directx 9  יחד עם זאת features  מתקדמים של directx לא בטוח שהינם הכרחיים לעבודת גמר . ניתן לכתוב ב C#  והיא Cross platform  ל Microsoft .כמו כן היא נותנת תבנית ראשונית לכתיבת משחק .יש המון דוגמאות ברשת שמהם אפשר להצעיד את המשחק .לכן המלצתי לה על הטכנולוגיה הזו .

Renderscript  

מהכרות ברמה של קריאת מאמר פה ושם עובדת הן על ios  והן על  android  בשפת תיכנות C

שיקול נוסף וחשוב  הינה תמיכה של Xna  בניגון מוזיקה ובקלט של joystick  ו keyboard בטכנולוגיות 3Dאחרות יהיה צורך לשלב את החלק הזה מטכנולוגיות אחרות .

ידע בסיסי נדרש

אלגברה

בכל הטכנולוגיות שהוזכרו על מנת לכתוב תוכנה בסיסית יש צורך בידע מתמטי מהתחום של אלגברה ליניארית ,לא יותר מאשר קורס אלגברה ליניארית I  ,כמובן שיש טכנולוגיות כגון prt  שדורשות ידע מתמטי יותר נרחב שוב לא נראה לי שמסגרת עבדות גמר צריך להגיע אליהן .

כפל מטריצות וקטורים , מטריצת יחידה מטריצה הופכית משטחים  וכד
בהחלט יכולים להספיק


תאוריה בנושא גרפיקה ממוחשבת

נדרשת הבנה בסיסית של תחום הגרפיקה התלת ממדית: מושגים כמו

World , view , projection

Transformations 

Lights and texture   .

תיכנות וארכיטקטורה

לא נדרש יותר מידע בינוני + בתכנות בשפה שהטכנולוגיה קשורה אליה , הצלחת פרויקט גמר איננה תלויה בערך חד חד ערכי אם התכנת עבד לפי כללי solid נוקשים .רוב הטכנולוגיות המורכבות כגון thread ים וכד אין להם שימוש במשחק פשוט שבד"כ חי ב rendering thread .

פיזיקה וAI

אין צורך להיות מדען גרעין של אחמדניגאד ברם צריך להכיר נוסחאות של חוקים בסיסים כגון כח המשיכה , מתקף ותנע וכד .

AI צריך לדעת ברמה בסיסית אם בכלל .


חומרה

ניתן למצא כרטיסי מסך זולים מאוד שתומכים בגרסאות המעודכנות ביותר

 Resources

נדרש אוסף של resources  כגון meshes  , Textures  אותו יש ללקט ברשת ,לחפש בתיקיות של ממשחקים של ילדים יצירת 3D Resource הינה דבר מורכב המצריך ידע ב Blender  או כל תוכנה אחרת חבל על הזמן כאן במקרה של פרויקט גמר  ,כעקרון עם ה pix  החדש אפשר להעתיק Resource ,מכיוון שעבודת הגמר איננה פרויקט מסחרי הדבר יותר פשוט.

לינקים

בלוק עם סדרת לימוד ל XNA

קישור ל msdn בנושא xna

אשמח להמשיך לקבל שאלות בתחום של directx ואשתדל לענות עליהן במסגרת הבלוג .

 

Understanding the Domain

יצא לי פעם לעבוד כתכנת על פרויקט IT במוסד פיננסי כלשהו. למערכת היה ארכיטקטורה מעולה מכל הבחינות: ביצועים , אבטחת מידע , איכות התצוגה עם גרפים תלת ממדים סוף הדרך .אבל כשבאנו להציג בפעם הראשונה את המערכת ללקוח הסתכלו עלינו במבט שהזכיר לי את הקטע בו הרבנים מסתכלים על המורה לבר מצווה של אלכס קופרובסקי והוא לא מבין מה לא בסדר ושואל :"הציצית שלי לא כשרה ? " . גם אנחנו רצינו לשאול האם הצל של הגרף התלת מימדי לא נראה ראלי ? כי אם זה הבעיה אפשר להשתמש ב cascaded shadow maps .

מה שקרה זה שהגרפים והטבלאות שהיו יפיפיים הראו נתונים של שטויות במיץ עגבניות , לא עניין את הלקוח אם השתמשנו ב decorator , אם הארכיטקטורה עונה על כל העקרונות של srp , ocp ,lsp בצורה מושלמת ,מצדו שהכל ייכתב ב method אחד וכל הלוגיקה תופרד באמצעות goto חו"ח שלא נדע מוטמע .אבל עם נתונים כמו שהמערכת מציגה אי אפשר לעשות כלום .

אם כבר דיברנו על הצל  אז השיטה הפשוטה של יצירת צל עם stencil buffer לדוגמא יוצרת רקע שחור בקטע שמקור האור נחסם על ידי mesh יוצרת צל לא מציאותי 

בתמונה צל לא ראלי

2

במציאות צל ממש לא מורכב מ rgb 0, 0 , 0 אחיד אלא יש התכנסות של דעיכת לעבר מרכז הצל .

3

הבעיה שאנשי התוכנה אינם מכירים את ה domain של הפרויקט הינה בעיה שקימת בהרבה מאוד פרויקטים.

ברוב הפרויקטים בהם השתתפתי לצוות התוכנה היה ידע מזערי או בכלל לא היה ב מרחב הבעיה .אם ניקח את כל התכנתים שהשתפו בפרויקטים מעולם הביטוח בארץ אני כמעט בטוח ש95% מהם לא יודעים מה ההבדל בין פיצוי לשיפוי .(גם אני בעונותיי הגדולים לא הצלחתי לקלוט את זה למרות שהסבירו לי מיליון פעם)

כמה אנשי התוכנה יכולים להתקרב ל הבנה של ה domain במסגרת תהליך ה design והפיתוח .האם בסוף הפרויקט שעוסק ב תחום של כירורגיה יוכל כל אחד מהתכנתים להתחיל לצאת ב 4 מהעבודה לצורך השלמת הכנסה ככירורג בכיר באחד מבתי החולים הפרטיים ?

אחד ה patterns הקבועים של ישיבות בהן מוצגות הדרישות של פרויקט הינו התפרצות של תכנת שאומר הדרישה הזו זה בדיוק מה שהטכנולוגיה הזו והזו עונה  (כלומר הטכנולוגיה החדשה שאתמול שמעתי עליה ואני מה זה רוצה שהיא תקשט את קורות החיים שלי )  .בד"כ הדובר גורם לתזוזה של הדיון מנושאי ה דרישות מעולם ה domain כגון  ה use case או ה use story , מהם המושגים המקצועיים מעולם ה domain  העיקריים לדיון  טכנולוגי .

הניסיון לגרור את התהליך בהו מוצג ה domain  של הבעיה לישיבות טכנולוגיות לפי דעתי פוגע ב Design של הפרויקט ובהמשך בהצלחת הפרויקט כולו .

נכון לפעמים קיים לפרויקט מחסום טכנולוגי דרישה לקחת סרט וידיאו באורך מלא לפרוס אותו  להוסיף water mark ולקבצו בחזרה בכמה שניות על חומרה של מחשב ממוצא הינה משימה בלתי אפשרית .ומחסומים כאילו צריכים לאתר כמה שיותר מוקדם בחייו של פרויקט אבל מהמקרה הזה לדיון האם נשתמש ב task או threadpool או ביכולות הasync החדשות של C# 5 במהלך דיון דרישות של הפרויקט המרחק עצום ורב .

מספר הפרויקטים שצריכים להיפסל על הסף בגלל אי קימות של טכנולוגיה הוא לא גבוה במיוחד כנ"ל לגבי מספר הפרויקטים שנפלו עקב הגעה למבוי סתום מבחינה טכנולוגית.אני לא מדבר על בחירה טכנולוגית לא מתאימה אלא על אי אפשרות טוטלית למימוש הפרויקט .

דוגמא לכך לפי דעתי אפשר לראות מה דרישות של FIFA2012 שהתוכנה רצה על Directx9

1

כמובן שאם FIFA2012 היה נכתב תוך כדי שימוש ב directx11 היה אפשר להשיג חווית משתמש בהרבה יותר טובה בוודאות .אבל בל נשכח שהמשחק הכי פופולרי בימנו Angry Birds יכל עם קצת רצון וקצת יכולת להיכתב ל Commador 64 עם pick ו pokes !!!.

כך שהסוגיה הטכנולוגית זו לפי דעתי איננה מהווה Risk על פרויקט בחלק ניכר מהמקרים.לאומת זאת הבנה של ה Domain ומרחב הבעיה של הפרויקט הינו דבר קריטי להצלחת הפרויקט .

בכול מקרה המטרה בתהליך התהוותו של פרויקט היא להבין את ה Domain לקרב את אנשי הארכיטקטורה והקידוד למרחב הבעיה ולא לקרב את מומחי ה domain ל xml ,soap , json ,rest .

שלושה סוגים של מומחי domain קיימים :

עמית מעולם מתוכנה

בד"כ ממחלקת professional services עולם הDomain שלו זה עולם התוכנה בד"כ הוא ירצה עוד פרמטר ב log  שמאפשר רישום של הstack  או משהו כזה .

מומחה domain

בעל ידע רב ב domain עצמו וללא כל ידע בעולם המחשבים .

וזה שבאמצע

שבא מעולם האלקטרוניקה עם אוריינטציה תכנותית אילו הבעייתיים כי הם גוררים אותך בעצמם לעולם הטכנולוגיה .פעם יצא לי להשתתף בדיון התנעה של driver לכרטיס ל PC אנשי האלקטרוניקה כבר באו עם ידע מהבית ש windows זה מערכת שאיננה real time לכן חייבים להשתמש בתוכנה שעוטפת את הwindows ,ומאפשרת ל windows להתנהג המערכת real time . לקח די הרבה זמן לשכנע אותם שלדרישות של הכרטיס שלהם אין בזה צורך .לעמיתם האילו שלי במיוחד אילו איתם אני עובד עכשיו אני בד"כ ממליץ על החומר הבא בנושא ה domain.

הידע וההבנה של ה domain הינו קריטי במהלך הארכיטקטורה . ניקח לדוגמא מערכת של רובוט לשטיפת רצפות ארכיטקטורת התוכנה תראה שונה לגמרי אם הראש של השטיפה אפשרי להחלפה באחד אחר עם פונקציות אחרות תוך כדי פעולה , בלתי אפשרי להחליפו בכלל והינו חלק אינטגרלי מהמערכת אפשרי להחליפו רק ב off line האם יש סיכוי שבעתיד יהיה מספר ראשים על אותו הרובוט או שאין לזה בכלל משמעות .

גם בעולם ה IT יכול להיות מערכת סגורה לחלוטין שהינה בעלת דרישות security גבוהות מאשר מערכת אשר מותקנת וחשופה ל web עקב זה  שהמערכת מותקנת ברשת שחלק ממשתמשיה אינם מורשים ובעל רצון להתעסק במערכת ולא מפריד בינם למערכת ל fire wall ואף אחד מהם הוא לא guest אלא users ו power users .

בכל מקרה המטרה הינה לאפשר את תקופת הלימוד הזו של הdomain נטו לעזוב את הטכנולוגיה בצד .להתערבב בעולם ה Domain .גם מבחינה אישית זה מעשיר אותך וגם תוצאות הפרויקט נראות שונות לגמרי .

Instancing in direct3d

Rendering ‏ של Frame המבצע הרבה קריאות לכרטיס המסך הינו בעייתי מבחינת ביצועים .אחד המקרים שמצב כזה קורה הינו Render של scene המכיל הרבה מאוד פרטים די דומים שאינם מאוגדים בmesh ‏ .

דוגמאות ל scene ‏ כזה הינם :

  1. עץ עם הרבה עלים מתנפנפים ,
  2. שדה של שיבולים
  3. קהל של קבוצת כדור רגל .
  4. שער ארוך שהמצלמה קרובה אליו .

8

התמונה לקוחה מ http://software.intel.com/en-us/articles/rendering-grass-with-instancing-in-directx-10/

הסיבה לבעייתיות הינה שעבור כל פרט לדוגמא שיבולת בשדה צריך לבצע מספר קריאות לכרטיס מסך , הדבר משפיע על מספר ה context switching ‏ ועל רוחב הפס .

הטכנולוגיה של Instancing ‏ נוצרה על מנת למנוע את ה  chatty talk‏ מול הכרטיס מסך .כאשר יש לנו הרבה פרטים די זהים .

אצלנו במערכת יש משהו די דומה לצבא של נמלים (אלפי נמלים ) שנעות על הקרקע כל נמלה בכיוון ובקצב שלה .נמלה מוגדרת באמצעות skin mesh .לכל vertex ב mesh של הנמלה משוייכים index ים של bones  ,עבור כל bone יש פאקטור של bone weight שבאמצעות שינוי יוצרים את התנועה של הראש המפרקים והגוף של הנמלה .

למרות שהקונספט של instancing הינו ישן גם כיום עם cpu וכרטיס מסך מתקדמים 1000 קריאות כל frame לעדכן את ה weight של ה bones , את מיקום וכיוון הנמלה , ערכי texture שונים הינה פעולה שמכבידה במידה מסוימת על ה rendering thread .

באמצעות טכנולוגיה ה Instancing  מתאפשר לנו בקריאת draw אחת לבצע עדכון של כל ה 1000 meshs.

דוגמא מאוד בסיסית שמסבירה את העיקרון של הטכנולוגיה אפשר למצא כאן.הדוגמא מציגה 4 משולשים על המסך אשר נוצרו באמצעות instancing של משולש אחד .

1

אם נסתכל על ה vertex ים לאורך ה pipeline של Directx באמצעות pix נוכל לראות את הדבר הבא :

2

ל pipline נכנס Vertex Buffer  המכיל בדוגמא 3 vertex ים בלבד .במקרה שבפקודת ה Draw אנו משתמשים ב DrawInstance ה Input assembler stage ב DirectX pipeline  מתחיל את ה תהליך של עיבוד ה buffer כמספר ה instance ים שצוין בפקודה .

deviceContext->DrawInstanced(vertexCount, instanceCount, 0, 0);

כלומר אם instanceCount בדוגמא הינו 4 ה pipeline  ירוץ 4 פעמים שונות עם אותם הנתונים בכניסה .

 

3

ה Vertex Buffer שנכנס ל Input assembler stage מחולק ל 2 חלקים :

חלק 1 אשר נכנס ל slot 0 מכיל מידע המשותף לכל ה instance ים .בד"כ המידע הזה מכיל את ה Vertex ,  Texture , normal וכד עובר כל הפוליגון ופוליגון המשתתף ב מקטע של ה Rendering 

חלק 2 אשר נכנס ל Slot 0 הינו מידע מבדל עבור כל instance ו instance בפעולת הDraw .

D3D11_INPUT_ELEMENT_DESC שמכיל את ה instance data מאופיין על ידי :

InstanceDataStepRate – מגדיר בכמה לקדם את ה index של ה buffer בכל instance

InputSlot – המידע נכנס ל slot 1

SemanticName – ה Demo מגדיר את ה instance buffer  כ texture buffer שמכיל ה vector של מיקום עבור כל Instance ו instance .

הקוד שמגדיר את מבנה ה D3D11_INPUT_ELEMENT_DESC עבור ה instance rendering

 

4

 

7

 

5

ב Vertex shader ה Demo משנה את המיקום של כל vertex על פי ערכי ה vector שמשויך ל instance הספציפי.

6

פעולות נוספות עם Instancing.

ניתן לנתב את פעולת ה shader באמצעות מידע של ה instance לדוגמא אפקט שונה ברמה של קוד שונה שמתבצע לכל אחד מה instance ים.

Texture שונה עבור כל אחד מה instance ים

הערך של bone weight factor שונה עבור כל instance הדבר מאפשר ליצור בדוגמא עם הנמלים אפשרות שהנמלים לא ילכו בדיוק אותן הצעדים אלא כל נמלה תהייה לה את הקצב והמופע שלה של צעידה  

לסיכום

Instancing הינה טכנולוגיה של DirectXהמפאשרת לרנדר מספר גדול של אלמנטים דומים באמצעות קריאת Draw אחת .

רצוי למנוע את הכמות הגדולה של האלמנטים  ב render כבר בשיכבה של ה cpu על ידי frustom culling , או פעולה לוגית אחרת הקוטמת אלמנטים שבטוח שלא יוצגו .

ToggleButton Command property and SRP violation

באחד מה Code reviews שערכתי השבוע בפרויקט שעובד במתודולוגית mvvm נתקלתי בקשירת Command ל Command property של ToggleButton.

לפי עניות דעתי ה Command property ‏ של ToggleButton‏ מעודד באופן בילתי מודע את ההפרה של עקרון ה SRP — The Single Responsibility Principle‏ שאומר שלכל class‏ צריך להיות תפקיד אחד בלבד .

הclass‏ שממש את ה ICommand צריך לטפל בשני מצבים שונים :מצב אחד שהמשתמש מבצע checked ‏ומצב שני שהמשתמש מבצע unchecked ‏ של ה control ‏ .טיפול לוגי שיכול להיות מאוד שונה ולא קשור .

ניקח לדוגמא ToggleButton ‏ אשר בלחיצה פנימה הוא צריך להתחיל תהליך של הפעלת מזגן , בלחיצה החוצה ה ToggleButton שלנו אמור לכבות את המזגן , שתי פעולות שאולי קשורות מבחינת תפעולית זו לזו ולכן ב שיכבת ה UI הצמידו אותן זו לזו אבל מבחינה לוגית הן שונות: בהדלקה צריך לבדוק שעברו 5 דקות מהפעם הקודמת ,להתחיל תהליך הדרגתי ומורכב בעוד בכיבוי מנתקים את זרם ,עושים רעש של פאופ וזהו .

אם משתמשים ב Command ‏ אחד אשר מושם ב Command Property ‏ של ה ToggleButton כאשר נלחץ או משחורר הכפתור קודם כל נקראת הCanExecute‏ אשר מחליטה האם מותר לוגית לבצע את הפקודה אם כן נקראת Execute .

בשתי ה methods ‏האילו דבר ראשון צריך להבין האם ה Command ‏ נקרא כתוצאה מלחיצה או שחרור ,חיפוש מידע שמסבך את הקוד ובד"כ גורם לבאגים כי מקור המידע לא תמיד קשור לכפתור והסתמכות על state של השכבה הלוגית לא תמיד תואם את המצד שב UI .(דוגמא לכך שלחצו על הכפתור והמזגן לא נדלק ובכול זאת הכפתור נשאר ב ON)

יש כאן 3 פעולות שונות אשר מוכלות ב class ‏ אחד:

  1. בדיקת המצב של המנוע לפני הפקודה
  2. כיבוי
  3. הדלקה  .

3

הפתרון לפי דעתי זה לא להשתמש ב  Command property‏ הקיים אלא לפצל את ה property של ה ToggleButton לשני Commands properties ‏ שונים.

אחד שיקשור אליו את הCommand של פעולת ה Checked והשני של פעולת ה Unchecked.

בקוד דוגמא מוגדר ה Dependency property על פעולת ה Unchecked

1

ב xaml יש לקשור את ה Command היעודי ל attached property שיצרנו

2

כעת  כל  Command  שנקשר ב property מכוון לטיפול בפעולה לוגית אחת .

4

Frustum Culling

אחד האתגרים בתכנות מנוע תלת מימד זה בנוסף ל לדעת מה להכניס לכרטיס מסך זה לדעת מה לא להכניס לכרטיס המסך.

אל אף מהירותו וריבוי ה מעבדים ב GPU תחולת עיבוד גדולה תגרום להשהיות של ה Rendering thread כך שאיכות המוצג תיפגע עקב קצב רינדור נמוך (מספר frames לשנייה ).

אם נבחן scene מתוך ה Demo  של SubDMesh

 

4

נראה שלצייר Scene בודד לוקח כ 50mSec .

בGraph שה Pix  נותן לנו ניתן לראות היכן הרוב המאמץ והזמן עיבוד של ה GPU לוקח .כמובן בפקודת Render (מה שמיוצג על ידי החורים הלבנים )  בפרוט ה פקודות ניתן לראות את כמות ה Vertex ים הגדולה שכל פקודת Draw צריכה לטפל כמובן שהכמות מוכפלת עקב זה שה Demo משתמש ב Tesselation.

בכל מקרה בחרתי ב Patch divisions נמוך יחסית על מנת לא  להכביד על ה GPUעל ידי יצירת הרבה Vertex חדשים כתוצאה מה Tessellation.

2

 

3

ב Scene שהודגם היה סך הכל חייל אחד מסכן שאני חושב שאפילו משרת אומנם בגבורה אבל בקריה. ב Sceneים  אמיתיים כמות הMeshs בהרבה יותר גדולה  .

כל Vertex , index שנכנסים לכרטיס מסך עוברים עיבוד דרך כל ה Shaders הפעילים ברגע הזנתם , רק בסוף ה ה Pipeline מתבצע ה Cliping של ה Data שאיננו מוצג .

11

ה RasterizerState קוצץ את כל ה pixels שלא נכנסים לאותו מלבן ש החלון שמוצג כלומר אם יש לנו scene שמורכב מאצטדיון כדור רגל שלם וכרגע רואים במסך רק שחקן אחד , רק ה pixel של אותו שחקן יגיעו ל pixel shader .

ה Z- test לסוגיהם מתבצעים בשלב יותר מאוחר כלומר אם אני מרדנר קריין חדשות מאחורי שולחן ל pixel shader יגיעו גם ה pixel ים של ה שולחן וגם של המכנסים הקצרים שלו (במקרה הטוב ) שלא נראים כלל .

כאן ללא כל קשר לטכנולוגיה שבה משתמשים בא התפקיד של התכנת למנוע ככול הניתן הגעה של vertex ים ו index ים שלא יגיעו לידי רינדור .כמובן גם פעולות אילו אשר מתבצעות ב Cpu יש להן מחיר מבחינת ביצועים ,אולי חלק מהן ניתן לבצע ב Thread אחר בכל אופן לבדוק בכל Frame כל  vertex לפני שהוא מגיע לכרטיס מסך האם הוא Visibility זה דבר בלתי ישים לחלוטין !!!

 

LOD

מכיוון שאין שום סיבה שבתחום של 3X3 פיקסלים בו אמור להופיע מטוס קרב מרוחק ירונדר F22 עם מיליון Vertex ים  נוצר מנגנון של LOD שמהותו לכל mesh שיכול להיות מרונדר ישנם מספר גרסאות שנטענות לכרטיס מסך בהתאם לקירבה של ה mesh לצופה .

14

ב Direct3d11 ניתן לבצע lod  יותר חלק באמצעות tesselation .

 

View Frustum Culling

viewing frustum הינו החלק בעולם שהינו נראה על ידי המצלמה .

17

ה View frustum מורכב מ 6 משטחים כאשר כל מה שנמצא בתוכו הינו נראה על ידי המצלמה.

המטרה של הבדיקה הינה לראות האם mesh או חלק מ mesh נמצא בתוך ה View frustum ואם כן אז להזרים את ה mesh לכרטיס מסך.

ישנה דוגמא מאוד טובה ומאוד מאוד מאוד פשוטה אשר נלקחה מקורס תכנות גרפיקה ממוחשבת לתלמידי מדעי החברה באחת מהמכללות .את הדוגמא אפשר למצא כאן.

הדוגמא מבצעת 3 פעולות מרכזיות במטרה להחליט אם אוביקט נימצא ב View frusum

1.הדוגמא מגדירה את 6 ה planes שמרכיבים את הצלעות של ה frustum של המצלמה .הקוד הינו קוד סטנדרטי ביותר שאין צורך להמציאו .

2.עבור כל סוג של אוביקט תלת מימדי הדוגמא מגדירה פונקציה שיודעת לחשב האם האוביקט נחתך \ מוכל בתוך ה frustum או נמצא מחוצה לו

דוגמא לפונקציה כזו עבור כדור הינה :

16

3.הדוגמא מרנדרת רק את האובייקטים שנמצאים בתוך ה View frustum או נחתכים אייתו.

מכיוון ש mesh הינו צורה יותר מורכבת מכדור או תיבה ואם נתחיל לבדוק כל vertex ב mesh כל Frame הcpu יחנק לנו בד"כ בונים תיבה חוסמת ל Mesh ובודקים האם היא נחתכת או נמצאת בתוך ה View frustum .

18

החישוב של ה מלבן החוסם את ה mesh יכול להיות מבוצע על ידי שימוש ב פונקציה D3DXComputeBoundingBox שהינה חלק מה Dx sdk .

לפני שנים רבות הייתה המלצה להשתמש בכדור חוסם במקום במלבן חוסם עקב זה שמספר הבדיקות של מלבן חוסם גדול פי 6 מאשר כדור ,היום בcpu ים המודרניים גם בדיקה של מאות מלבנים חוסמים לא מורגשת .

ניתן לבצע אופטימיזציות על החישוב ,רוב האופטמיזציות מכוונות למצבים בהם רק חלק מה mesh מופיע ב frustum . ניתן לחלק את ה mesh ל Quad trees (ב gpu gems בפרק של הterrain יש הסבר איך לעשות את זה )  כאשר מרנדרים terrain הדבר מאוד חיוני , יש מאות אלגוריתמים סטנדרטים לTerrain (דוגמא) לגבי mesh ים בודדים כדוגמת מטוס לא בטוח שהטרחה משתלמת.

כאשר ה meshהינו מסוג Hierarchical Bones Mesh ניתן לבצע את החישוב של איזה חלק מה mesh יכנס ל frustum באופן רקורסיבי .

20

 

וכל זה הקדמה לבאג שהופיע אצלנו לפני כשבועיים :

כאשר היו מטיילים עם המצלמה לאורך אחד הצירים היו מבחינים במעין קפיצה של mesh ים קרובים כאשר ה Mesh היה אמור להיכנס לתמונה ,מאין השהייה של כמה מאות מילי רק ל Mesh ואז בבת אחת חלק ממנו הופיע הוא המשיך להיכנס חלק לScene באופן חלק .

לאחר חיפוש הסתבר לנו הדבר הבא :

מכיוון שה Mesh  היה מרונדר באמצעות Tessellation map ו Tessellation maps בניגוד לכל ה Maps לסוגיהם (Light , hights וכד) בעל יכולת הרחבה של ה mesh מעבר למימדים שלו . ההרחבה בוצעה רק בGPU וכאשר חישבנו את ה frustum culling ב CPU הדרנו את הMesh למרות שחלק ממנו כבר היה צריך להיות בתמונה .

הפתרון מבחינתנו היה לתת למנגנון ה frustum culling מקדם עבור כל mesh שבאמצעות הfrustum מאין מוגדל עבור mesh ים מסוימים בקרבה ל מסך .

אם נביט בתמונה הבאה אפשר לראות שיש חלק שלם של מים ליד הגלגלים שנוצר על ידי מנגנון ה Tessellation ב gpu  ואיננו נכלל בחישוב של ה frustum culling המתבצע ב cpu .

15

Nosql document DB

הדרישה

באחד מהפרויקטים עליהם עבדתי בעת האחרונה היינו צריכים לבצע ארכיטקטורה של שכבת DAL עבור אפליקציה שמכילה מספר רב של סוגים של ישויות מידע שונות ביילתי קשורות או תלויות זה בזו כמעט לחלוטין .כלומר לפעולות join לסוגיהן בין סוגי ישויות המידע אין קשר לוגי .

על ישויות המידע השונות יש לבצע פעולות Cruds כתיבה חיפוש עידכון ממחיקה , Full text search וכד

כמות הפריטים בכל רשימה של ישויות מידע נעה בין בודדים לאלפיים ,כאשר דרישה נוספת זה שהסכמה של ישות מידע הינה דבר דינמי שיכול להשתנות עם הזמן .

ישויות המידע כתובות כ Poco objects בלתי תלויות כאשר ישות מידע יכול להיות מורכבת מ Class ראשי שמכיל מספר  Classי משנה.

6

חשבנו לבחון אפשרות של שימוש ב NoSql Database מסוג Document כ Repository משום ששימוש ב RDBMS גם מצריך הרבה עבודה של יצירת הרבה מאוד טבלאות , שינוי סכמות דחופות  בניית שיכבת dal מורכבת ואין הנאה מהיתרונות של RDBMS הן בגלל גודל יחסית קטן של הטבלאות והן בגלל שאין קשר בין הטבלאות .

(אפשרות נוספת שחשבנו עליה היתה שימוש ב code first של אחד מה Frameworks )

ה NoSql Document Db שבחרנו לבחון הינו RavenDB .

RavenDB  הינו NoSql DataBase שכתוב ב net. ששומר מסמכים בתצורת JSON documents שתומך בטרנזקציות , RavenDB רץ כServer כאשר הממשק אליו הינו באמצעות שאילתות Linq . ניתן למצא פרטים על RavenDB הן באתר ,מאמר ב msdn וגם בסדרת פוסטים בנושא כאן וגם כאן.

היתרונות

  1. פשטות התממשקות וכתיבת שיכבת הDal , Interface חושף  RavenDB טוב שעונה על ההגדרה של Interface אידיאלי בחלק של פשוט מאוד לעשות איתו דברים פשוטים בחלק של אפשרי לעשות איתו דברים מורכבים אני לא כל כך הסתדרתי אולי זה נובע מחוסר תעוד .
  2. פשטות הפעלה ותמיכה ב DB .
  3. ביצועים מעולים בכל הפעולות שניסינו גם בכמות מידע שגדולה בכמה סדרי גודל ממה שאנו צריכים .
  4. תמיכה מעולה של החברה גם בstackoverflow וגם בקבוצת הדיון .
  5. מחיר יחסית זול ל RDBMS ים

6.ממשק ניהול נוח .המאפשר לבצע גיבויים לראות את הלוג , למחוק , לראות את כל הdocuments ב Database , ניהול index ים .

דוגמא למסך מתוך ממשק הניהול בו ניתן לראות את ה Documents השמורים , לבצע חיפוש להוסיף ידנית .

1_thumb2

החסרונות:

  1. כלי ניהול כדוגמת גיבויים אוטומטיים , שאילתות online לא מפותחים מספיק , למרות שלצרכים שלנו ניתן לתפור את הכלים די בקלות לפי הדוגמאות המסופקות עם החבילה .גיבויים ידניים המערכת מאפשרת לעשות באמצעות ממשק הניהול בקלות.
  2. אפשרות הרחבה לעתיד של ה Storage לצורכי BI לדוגמא על מנת לשמור את כל הפעמים שהליך רץ ותוצאת הריצה וחיפושים ותובנות ,הדבר אפשרי אבל מהר מאוד זה מתחיל להיות יותר מסובך מאשר שימוש ב sql db שמיועד למטרות אילו.
  3. חוסר תעוד רישמי למרות שאפשר למצא המון מזור באתרים כגון Stackoverflow וכד
  4. חוסר בדוגמאות (תמיד חסר לי אולי ב WCF נתקלתי בכמות מספקת ).
  5. נושא ה Security לא מפותח מספיק לצרכינו לטעמי .
  6. תומך בעיקר בעולם ה net. דבר שבעיתי אצלנו בעיקר באפליקציות שכתובות בpython , java , php .
  7. חסרה יכולת לשמור ערכים עם Referance מעגלי של אוביקט אחד לשני ובחזרה .

התקנה והרצה

לאחר שהורדנו את החבילה מהמרשתת על מנת להפעיל את הdb זה להפעיל את ה start batch file (דבר שפותח אוטומטית את ממשק הניהול הסילוורלאיטי ).

על מנת להתחיל לפתח יש לחבר מספר assemblies ל project להעתיק מספר שורות קוד ואתם בפנים .

8

Open DocumentStore and Session

5_thumb3

הממשק מול ה RavenDB מורכב שני אובייקטים מרכזיים :

ה Docuemnt store שמכיל את הממשק ברמה של הDataBase .הוא עוטף את אפשרויות היצירה שלה Session , התחברות ל Db instance

שמירה של אוביקט חדש

השמירה מעדכנת את ה ID של האוביקט הנשמר כאשר מבנה הid  אם הוא לא מסופק על ידי הצרכן מחולל  בtemplate שמורכב משם הclass עם סיומת רבים + ה id החדש .(המערכת יודעת מבחינת אנגלית להוסיף נכון את הסיומת )

7

אין צריך להגדיר ב DB את ה Scema של האובייקט או את התיקיות הכל מוגדר אוטומטית.

עדכון אוביקט

על מנת לעדכן אובייקט ב Database יש לבצע את פעולת הStore עם האוביקט המעודכן כאשר ה ID מכוון לID שאותו אנו רוצים לעדכן ,כל שינוי גירסה מעדכן את הערך של ה etag ואת זמן העדכון .

שאילתות ל DB

כאמור שאילתות מתבצעות תוך כדי שימוש ב Linq .

RavenDB עבור כל שאילתה בונה index דינמי בהתאם לתוכנה של השאילתה למטרת החזרת התשובה ,לשאילתות שכיחות RavenDB בונה index סטאטי שמתעדכן ב thread נפרד ,כאן יש עניין של נעילות אם רוצים לקבל את המידע המעודכן ביותר לאותו הרגע .

דוגמה לשאילתה :

12

ניתן להגדיר מראש את השאילתות אשר ישמרו באופן סטאטי כל עוד לא מוחקים אותן :

 

13

 

http://www.gamlor.info/wordpress/2011/07/ravendb-queries-and-indexes/

שונות

RavenDB תומך ב Attachments של קבצים בינארים (Blobs) כדוגמת קבצי תמונה או אודיו .

ניתן להרחיב את החבילה הביסיסית של RavenDB על ידי Plagins .

יש אפשרות לבחור מנוע אחסון כ Embedded ואז הקריאות ל DB מתבצעות באופן לוקלי ולא דרך ה network , כמו כן ניתן להגדיר שהנתונים ישמרו באופן ארעי בזיכרון RunInMemory = true

שיכבת ה DAL

המטרות שלנו בארכיטקרטורה של שיכבת ה Dal הינן:

  1. כמה שיותר Decoupling  משיכבת ה BLL כך שאם נצטרך מסיבה זו או אחרת להחליף את מנוע ה Storage הנגיעה בשיכבת ה BLL  תהייה מינימלית .
  2. אין צורך שהמערכת תוכל לתמוך בשני מנועי אחסון שונים בשינוי קונפיגורציה .
  3. זמן עבודה בערך כ 50 שעות (בחיים האמתיים זמן עבודה הינו אלמנט די מכריע בתכנון ארכיטקטורה )

עקב זה שלא נראה שיהיה צורך שהמערכת תוכל לתמוך ביותר ממנוע אחסון אחד שכבת ה Dal  יכולה להיות קונקרטית לטכנולוגיה ,וכאשר מסיבה זו או אחרת ירצו לתמוך במנוע חיפוש אחר יבצעו פעולת חציבה ורמונט כללי בassembly של הDAL.

Components diagram

5

ה Components מהם מורכבת שכבת ה Dal יכולים להיות מקובצים לפי מידת הקונקרטיות לטכנולוגיה כאילו שימחקו ויכתבו מחדש עכב שינוי טכנולוגית האחסון וכאילו שרק יעברו שינוי קל לצורך התאמתם לטכנולוגית אחסון אחרת.

השיכבה יכולה להיצרך ישירות או עלי ידי תפירתה בקלות כ Web Service.

Class diagram

6

 

בדיוק כפי שאני מעדיף ששכבת ה Dal תבצע שאילות SQL  או תקרא ל Sps ככה אני מעדיף ששאילתות הlinq יהיו חלק משיכבת ה Dal ול BLL יחשף interface לוגי .

 

10

 

9

הנושא של ארכיטקטורת ה Data containers נושא בחובו דילמה האם להשתמש באותם DataContainersלאורך כל השכבות מה Dal עד ל UI , מה שגורם להם:

  1. להיות עטופים בattributes שונים שכל אחד קשור לשיכבה אחרת.
  2. ,לממש interface ים משכבות שונות
  3. ולדאוג ל Convertors לדוגמא לשיכבה של ה Dal לא מתאים member מסוג Bitmap אלא מערך של Bytes .

אפשרות שניה עבור כל שיכבה לייצר DataContainers משל עצמה כאשר אפשרות זו נושאת בחיבה  עבודה של כתיבת Convertors שמציבים את הDataContainer של שיכבה אחת בשניה .

 

עבור כל DataEntity נכתב accessor קונקרטי שממש את ה interface הספציפי שהוגדר עבור אותו DataEntity .

פעולות משותפות הוגדרו בclass משותף

7

 

אלמנטים שמתפעלים את הRavenDB 

CustomSerializators – שממירם לנו אובייקטים שלא ניתן אוטומטית להמיר ל JSON

DbOperationsAccessor – מכיל פעולות כמו מחיקת DB , רפליקציה שממומשת על ידנו , יצירת DB

RavenDbSessionWrapper שעוטף לנו את הקריאה גם ל Document Store , ל Init פניה ל configuration להביא את ה port ושם ה DB

RavenDbDataIndex – הגדרות של index ים סטאטים

 

8

 

מסקנות

ראשית נחשפנו לטכנולוגיה של NoSql Document DB .

העמדנו מערכת בזמן קצר יחסית עם ביצועים משביעי רצון .

חסר לנו הקטע של Security כנראה שהתרגלתי לאושר של sql server וכד הן מבחינת אפשרויות הlogins וה roles דברים שהיו חסרים לי כאן .

חסרה לנו התובנה כיצד לבצע שאילתה שמכילה  Search על text למרות דוגמאות רבות לא הצלחנו בזאת .

Posted: Feb 22 2012, 11:14 PM by zvikapeer | with 2 comment(s)
תגים:,

Wcf UDP transport

בגירסה הבאה של .wcf  4.5 יכלל גם transport חדש שתפקידו לתמוך ב Udp .

הצורך ב udp transport  היה אצלנו כבר כמה שנים הסיבות לכך היו :

  1. אסינכרוניות מלאה אין מצב ל Dead locks  .
  2. תעבורת רשת יותר קטנה מאשר שאר ה transports  חשוב כאשר יש תעבורה גדולה ורוחב פס קטן .
  3. ביצועים :זמן שליחת , קבלת הודעה בהרבה יותר טוב משאר סוגי ה transports  .

בד"כ משתמשים ב udp transport במקרים בהם דרושה יכולת של שגר ושכח לדוגמא מקרר בסופר שמדווח כל פרק זמן על הסטאטוס שלו האם הדלתות פתוחות , הטמפרטורה וכד. לא מעניין את המקרר האם מישהו מאזין אליו , ולא מעניין את המאזין תוכן ההודעה הקודמת אם הוא כבר קיבל הודעה חדשה .

1

כאשר יש רק סוג אחד של הודעה שנשלחת באופן מחזורי ,אפשר לתהות מה ה Add in values ש Wcf נותן לנו על פני סתם המרה של האוביקט מידע למערך של bytes ושליחתו באמצעות udpclient .כאשר ה Contract נהייה מורכב ,ויש דרישות נוספות כגון security ,  Discovery , routing מתחילה להיות משמעות לשימוש ב wcf .

על מנת לספק את הדרישה הזו השתמשנו ב Udp transport שסופק כדוגמא ב sdk .הדוגמא מבחינת ה interface שהיא חושפת מאוד דומה לudp transport של 4.5 .

הדוגמא מספקת לנו udp transport channel כאשר ה Channel עצמו ממומש כ IInputChannel ו כ IOutputChannel.

 

2

 

3

החלקים המעניינים הינם כל הטיפול ב Socket ב Class ים האילו ב OutputChannel בפקודת Send אשר מבצעת סיראליזציה ל Message object וקוראת ל פקודת SendTo  של ה Socket

 

4

ב input channel המימוש קצת יותר  מורכב.

ב פקודת OnOpened של UdpChannelListener נוצר ונפתח udp socket עבור כל endpoint ש ה Service חושף.

לכל socket שנוצר מתחילים להאזין באופן אסינכרוני באמצעות הפונקציה ContinueReceiving .

 

6

כשמגיע הודעה חדשה ההודעה החדשה נדחפת לתוך Queue אשר תפקיד ה UdpInputChannel לקרא ממנו את ההודעות ולשלוח אותן ל Dispatcher .

בכוונה הדגשתי את הקטעים שקשורים ל udp socket שאר הקוד מטפל הן בהודעות סינכרוניות והן אסינכרוניות ומהווה בסיס מצוין לפי דעתי לכל צורך למימוש Transport channel החל מ Rs232 וכלה במנגנון שמפריח יונות דאר .

מכיוון שהדוגמה מתעסקת רק עם ה transport channel עדיין נשארים כל המנגנונים שלא קשורים באופן ישיר לתעבורה לדוגמא הEncoder ו הDecoder של ההודעה איזה encoder שרק תבחר או תממש כאן קביל, אפילו תקודד את ההודעה למורס אין שום קשר ל transport

5

ה encoder הינו class שיורש מ MessageEncoder ואפשר לצינו הן בקוד או בconfiguration .כאשר מגדירים את ה Binding בדוגמא משתמשים ב TextMessageEncodingBindingElement.

הדוגמא מדגימה איך ניתן לבנות את הChannel stack כך שיתקבלו תכונות שאינן אפשריות עקב האופי ה אסינכרוני של udp .

לדוגמא:

  • פעולה סינכרונית הClient קורא ל Server וממתין לקבלת תשובה .
  • ניהול wcf sessions
  • Reliable messages  - ה Client שולח הודעה ומחכה timeout עד שההודעה מתבצעת , יכול להיות מצב שה Client שלח את ההודעה כאשר ה Server בכלל למטה ואז כשהריצו את ה Server אם לא חלף לו ה timeout אז הפקודה תתבצע .

הDemo על מנת לתמוך בפעולות אילו מוסיף ל Channel stack  את ה ReliableSessionBindingElement.

על מנת לתמוך ב Duplex channels ה demo מוסיף ל Channel stack את ה CompositeDuplexBindingElement.

גם תמיכה ב טרנזקציות אפשרית והיא מודגמת באמצעות הDemo של TransactionMessagePropertyUdpTransport

תמיכה ב hosting  ב IIS מודגמת באמצעות ה Demo של UdpActivation.

אחד המקרים  שצריך את התכונות האילו ב udp transport הינה כאשר משתמשים בudp כ  Interoperability למערכת צד ג שהתעבורה אליה הינה udp והיא מתנהגת באופן סינכרוני .

יש לזכור שכאשר עובדים עם Relaible session מקבלים הפחתה ניכרת בביצועים .

Posted: Feb 18 2012, 09:56 PM by zvikapeer | with no comments
תגים:, ,

Creating WF workflow dynamically part 1

חלק ניכר מ Frameworks ,ארכיטקטורות  לסוגיהן כדוגמת MVVM , Spring  , MF ,  מגדירות מסגרת שהארכיטקטורה של המערכת צריכה להתיישר על פיה.

לדוגמא ב mvvm הקשר בין ה modal  ל view  צריך להיות דרך ה modalview ופנייה ישירה מהview ל modal  כדוגמת הירשמות לevent  של click  של button ומימוש ה event  ב xaml.cs  שוברת את הארכיטקטורה על אף שלכאורה הכול יעבוד.

לארכיטקטורה כזו מספר יתרונות שהמודגשת ביותר זו כמובן ה Decoupling  בין השכבות כך שבעולם אידיאלי ניתן יהיה לשנות את ה view  מבלי צורך לשנות את שיכבת ה UIL .בעולם האמיתי זה יותר בכיוון שלתכנת יהיה קצת יותר קל להבין את הקשר בין שיכבת ה UIל UILופחות מסובך לשנות את שיכבת הUIL  כך שתתאים ל view  החדש .  

אחד היתרונות שלפי דעתי יותר משמעוותים שארכיטקטורה כזו נותנת זה אותו השלד של ארכיטקטורה שרק צריך לעטוף  בשכבה כמה שיותר דקה של לוגיקה עסקית קונקרטית.

יותר פשוט לעשות ארכיטקטורה לפי כללים מסוימים לדוגמא בשכבת ui  המבוססת על mvvm  הארכיטקט יודע שהוא צריך להגדיר את ה modal  ודרך זרימת הcruds  אליו , הוא צריך להגדיר את הmodalview  ואת ה forms  ו ה user controls  של הView .

עדיין יש מרחב התקשקשות ואין שבלונה קבועה אבל זה עדיף בהרבה ממצב בו מתחילים ממצב נקי לגמרי בשיא ההתלהבות וחושבים על פיתוח כל מיני תשתיות גנריות שישמשו גם לעתיד וישום כל מיני patterns  תאורטיים   והמערכת יוצאת מסורבלת וכל מה שחושבים לגבי העתיד זה מתי ניתן לזרוק את המערכת ולכתוב הכול מחדש .

החסרונות של אותה ארכיטקטורה המבוססת על framework

גמישות – דברים לא מורכבים  בדרך כלל קל לעשותם עם אותו ה Framework  דברים מורכבים לפעמים ההשקעה שצריך במערכת שמפותחת באמצעות framework  גדולה אין ערוך מזו של עבודה ללא ה framework  .

לדוגמא : מימוש GraphView  של nodes  במקום TreeView בMVVM .במצב ערום ללא framework  הדבר מורכב אבל אפשרי , כאשר מנסים ליישם את זה באמצעות mvvm ומתחילים לחפש איך לרשת מ HierarchicalDataTemplate , איך לשנות שיהיה אפשר שchild  יהיה משותף לכמה אבות כמות ההתעסקות בכיפוף הטכנולוגיה הינה אדירה. עד כי נראה כי ניתן להחליף לנזירים ממגדלי הנוי את העיסוק היום יומי .

אי תמיכה – מחר מיקרוסופט או חברה אחרת  יכולים להחליט שהם מזיזים הצידה טכנולוגיה זו או אחרת ואז מה ? קוד לוגי שאיינו מסתמך על טכנולוגיה בהרבה יותר פשוט להעביר לדוגמא מ C#  ל java  מאשר workflow  של wf  לאיזשהיא טכנולוגיה מקבילה או לקוד .

Technology awareness – עצם הקישור לטכנולוגיה מגבילה למה שהטכנולוגיה יכולה להציעה לדוגמא אם השתמשנו ב mvvm שקשור ל wpf  יהיה קשה לנו להכניס טופס ישן מבוסס על winforms.

מוטיבציה

ברגעי משבר שאתה מתחרט שלא שמעת בקול של הוריך שרצו שתהייה מציל בחוף שרתון ואתה התעקשת ללכת לעבוד בהי טק כי יש שמה מכונות קפה שוות בא לך לעשות double click  על כפתור בEditor של ה  טופס וליצור event  ולממש שם את התוכן שלך בקצרה במקום להתחיל להגדיר commands  ו bindings  ו לשים את הcommand  ב context .

שימוש ב Framework כזה או אחר דומה לטיול מאורגן לחו"ל מאוד נוח רואים יותר דברים לא מבזבזים זמן על התעסקות בדברים אדמינסטרטיבים אבל בכל זאת מפסידים משהו מהחוויה.

WF Framework

WF  לא נותן יכולת טכנולוגית שלא היתה קיימת קודם או שהיה צריך להתאמץ מאוד על מנת לישמה נהפוך הוא הרבה מאוד פעמים ליישם בקוד דברים יותר פשוט מאשר מwf .

WF  נותן מסגרת למימוש תהליך עסקי , מה שחוסך צורך בהגדרת ארכיטקטורה אם אפשר להתיישר לפי wf  .

אחד השימושים שאנו משתמשים בטכנולוגיה זו הינה יצירה דינמית של bl workflows .

דוגמא דומה לישום שלנו הינה מכונה שיודעת להכין עוגות לבד בהתאם למתכון שהוזן על ידי המשתמש . (כמובן שHighlight  שלה זה עוגת שוקולד עם ספותה שחורה ).

השף מגדיר באמצעות מסך גרפי את התהליך של אפיית העוגה הוא מגדיר חומרים לעוגה , תהליכים באפיה בדיקה עם קיסם עץ אוטומטי האם היא אפויה וכד.בסיום התכנון השף שומר את התוכנית בבסיס נתונים ,התוכנית תשמש במכונה לצורך הרצת תהליך האפייה .

למרות ש wf  תומך ומעודד שימוש בDesigner שלו לצרכי בניית ה Wf  (דוגמא DesignerRehosting  בsdk )  מנסיון שלנו לא טוב לנסות קשור בין ה Ui  של ה wf editor  ל UI  של משתמש הקצה  אלא להתאים את  הui לuse case  של המשתמש ולא לטכנולוגיה של שיכבת הBLL   .כמו שלא ניתן לשף מסך לעשות joins  בין טבלאות למרות שאפשר להציג את זה בצורה מאוד נוחה למשתמש .

מה גם שהeditor של wf עדיין לא מפותח דיו ואיננו מאפשר קסטומיזציה טובה .לדוגמא בגירסה הנוכחית הוא אינו תומך בcustom activity designer  באפשרות להכניס control  אחר מאשר edit box  לדוגמא combobox  ולאפיין את הקישור אליו.(כפי שהבנתי בגרסה הבא מיקרוסופט אפשרו את היכולת הזו ).

המערכת אצל המשתמש מפיקה את ה workflow באופן דינמי ושומרת אותו בבסיס נתונים.

יתרונות של הארכיטקטורה הינן :

הארכיטקטורה מפרידה תהליך מאוד מורכב של קליטת נתונים ממפעיל והפעלת מכונה עם אותם נתונים לשני חלקים :

חלק סטאטי שהמכונה בזמנה החופשי מייצרת workflow על פי הנתונים של המפעיל . כאשר הworkflow שמיוצר הינו מינימליסטי ומאוד קונקרטי לטובת תהליך אחד  בלבד.

חלק דינמי שהוא יותר real time שמריץ את הworkflow שיוצר מראש .

תהליך דביגאבילי :

ניתן להשתמש בכלים שה wf חושף בצורה מיטבית הן להציג את התוכנית לפני הריצה והן תוך כדי ריצה לראות את התקדמות שלה . 

7

לWF ישנן יכולות tracking מאוד טובות שהינן Build in .

שימוש ביכולות הWF מובנות של

כדוגמת :

 Cancelation ‏ ו ב Compensation

אם באמצע תהליך אפיית העוגה מסיבה מסוימת מחליט האופה לבטל את התהליך או שלוגיקת התוכנית עצמה קוראת ל Cancel

9

יכולות אילו נותנות אפשרות להגדיר Activities אשר ירוצו הן במקרה שActivity הסתיים בהצלחה ובהמשך הריצה נקרא Cancel  ואז צריך מאין להחזיר את הגלגל אחורה ולבצע פעולה מנוגדת לפעולה שכבר הסתימה בהצלחה כמו אחרי הזמנת כרטיסי טיסה אם המערכת מבטלת את התהליך כתוצאה מאי אישור של מנהל אזי יש לבצע פעולת פיצוי של ביטול ההזמנה .

ונותנת גם אפשרות להגדיר ל activity  סוג של תהליך שיקרה כאשר הcancel נקרא כאשר הוא במהלך הריצה ולא השלים את עבודתו .

 

תשתיות הWF נותנות יכולות לכלול השהיית התהליך והמשכתו  בשלב מאוחר יותר .

טרנזיטיביות זה לא בדיוק תכונה נתמכת במערכת עקב החוק השני של טרמומכניקה שקצת קשה להפריד חזרה את הביצים , קמח והגזר מהתערובת של העוגה אם לא הצלחנו בתהליך הדלקת התנור .

Use case

1

המפעיל של המכונה טוען את הקובץ הworkfow נטען ויכול להריצו ביחד עם פעולות כמו לבטל הרצה , לראות את התוכנית של האפייה וכד

2

 

אבני הבניין העיקריות של הארכיטקטורה

3

 

Class diagram

Custom activities

אילו Activities קונקרטיים שמהווים את אבני הבניין לWorkflow שיחולל אוטומטית.

4

הערות

1.הDesigners של ה Activities כתובים ב Wpf ,הבעיה המרכזית איתם בגירסה 4.0 הינה העדר יכולת להכיל controls לעריכת Arguments או variables שאינם EditBox ואז לדברים מורכבים כגון list של אלמנטים בלתי אפשרי לתת אפשרות עריכה .

למיקרוסופט יש פיתרון פנימי לבעיה הזו הוא משמש לדוגמא ב Send activity לצורך מילוי השדות של הפרמטרים , לא הצלחתי להעתיק את הפתרון שלהם לאפליקציה שלי.

ניתן לקשור לXaml בBinding ערכים של modalview אשר ישמשו בזמן debuging להצגה אקטיבית של state של הריצה .לדוגמא: במקום הDesigner הסטנדרטי של Delay activity ניתן להחליפו בDesigner שמראה זמן יורד תוך כדי ריצה .

2.על מנת לבצע פעולה ממושכת כמו דימוי האפייה כמומלץ אנו לא ממשים בתוך ה Bakeing activity סוג של while loop  עם sleep ובדיקה מחזורית,אלא משתמשים בextention .

כאשר הactivity מסיים את פעולות האתחול שלו הוא נעצר בbookmark ואז extention  ששייך לו מבצע את הבדיקות וכאשר התנאי מתקיים הוא משחרר את הbookmark וה Activity יכול להמשיך בעבודתו .

הדבר נועד לאפשר את תהליכי ה Cancelation וכד

8

הקוד:

5

6

 

NDIS filter driver part 3

ברוכים הבאים לפרק השלישי של הטרילוגיה שעוסקת בשינוי ה data packet שזורם לרשת או ממנה באמצעות Ndis filter driver.

לצערי בגירסה הנוכחית של NDIS  עדיין  אין תמיכה בשאילתות Linq  ואו בReflection לכן את העבודה שלה parsing של ה NBL עלינו לבצע באמצעות פקודות  וmacros  של wdm  ו ndis .

מבחינת תוכן לוגי ה NBL בהודעת udp בנוי בצורה הבאה :

4

חלק של Header הודעת Ethernet

נציג של שיכבת הקו בosi .

חלק שזה מכיל את ה Mac  של כתובת המקור ,

ה Mac של כתובת היעד .

ופרוטוקול המידע של ההודעה לדוגמא: ip4 ,ip6 , arp  , Icmp וכד

12

חלק של Header הודעת Ip4

נציג של שיכבת הרשת ב osi

מכיל את הנתונים הבאים :

גרסת הפרוטוקול ,

אורח הפתיח ,

סוג השרות ,

הגודל הכולל של החבילה ,

מספר הזיהוי של החבילה שמשמש כאשר הודעה מורכבת ממספר חלקים

(TTL - Time To Live).

הפרוטוקול שבאמצעותו מעבירים את המידע לדוגמא : tcp , udp ,

כתובות ip של שולח ההודעה וכתובת ip של הנמען הסופי .

10

חלק של Header  הודעת Udp.

נציג שכבת ה תעבורה ב OSI

מכיל את פורט ה מקור ופורט היעד אורך החבילה וה Checksum .

15

payload , Data

המידע עצמו שנשלח או התקבל ברשת לדוגמא הודעות soap , http ,smtp וכד

11

מבנה המידע בהודעת udp

באיור מוצג structs שמרכיבים את מבנה של הHeader המבנה מתאים להודעת udp בלבד ,כל הודעה אחרת המרכיבים שלה יהיו שונים .

כל הודעה מכילה מפתח שמצביע על סוג ההודעה הבאה על פיו אני יודעים לדלות את המידע של הheaders המתאימים.

5

מבחינת פיזור המידע ב NBL  המידע ערוך בצורה הבאה :

 

6

Object diagram

7

מציאת הFirst Network buffer מתבצעת בצורה הבאה

8

להודעת udp יש שני Buffers הראשון של הheader והשני של המידע .מציאת הBuffer  ים של המידע מתבצעת בשיטה הבאה :

9

בקוד הבא ניתן לראות את הדרך בא מוצאים את ה packet הראשון של ה Header .

ndis הינו little indian כלומר צריך להפוך את מיקום ה Byts בStructs כאשר מלבישם עליו מערך של bytes  

13

משתמשים בפונקציה RtlUshortByteSwap על מנת לבצע את ההצרחה של ה Bytes.

הקוד שמוצא את הpattern ומחליף ערך הינו :

14

אנו מוצאים את הpattern באמצעות NdisEqualMemory ומחליפים char אחד בו .

בUdp אין צורך לעדכן Check sum

כלי עזר מאוד חושב הינו ה Wire Shark , יש לשים לב שwire shark איננו עובד במקביל ל Kernel debuging

הרבה מאוד פעמים structs של אוביקטי רשת שמורידם מה internet אינם מדויקים ובאמצעות wire shark ניתן לבדוק ולהשוות לשמה בdriver .

את הקוד ניתן למצא כאן

 

Implements bridge pattern with wcf

באחד מהפרויקטים שעבדתי עליהם לאחרונה היתה דרישה להחליף תוכנת עמדה  במערכת מבזורת בתוכנה אחרת .

התקשורת בין כל העמדות הינה WCF  ,כאשר הcontract  של העמדה החדשה שונה לחלוטין מהcontract  הקיים ואין אפשרות להחליפו לזה שהיה קיים .(העמדה הייתה ונשארה server )

ל Contract החדש אין תאימות חד חד ערכית ברמת הקריאות כלומר חלק מהקריאות של ה Client  היו צריכות מספר קריאות בContract של ה Server החדש חלק היינו צריכים לשמור ב Cache  על מנת לאגד מספר קריאות מה client לקריאה אחת בServer וכד.

1

 

חשבנו על 3 פתרונות אפשריים

פתרון 1 מערכת חיצונית

לכתוב או לקנות מערכת חיצונית שהינה מאין biztalk sever  אשר יבצע את פעולת התרגום .2

 

 

 

יתרונות

מבחינת decoupling מאוד גבוה בין מנגנון ההמרה לאפליקציה , השינוי היחיד שנדרש לבצעו באפליקציה זה החלפת ה address  של ה wcf server .

אפשרות ניטור של המידע הזורם + העבודה המתבצעת באותו מתאם .

תמיכה יכולת גידול לעתיד לdevice ים או שיטות תקשורת שונות .

חסרונות

הבעיה שצריך לתחזק עוד אפליקציה \ service  שאיננו חלק אינטגרלי מהאפליקציה .(תיעוד התקנה קיטלוג )

לקנות אפליקציה חיצונית עולה כסף .

Hop  נוסף של מידע שאין בו צורך . המידע נשלח ל wcf service  ולאחריו ל עמדה הנוספת. 

 

פתרון 2 השיטה הסינית

שיטת הquick and drity  לאתר את כל המקומות בקוד שפונים לwcf client  ולשתול בכל המקומות switch ים של האם לשלוח בintrerface החדש או הישן . + להוסיף את כל הלוגיקה בתוכנה עצמה של ה Client .

יתרונות

למרות שיש הרבה מאוד עבודה העבודה פשוטה אין סיכון טכנולוגי .

חסרונות

מכיוון שבאפליקציה  אין שיכבה אחת מסודרת שקראה לwcf clients  אלא הקריאות התבצעו מכל מקום אפשרי וישנם מאות מקומות כאילו הקוד של האפליקציה יסרבל  עוד יותר כי זה לא רק הקריאה עצמה יש להוסיף לוגיקה לכל קריאה .

כמובן שאפשר לעשות את זה יותר אלגנטי ולא להשתמש בSwitch אלא שימוש ב Factory   שיחזיר Iterface  ל ממשק .

 

הפתרון ה 3 Wcf custom channel

פתרון באמצעות Custom protocol channel שכתבנו שתפקידו לתרגם את ההודעות .

יתרונות

פתרון שהינו מאוד decoupled  אין צורך לפתוח אף אחד מהתוכנות . אפשר באמצעות קונפיגורציה להכיל אותו .

 לא נוצר עוד hop  מיותר

מאתגר מקצועית

אפשר באמצעותו ללמוד wcf  לעומק

מאוד מרשים ראשי צוותים סמי מיקצועיים (כאילו שיועדים מה זה wcf   בשתי מילים אבל אין להם שמץ ניסיון בארכיטקטורה נכונה וכד )שאתה מספר להם ברעיון עבודה שעשית כזה דבר חושבים איזה ילד פלא אתה ,השועלים הותיקים לא יתנו לך לסיים את הטרילוגיה והם כבר יראו לך את הדלת. שתסבך עד מוות את הפרויקט של מישהו אחר  .

חסרונות

מאוד technology aware  כלומר מבוסס על יכולות ההרחבה של wcf  ותלוי ביכולות האלו . ומכיוון ש wcf איינו קוד פתוח ניתן להיתקע עם memory leak בעיית ביצועים או חלקים שבלתי ניתנים למימוש .

 

Wcf channels

התשתית של wcf  מכילה ערימה של channels  המתפקדים כ chain of responsibility

דומה מאוד ל ndis filter drivers  .

3

 

 

בין כל החלקים של ה channel  זורמים אוביקטים מסוג Message .

הMessage

מורכב מ Headers  וPayload  של המידע (הAction  והפרמטרים שלה ).

כל channel  יכול להוריד להוסיף או לשנות את ה header ים .

כמו כן ה Channel יכול לשנות את ה payload כלומר את המידע עצמו שעובר ב Message

(שינוי פשוט של מידע יכול להתבצע באמצעות Behaviors כדוגמת מימוש IOperationBehavior ביתר קלות )

 

הפתרון שלנו התבסס על זה ש Channel במקרים מסוימים יכול להחליט שהוא לא מעביר הלאה הודעה (כלומר חוסם אותה ) או מעביר כמה הודעות במקומה )  או מעביר כמה הודעות בזמנו החופשי בthread  אחר אחרי שההודעה בכלל נסתיימה .

 

הפתרון הזה עובד טוב רק ב interface אסינכרוני .בinterface סנכרוני המצב מסתבך כי המערכת מנסה להחזיר לך תמיד הודעה על כל קריאה באופן סינכרוני ויצירת מצב ששתי הודעות נשלחות ומקבלים רק תשובה אחת מאוד בעיתי , אינני יודע אם אפשרי בכלל.

 אנו כתבנו Custom channel משלנו והכנסנו אותו ל channel  stack  .

15

ה  Channel הכיל את הלוגיקה כלומר את המימוש של ה Bridge  שמתאם בין ההודעות , הchannel  הינו statefull  הוא זכר את כל המידע מהקריאות הקודמות שדרושות לצורך התאום .  

הפיתרון מכיל את ה class ים הבאים :

7

LogicOrcBinding

הcustom binding  שמכיל את ה binding elements  שלנו .

 

4

 

הגדרנו רק 2 elements  כאשר תשתיות ה wcf  מוסיפות את החסר  בהתאם לקונפיגורציה אם זה security  , relaibale session  וכד

התשתית מוסיפה את שאר ה elements במקומות הנכונים כך שהצפנה לדוגמה תתבצע אחרי הטיפול שלנו .

 

 
5
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

 

LogicOrcBindingElement , LogicOrcChannelFactory , LogicOrcChannelListener

מכילים את ה בוילרפארט קוד בד"כ לא נוגעים או משנים אותם. תפקידם לעטוף את היצירה של ה  channel שלנו .

כאשר יש פרמטרים שצריך להעביר מה Binding  עצמו ,צריך לדאוג להעביר דרכם .

 

   

 

LogicOrcBodyWriter

class עזר פשוט שתפקדו לעזור בלכתוב את ה פרמטרים של הAction בMessage

הClass  מכיל event  בשם  writeBodyCallback שנקרא אוטומטית על ידי המערכת לצורך עדכון הפרמטרים .

 

6

 

LogicOrcChannel

זהו לב המערכת

8

 

בCtor אנו מקבלים Reference ל Channel הבא בstack

 9

אנו נשתמש בReference הזה לשני דברים :

1.להפנות מימוש methods למימוש ב Channel הבאה בstack ב methods שאין לנו צורך לממשן

לדוגמא:

10

2.הפניית הMessage אחרי הטיפול לChannel  הבאה ב stack

 

הmethods  שמטפלות בשליחת הנתונים ל channel הבאה בstack הינן :

public void Send(Message message, TimeSpan timeout) ,

public IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state)

כאן משתלבת הלוגיקה העסקית של הBridge בשליחה של הודעות לServer ,ניתן לא להעביר את הMessage ל channel הבא ובכך לחסום את ההודעה ניתן להעביר הודעה אחרת או מספר הודעות אחרות ,כמו כן ניתן להעביר את הטיפול ל thread אחר ובזמן שונה להעביר הודעה ל Channel הבא ב Stack .

 

11

 

דוגמא למימוש

פונקצית עזר לבניית Message חדש בהסתמך על העתקת ה Header של ה message  שהתקבל מבChannel הקודם ושינוי ה Action

12

 

הפונקציה הבאה מקבלת פקודה אחת ומפצלת אותה ל שניים

 

13

 

הMethods שמטפלות בקריאת הנתונים בצורה סינכרונית או אסינכרונית בהתאמה הינן :

public bool TryReceive(TimeSpan timeout, out Message message)

והצמד

public

IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state)

public bool EndTryReceive(IAsyncResult result, out Message message)

 

אחרי ששלחנו שתי הודעות Call1 וCall2 ל Client אמו מקבלים גם שתי תשובות אותן אנו צריכים לאחד לתשובה אחת .את הפעולה הזו אנו עושים ב EndTryReceive

14

 

Exception

בזמן הפיתוח אם מבצעים שגיאה בקריאה של ה Contract לדוגמא קוראים ל Action שאיננו נמצא ב contrat של ה Server המערכת נותנת שגיאה מפורטת :

{"The message with Action 'http://tempuri.org/ILogicOrcSample/CallWithWrongAction' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver.  Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None)."}

טעיות בשמות של ה פרמטרים בד"כ יגרמו ל להעברת null בפרמטרים של ה method

 

בדיקות

שתי בדיקות נעשו לצורך ולידציה של הפתרון :

1.בדיקת memory leak שהמערכת לא משאירה אצלה זבל במקרה ונחסמת פקודה מלהגיע ליעדה וכד.על מנת לבצע את הבדיקות עם התוכנית דוגמא יש להוריד את כל ה חלק של ה  Diagnostic מה Configuration files , לבצע את הקריאות הנדרשות בloop ומידי פעם לקרא ל GC.Collect

2.בדיקת ביצועים ש ה Bridge Channel לא פוגע בביצועים כתוצאה מביצוע הלוגיקה שלו

בבדיקה שבצעתי לא נראה כל דליפת זיכרון אך אני ממליץ בחום לכל מי שחושב על הפתרון לבדוק גם את נושא הזיכרון , יציבות , ביצועים של הקונספט האם הם מתאימים לדרישותיו.

קישור לקוד דוגמא:

קוד דוגמא מאוד בסיסי נמצא כאן .

הקוד מבוסס על דוגמא של מיקרוסופט בשם Chunking channel לדוגמא הוכנסו רק הדברים האלמנטריים ביותר לצורך הדגמת הקונספט .

על מנת להשתמש בה יש כמוסן להוסיף לה את כל הקוד הסטנדרטי כגון טיפול ב Timeouts סגירת Channels  ללא exceptions  וכד.

Multithreaded Rendering DX11

ל Directx גירסה 11 נוסף פיצר חדש של Multithreading שמטרתו להפחית את העומס הרב על ה Rendering thread היחיד , על ידי פיזור של חלק מהעבודה שהוא עושה בthreads אחרים או שימוש בbatch ים של פקודות לgpu . בפוסט זה אני אנסה לשפוך אור על הפיצר הזה .

על אף ריבוי המעבדים ב GPU שמגיע לאלפים ,וריבוי ה Cpu ים במערכת. הפקודות ל GPU מה CPU עוברות דרך GPU Commands queue יחיד באופן סינכרוני.

ההזנה שלה Commands queue מתבצעת על ידי Thread יחיד בשם ה Rendering thread .

ניתן לראות ולדבאג את הפקודות הנכנסות ל Command queue באמצעות Pix

mtdx15

.

במצב שבו לא משתמשים ב Directx multitheading כל העבודה של הrendering מתבצעת בthread אחד .מכיוון שהעבודה של ה GPU הינה סנכרונית ל Rendering thread ,נוצרים מצבים שבהם הgpu מחכה בחוסר מעש לפקודות מה cpu.

 

טעינה אסינכרונית של Resource ים

טעינה של Reource ים כדוגמת Textures , Vertex buffersלוקחת זמן ,ביצוע טעינה ב Rendering thread גורם לעיקוב פעולת הGPU ,בד"כ במערכות מורכבות לא ניתן כמו ב Demos לטעון את כל הReource ים בתחילת התוכנית בשל העובדה שהכמות של הReources ים די גדולה  אלא יש לבצע את הטעינה של ה Reources ים On the fly  במהלך התוכנית .

Directx 11 מאפשר לנו ליצור את הResources ב Thread נפרד שונה מה Rendering thread

dx5

Multithreaded Submission

האפשרות לחלק את העבודה של ה Rendering של ה Device בין מספר threads .כל Thread בונה Display List שבסיום הבניה משוגר ל Rendering thread .

mtdx16

 

 

mtdx13

 

Per-Object Display Lists

יכולת זו מאפשרת להכין בthread שאיינו ה Rendering thread   ,אסופה של פקודות Draw שנקראות Display List המרכיבות אוביקט לוגי בSence כדוגמת החייל שמורכב מאוסף הDraws הבאים :

 

mtdx4

mtdx5

mtdx6

mtdx7

לאחר שיצרנו את הBatch אנו יכולים ב Rendering thread להשתמש בו על ידי קריאה ל Execute של אותו Display List

mtdx8

mtdx9

mtdx10

 

אחרי שה Display List נוצר הוא Immutable אין אפשרות לשנותו על ידי הוספה או גריעה של פקודות Draw .לדוגמא להוסיף לחייל חרב , לדמות פגיעות וכד .

ניתן לשנות את הResources שמשויכים לאותו DisplayList החל מדברים בסיסים כמו מטריצות העולם שבו החייל נמצא וכלה במטריצות הסיבוב המשויכות לBones של החייל שנועדו ליצור תנועה .

 

מימוש

עד לגירסה DX11 היה בDirectX רק Interface אחד כדוגמת IDirect3DDevice9 ששימש לפיקוד על ה DX device בDX11 הפיקוד על ה Device מתחלק ל 3 בעלי תפקידם שונים.

mtdx23

ID3D11Device – הinterface הזה יכול להיקרא מכל thread שהוא ולבצע טעינת reosurce וכד במקביל לפעולת הרינדור

Rendering thread ID3D11DeviceContext – הDevice context ששייך ל Renderingthread .אחראי להזרמת הCommands ל Command queue של כרטיס המסך .

Deffered Thread ID3D11DeviceContext – ה context שנוצר בthread שאיינו הrendering thread ויכול לבנות Display List .

mtdx91

בDirectx Sdk האחרון ישנו demo המדגים את הטכנולוגיה הזו .

mt1 

עבדות הrender כאן יכולה להתחלק למספר חלקים בילתי תלויים:

  • ציור ההשתקפות של ה scene במראות
  • ציור הצל 

הDemo בא להראות איך ניתן להשתמש ב Multithreaded rendering על מנת להגדיל את מספר ה fps .

(ניתן להריץ את הdemo בכמעט כל כרטיס שתומך ב dx11 ולראות את השיפור בביצועים )

הdemo מדגים 5 מצבים של Multithreaded rendering .

Immediate

מבצע רגיל בו thead  אחד מבצע את כל העבודה משמש referance

ST Def/scene

בmode זה סתם מדגים את השימוש בDeferrered context ללא כל יתרון של ביצועים

MT Def/scene

בMode זה חלוקה של עבודת הציור לפי נושאים כדוגמת רינודר הצל המראות כל אחד ל thread נפרד .

ST Def/chunk

בmode זה עבודת הציור מחולקת לchunks אשר כולם מבוצעים באופן סינכרוני מיועדלהראות את הapi של חלוקה ל chunks

MT Def/chunk

בmode זה עבודת הציור מחולקת לchunks ואז מתרחשת חלוקה של ה chunks לפי מספר המעבדים .

ניתן לראות לפי המונה של Frame per seconds אשר מראה עליה במספר ה frames שמרונדרים על ידי הכרטיס בהתאם למצבי ה Multi threaded rendering השונים בהתאם לכרטיס המסך ולמספר ה cpu ים במערכת .

הרבה פעמים נתקלתי בקוד review שעשיתי בעבודה כבדה של ה CPU כדוגמת חישוב אילו אוביקטים נמצאים ב view frustum או אפילו עבודות AI בRendering thread, הדבר נובע מזה שברוב ה Demos וגם בDXUT הקריאה ל OnFrameMove callback מתבצעת ב rendering thread .דבר זה גורם לפגיע באיכות הrendering ללא קשר ליכולות הgpu .

הצרכניה וRecoverability של אפליקציה

ביום שישי שעבר בשעה 9 בבוקר בדיוק שהתחלתי לפרוק את המוצרים מהעגלה למסוע של הקופאית בסופר התחילו המסופים של הקופות אחד אחרי השני לקרוס וקול הצווינג של קריאת הbar code נדם  .

הקופאיות ניסו לרסט את המסופים אבל זה לא עזר ,והתור והלחץ של הקונים (יום שישי יום קצר) התחילו לגעוש .

היחידים שנראו מבסוטים מכל העניין היו הקרפיונים שקיבלו חסד של עוד כמה שעות לפני שטוחנים אותם ושמים להם חתיכת גזר על העין .ביחד עם אותו סבאלה שהחליט לספר צ'יזבטים על אותם הימים בהם קנית במכולת חצי כיכר לחם והתווכחת איזה חצי יותר גדול .

מנהל הסופר ניסה להתקשר למרכז התמיכה ולתאר להם את הבעיה שהמקסימום מידע טכני שהוא יכל למסור לאותה מרכזנית זה הודעה הזויה של :Failed to login due to transaction abortion משהו כזה ,משהו שנראה לי שגם למפתח הראשי של האלפיקציה לא היה אומר הרבה .

האפשרות לבקש ממנהל הסופר לייצר קבצי minidump ולשלוח למרכז הבקרה לא היתה ראלית ,כמו כן להגיד למנהל הסופר שכעת שולחים לו קבצי symbols של הגרסה שמורצת אצלו שיוריד בבקשה מה msdn את ה windbg  ויתחיל לדבג את האפליקציה (זה טוב להדגמות עם תכוניות קטנות ).

גם האפשרות לכרוז ברמקול של הסופר :יש פה תכנת בקהל גם לא נראתה משהו. במיוחד אם היו מוצאים תכנתים בקהל הלקוחות סביר להניח שעזרה לא היו מקבלים מהם אלא עצות וחוות דעת על למה צריך לכתוב את כל האפליקציה מחדש , למה כדאי לעבור לענן , אנדרויד , mvc4 silverlight 5 או spring .

לא משנה כמות המוטיבזציה שהיו יוצרים אצל מנהל הסופר על ידי משפטים כדוגמת "עתיד הסופר בידך אין אף אחד מאחוריך!!! " האפשרות להמשיך את יום הקניות כסדרו תלויה עכשיו אך ורק ביכולות הrecoverability של האפליקציה !!

כמעט כל אפליקציה יכולה לקורס אם זה עקב בעיית חומרה או בעיית תוכנה ,אני יודע שבמטוסי נוסעים ישנם לפעמים מספר מחשבים לאותה משימה גיבוי אחד לשני ,אצלנו בסופר בנס ציונה לא נראה לי שזה המצב .

אינני יודע למה לפתע קרסו כל העמדות. יכול להיות שהארכיטקט של המערכת לא לקח בחשבון אפשרות של נתק בין ה clients ל servers , או אפשרות שה server יקרוס והמערכת לא תוכננה כOccasionally Connected Systems Architecture .

יכול להיות שהמערכת תוכננה כ Occasionally Connected Systems Architecture אבל הפצה של poison message לclient שאין נגדו הגנה גרמה לשיתוק של כל העמדות .

דוגמא ל poision message הינה עדכון של פרי חדש (ספוטה שחורה ) בטבלת התמונות של הפירות עם תמונה בגודל 0 שגורמת לexeption

imagesCAW504NL

(הספותה השחורה הינה פרי רעיל כל עוד איננה בשלה כשהיא בשלה ניתן לייצר ממנה עוגות שוקולד מדהימות).

מרחב המקורות ל Malfunction  במערכת client server של 24 קופות שכל הזמן מעדכנות נתונים בשרת וכל הזמן נדחף להם נתונים חדשים כגון מבצעים של יום שישי כמעט ולא יכול להיות אפס .

עם הזמן כמות המידע שנצברת ומשתנה במערכת גורמת למצבים שלא תוכננו כמו שאילת select בהצבה למשתנה שאמורה להחזיר רק ערך אחד מחזירה יותר ואז ה store procedure נופלת .בעיות של buffer overflow , בעיות של race condition שנוצר עקב שילוב של כמות מידע וכד .

בכל מקרה לפי דעתי על הארכיטקט של המערכת לתת את הדעת שמצב של קריסה לוקלית בעמדה אחת או כללית בכל העמדות אפשרי .

ישנו פיתרון build in  לחלק מסוים מהבעיות מנגנון ה Application Recovery and Restart ומנגנון הWindows Error Reporting   ניתן למצא עליו פרטים ב http://msdn.microsoft.com/en-us/library/cc303708.aspx  אבל הפתרון הינו חלקי ולא היה עונה על הבעיה שהתוכנה בקופות לא קרסה לא היה second chance exceptionהמערכת ברוב העמדות אפילו לא נתקעה אלא פשוט הפסיקה לעבוד לקבל barcodes .יכול להיות מצב שרק ה תת מנגנון של בחירת פירות לא עובד והמערכת בלתי שמישה לחלוטין.

Recoverability  היכולת של אפליקציה לעלות מחדש ולהמשיך לעבוד מהנקודה בה היא הפסיקה אחרי נפילה באג או תקיעה .(אם אוטומטית או על ידי מפעיל ).

ברמה של  product management יש מספר עקרונות לתמיכה ב Recoverability

1.זמן recovery ועליה מחדש מינימלי.במשך השעה הזו שהקופות לא פעלו עשרות עגלות של מוצרים ננטשו על ידי קונים ממורמרים כמובן שאין זמן ל production debugging וכד  .

2.אפשרות ניטור הבעיה – מיועד למקרים קיצוניים בהם restart של אפליקציה לא עוזר בד"כ כאשר הבעיה נגרמת על ידי מצב סטאטי כמו בעיית חומרה כגון HD מלא , או בעיית תוכנה מסוג של poison message.

אפשרות לפתוח חלון של קופאי בכיר המציג את הבעיה מגובה תמיד באפשרות לפתוח קובץ לוג באמצעות Notepad ולהבין משם מה הבעיה .

3.החזרת האפליקציה במדויק לstate הקודם

האפשרות שאחרי reset של עמדה יצטרכו להתחיל חשבון שהוא כבר לפני סיום מחדש איננה פיסבילית לחלוטין ,הרי המסוע של המוצרים לפני הקופה כבר מלא במוצרים של הלקוח הבא . בזמן ההמתנה הלקוחות על מנת ליצור לפחות תחושה של התקדמות הערימו ערמות על גבי ערמות של מוצרים על המסוע .להתחיל להחזיר את המוצרים ממסוע הקידמי לזה שלפני הקופה ,תוך כדי שלקוחות מפחדים שיחויבו פעמים …….

בכל מקרה צריך לשים לב שהיו מספר reset ים של האפליקציה לפני שהיא חזרה לעבוד , לכן איפוס של ה state ששמור לצרכי המשך עבודה אחרי כל עליה הינו שגיאה לוגית ,אחרי שהאפליקציה חזרה לסורה למשתמש צריכה להיות האופציה לבחור את ה state של ה Recovery המתאים לו מבין כל הsession הקודמים .

4.מנגנון שמירת ה Session צריך לתמוך במצב  שלאפשר לעבוד בעמדה אחרת במקרה ועמדה התקלקלה לגמרי.

5.אפשרות לעשות roll back למידע חדש שיכול לגרום לmulfunction יכול להיות שזה מידע ב cahce  בלוקלי או מידע שנמצא בשרת ואינו מאפשר למערכות להמשיך לעבוד .

עקרונות ארכיטקטונים לתוכנה שתיתמוך ב Recoverability

הפרדה בין state לפונקציונליות

מבחינה ארכיטקטונית על מנת לתמוך ב Recoverability של האפליקציה יש להקפיד על הפרדה בין state ל פונקציונליות .

state שמופרד מהלוגיקה יכול להישמר תדיר לצרכי recovery על ידי מגנוני הסיראליזציה הקיימים כמעט בכל השפות והטכנולוגיות לדוגמא:מנגנון ה pickle , shelve  בפיטון .

האויב הגדול ביותר של ההפרדה בין state לפקונציונליות זה מימוש לא נכון של class properties כלומר get accessor שמשנה את הstate של הclass ו Set Accessor של property אשר כאשר קוראים לו מספר פעמים עם אותו הערך הstate של ה class לא נשאר אותו הדבר .

שמירה מתמדת על ה state של ה אפליקציה לצרכי שיחזור המצב , הstate השמור לא צריך להיות רק חלק מה db של האפליקציה אלא גם כגיבוי חיצוני חיצוני כדוגמת קובץ או שימוש בNo sql db   מסוג document .

יכול להיות שהstate ששמור הינו מינימלי כגון שלב עריכת החשבון של לקוח , רוב הנתונים כבר נשמרו בdb

Recoverability1

 

 

תיכנון המערכת כ Occasionally Connected Systems Architecture

מערכת שתוכננה כ Occasionally Connected Systems Architecture על אף היותה בהרבה יותר מורכבת ממערכת שהינה client server פשוטה , הRecoverability שלה בהרבה יותר גבוהה ,יכול להיות מצב כמו בדוגמה שלנו שהשרת התקלקל אפשר היה לסיים בשקט את הפעילות תוך כדי שמירה של כל הפרטים לdb לוקלי אשר יסונכרן בoffline מתישהוא .

Recoverability2

 

 

logging

logging  נכון ומפורט נטול מידע בילתי רלוונטי ומידע מיותר שחוזר על עצמו כגון להפציץ את הלוג בהודעות מחזוריות תקינות .לא פעם נתקלתי בלוג של כמה גיגות מפוצץ בהודעות :Message was send או second chance exception occurred מבלי stack trace  .

והכי חביב זה הודעות wrong value ב default של switch case מבלי לציין מהו הworng value .

יכלותי לעביר סדנה של כמה חודשים עם כמות משחקי הניחושים ששיחקתי בחיי בזכות עצלות רגעית של מפתחים .

 

זמן עליה \ ירידה של המערכת סביר

לא צריך להטעין את כל המידע שבעולם ל cache בזמן עליית המערכת .אפשר לטעון מידע בJIT

כלי ניהול

רצוי שכל הניהול של האפליקציה המאפשרים בחינה של ה Log ו ניהול הdb (מחיקה של poision  messages  ) לא יהיו חלק מהאפליקציה לא של ה client  ולא של ה server

Ndis filter driver part 2

בפוסט הקודם דיברתי על מרחב הבעיה , פתרונות אפשריים ותאור הDriver בקליפת אגוז ,הפוסט הזה אני אמשיך וארחיב לגבי המימוש .

לאחר שהעתקנו אלינו את הדוגמא של הDriver מה DDK מ

C:\WinDDK\7600.16385.1\src\network\ndis\filter

קימפלנו את ה code  של Driver (עדיין עם build בסביבת command  כשאצלנו בחברה יוצאים לסרט לתכנתי הdrivers מקרינים במיוחד סרטים מהתקופה של הכלים בהם הם עובדים רק בשבוע שעבר היה זה מבצע באנטבה עם יורם גאון ואריק שני.  אנו מתאפקים עוד קצת עד שvisual studio 11 ישוחרר ותכנתי ה drivers יקפצו 30 שנה קדימה) 

והתקנו את ה filter driver או virtual machine או במחשב אחר .

(בVirtual machine יש להקפיד שהקונפיגורציה של הרשת תהייה חיבור מלא אחרת זה לא יעבוד  )

ההתקנה מאוד פשוטה מהNetwork connections .

network1

 

לאחר שהתקנו את ה driver  אנו רוצים לראות שאכן ה driver עובד והודעות שנשלחות לNIC אכן עוברות דרך ה Filter Driver שלנו .

הContainer של הודעות המידע (בשונה מהודעות הoid עליהן ארחיב פעם אחרת ) שעוברות ב Ndis drviers לסוגיו (אם זה בminiports , Filters ,protocols driverts etc' ) הינו struct מסוג Network buffers list .

מבנה ה Network buffer list

ndis2_7

 

הפרמטר של ה  NetBufferLists בcallbacks של :

SendNetBufferListsHandler,

ReturnNetBufferListsHandler,

SendNetBufferListsCompleteHandler

ReceiveNetBufferListsHandler

מורכב מ linked list של NET_BUFFER_LIST struct 

כל NetBufferList מצביע על struct של linked list of  NET_BUFFER

אשר מצביע על Strcut של MDL  linked list

כל MDL strcut מצביע על buffer של מידע .

על מנת להרגיש את הפעולה של ה filter יצרתי תוכנית קצרה ששולחת הודעת udp ,העדפתי udp כי כמות המידע שזורמת בהודעת udp קטנה בהרבה מזו של tcp אין צורך בתעבורת handshake וכד

בכוונה אני עוצר את התוכנית רגע לפני שליחת ההודעה על מנת להימנע לעצור ב breakpoints שנגרמים כתוצאה מביצוע פעולת GetHostEntery .

 

ndis2_6

 

לעניות דעתי כלי ה Debug של ndis שמוכלים ב Ndiskd.dll מאוד חזקים ומאפשרים ניתוח מהיר ופשוט של הן המידע והן הstack של ה ndis

http://msdn.microsoft.com/en-us/library/windows/hardware/ff552270(v=vs.85).aspx

אחרי שהתחברתי למחשב שמריץ את הfilter driver טענתי symbols והרצתי את תוכנית הבדיקה ,אני שם breakpoint בcallback של FilterSendNetBufferList

 

ndis2_4

מיד אחרי שליחת ההודעה אני נעצר ב breakpoint

 

 

ndis2_3

באמצאות כלי הdebug של ndis בחנתי את תוכן ההודעה .

פקודת ndiskd.nbl פורסת אוטומטית את הnbl בהינתן ה Address של ה nbl הראשון .

כפי שרואים באיור הבא ההודעה מורכבת משני mdl ים אחד מכיל את הheader של הודעת הudp והשני את הpayload של המידע ששלחנו .

 

 

ndis2_2

הNBL מכיל metadata נוסף כדוגמת ה SourceHandle המוצג באיור הבא ממנו ניתן ללמוד על מיקום ה driver שלנו בndis stack ואיך ה ndis stack  בנוי ומורכב .

 

 

ndis2_5

Direct3d11 Shader reflection interface

אחד השינויים המהותיים ב Direct3D11 הינו שהשימוש בקבצי  Effect המרכזים את כל ה shaders ואת ההגדרה של ה resources שshaders צריכים הוחלף  בשימוש בקבצים דיסקרטיים עבור כל shader כלומר שימוש בקבצים מופרדים עבור ה pixel shader , vertex shader ה shaders של ה tesselation ה geometry shaders וכד .

ההגדרה של technique שמכילה את כל הflow החל מהכניסה ל  graphic pipeline ועד ל הגדרות של הz-buffer הועברה מהeffect file לקוד של האפליקציה .

שינוי נוסף ב Direct3D11 הינו שהhlsl5 הפך להיות  Object orientedנוספה תמיכה  בinterfaces , ב ירושות ,

בדומה לאבולוציה של ++C מ C .(מעניין אם יום אחד נראה קוד hlsl דינמי סטייל python או php משהו כמו if ( !isset ($light)) die ();

אם בגירסות קודמות שלן directx  היינו יוצרים תצרותיות של הקוד על ידי שימוש ב if define  כעת  .hlsl5 נותן לנו את היכולת להגדיר class קונקרטי עבור כל טכניקה של רינדור .

מכיוון שיש decouple בין האפליקציה ל shaderים ניתן לשכלל את ה shader ים ולהרחיבם מבלי לשנות את האפליקציה , הם לא צריכים להיות חלק מתהליך הקומפילציה ובלבד שכל הresources מסופקים להם .

לעיתים נוצר צורך מצד האפליקציה לתחקר את ה shader הנטען על ידה לגבי איזה class ים הוא מכיל איזה interface ים הוא ממש ואיזה resource ים הוא מגדיר זאת על מנת שהאפליקציה תוכל להפעילו .

הדבר דומה ל  reflection ב net.

DX3D11 נותן לנו כלים לביצוע התחקור באמצעות מנגנון :Shader Reflection API אשר במרכזו נמצא com interface  :

ID3D11ShaderReflection

לאחר שטענו את ה shader אנו יכולים לקבל את ה Reference  ל ID3D11ShaderReflection על ידי:

code1

הקוד הינו רלוונטי לכל סוגי ה shaders כלומר אין משתנה שמגדיר האם אנו עובדים עם ps , vs וכד .

דוגמא לשימוש בקוד הזה נמצאת ב DynamicShaderlinkageFX11 אשר ב Direct3d sdk

Dynamic Shader Linkage 11 Sample

 

הדוגמא מראה לנו איך אפשר לשנות את סוגי התאורה על ה scene באמצעות שימוש ב dynamic linkage של shaders .

החלק שנוגע לתחקור הshader מתבצע בפונקציה

OnD3D11CreateDevice

אשר נמצאת בקובץ DynamicShaderLinkage11\DynamicShaderLinkage11.cpp

בדוגמא מודגם  אפשרות של טעינה ושינוי דינמי של  תהליך חישוב ה pixel shader באמצעות class ים שונים הממשיים class אבסטרקטי  של חישוב מנת תאורה ל pixel .

כידוע חישוב מנת האור לpixel מורכב מכמה מרכיבים :

float3 Lighting = saturate( Ambient + Diffuse + Specular

 

עבור כל אחד מהרכיבים אפשר לחשב את המקדם של עוצמת האור בדרכים שונות בתלות בסיבוך של החישוב כמות ה resource ים שנדרשים וכד

code2

 

כאן אחרי שדגמנו את ה texture אנו מכפילים את הערך בפונקציה וירטאולית :IlluminateAmbient

 

בדוגמא ניתנים שני מימושים שונים קונקרטיים ל IlluminateAmbient

אחד הפשוט :

code3

והשני מסתמך על

Hemispheres of light כלומר התחשבות גם של האור הישיר של השמים וגם האור שמוקרן מהאדמה

code4

ה shader מגדיר שני הטכנולוגיות לחישוב הAmbient light  בעוד האפליקציה צריכה לבחור עם איזה מימוש משתמשים .

האפליקציה צריכה למצא ב shader  את המשתנה שמחזיק את ה reference   ל class שממש את חישוב האור :abstractAmbientLighting ולהציב לתוכו את ה instance של ה class הנבחר.

 

שלבים בתחקור של ה shader בsample ובהצבה:

1.קבלת ID3D11ShaderReflection

2.שאילתה לגבי  כמות ה interface slots ב Shader

כלומר שאילתה באמצעות הפונקציה

pReflector->GetNumInterfaceSlots

שמחזירה את כמות ה interface pointers בshader

הסיבה לשאילתה הזו הקצאת  מערך של

ID3D11ClassInstance

שיכיל את כל הreference   ים ל class ים הקונקרטיים כמו כן נשתמש בערך הזה בהמשך כאשר נציב ל shader את מערך instance ים שבחרנו להשתמש בהם

3.עבור כל pointer ל interface ספציפי אני מעוניין לדעת את מיקומו היחסי ב shader

זאת מתבצע באמצעות :

code5

 

כעת עלינו לקבל מ הshader את ה instance עבור כל אחד מה class ים הקונקרטים :

code6

 

לקבוע עבור ה render את הps איתו הוא יעבוד ,כאשר הפרמטר השני מכיל את טבלת הinterface ים של ה class ים הקונקרטיים מסודרים לפי מספר ה slot אותם תחקרנו והפרמטר השלישי מכיל את גודל טבלת הclass ים הקונקרטיים .

code7

 

כמובן שאפשר לשחק עם ה shader במהלך תהליך ה render לחלקים שונים להפעיל class ים שונים ,דוגמא זו שהינה פשוטה קובעת את ה ps רק פעם אחת במהלך render ,ניתן כמובן לחלקים קרובים לקבוע pixel shader מורכב ויקר מבחינת צריכת משאבים ולחלקים רחוקים להשתמש ב ps יותר פשוט .

More Posts Next page »