קרנל ו-++C...

voguemaster

New member
בוא נגדיר את זה כך

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

אלדד28

New member
אני לא מכיר כמעט משחקים שעובדים

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

eyalbd

New member
זה מיתוס ועוד איך

קודם כל אפשר תמיד לכתוב בסיגנון פרוצדורלי ואז זה Better C. לא יותר איטי. אבל אתה כנראה לא התכוונת לזה אלא לסיגנון תיכנות. כלומר זה לא השפה אלא הפיצ'רים שאני בוחר שעלולים לגרום לקוד לא יעיל. אתה לא חייב לבנות היררכיות. תמיד אפשר להשתמש בclass ל Data Abstraction מבלי להפסיד טיפה ביצועים. CTOR ו-DTOR הם חיוניים ב-++C ממש כשם שהם חיוניים ב-C. ומהו fopen אם לא CTOR ל *FILE? רק ב-C לא קוראים לזה כך וזה לא אוטומטי. ועוד, dynamic dispach בעזרת vtbl יותר מהיר מבחירת נתיב קוד ע"י switch השימוש בtemplates לא גורם כשלעצמו לאובדן ביצועים - הנה לך עוד Feature מצויין שאפשר להשתמש בו בקרנלים. החיסרון היחיד היום הוא אולי פחות בשלות של קומפיילרים וספריות. אבל גם זה יבוא.
 

אלדד28

New member
לא התייחסת לדברים שדיברתי עליהם.

TEMPLATES אכן אינם גורמים לירידות בביצועים. ולא דיברתי על קומפיילרים, כי הנחת היסוד שלי היא שבתיאוריה הקומפיילרים של C ושל ++C מושלמים. אולי זה לא נכון היום - זה יהיה נכון מחר. גם על היררכיות לא דיברתי. אני מדבר על דברים כמו stream-ים או string-ים. אתה יכול לא להשתמש בהם ואז יהיה לך better C, אבל זו לא ההגדרה של ++C. אני מסתכל על תוכנה ב-C שעוברת "המרה מקסימלית" ל-++C, עם STL ועם כל FEATURE אפשרי, וזה גורם לירידה בביצועים. בדיוק בשביל זה יש את ++Efficient C, שמסביר איפה צריך להיזהר.
 

MotiAd

New member
חחח... הורשה באסמבלי...

אתה יודע מה? חשבתי על זה (וירדתי מהרעיון בערך באותו הרגע. אני לא חושב ששפת אסמבלי נועדה לזה כי יש לה מטרות אחרות ואני לא אעשה לה את העוול הזה.) בכל אופן אני כבר בחרתי את השפה שאני רוצה לכתוב לה קומפיילר במסגרת קורס קומפילציה באוני'.חחחח. בכל אופן אני לא מתכוון להמיר את ההורשה וכל המנגנונים האלו לאסמבלי. אני רק רוצה לקבל מושג ירוק על איך לבצע את הדברים בשפה עילית ואח"כ להעביר ל-ASM. זה יותר קל מבחינתי (מאשר לעבוד עם רשימות מקושרות ב-ASM ולראות איפה מגדילים את EDI כל פעם.) אל תשכח שאני צריך ב-ASM גם לתכנן את כל המראה של המערכת (חלוקה זיכרון - דפים או רק סגמנטים? ממימוש של תהליכים וכו') דברים שאני לא מתכוון לתכנון כ"כ ב-++C כי כשאני אעביר את הקוד ל-ASM זה יהיה מוכן (אני אוהב לעבוד על כמה דברים במקביל). אני מקווה שהבנתם את הראש שלי ואת הדרך שבה אני חושב. שלכם, מוטי.
 

annefan

New member
אני לא מצליח להבין את הראש שלך

למה באסמבלי? למה לא ב-C? (או ++C אם אתה רוצה ויכול?)
 

voguemaster

New member
מוטי

גם אני אוהב ASM אבל נראה לי שנסחפת קצת
 

eyalbd

New member
אני חושב ש std::string לא יותר איטי

בשביל מה שהוא נותן. אתן לך דוגמא פשוטה - קריאת שורה מקובץ טקסט. הקוד הבא:
string s; getline(cin, s);​
לא דומה בכלל ל fgets של C, כי הוא עושה בשבילך הרבה הרבה יותר. אם אתה רוצה קוד שקול לחלוטין ב-C תצטרך להקצות בלוק ולהגדיל אותו במידת הצורך. זה כבר לא יותר מהיר (אבל זה הרבה יותר נכון). אין לך שום בעיה לממש את כל הפונקציות של std::string באסמבלי (לדעתי זה עוד יבוא). הדבר היחיד ש"יקר" הוא הקצאה דינמית של זיכרון אבל אתה תמיד יכול לייעל זאת ע"י כתיבת מנהל זיכרון ספציפי שייעל. להזכירך std::basic_string הוא template שאחד הפרמטרים שלו הוא allocator - שנה אותו ותשפר ביצועים. כנ"ל למשל וקטור עבור טיפוס נתונים ספציפי. לגבי IOSTREAM - כבר דיברנו על זה כאן - בתיאוריה זה צריך להיות יותר מהיר מSTDIO. העניין כאן הוא רק בשלות של הספריות. ב-STDIO כבר מיצו כל אפשרות של אופטימיזציות. ב IOSTREAM עוד רחוקים מזה. למרות זאת יש ספריות שכן מגיעות כמעט לביצועים של STDIO
 

אלדד28

New member
זה לא מדויק.

יש קריאות מיותרות לפונקציות. למשל, בוא ניקח משהו פשוט - נניח שם אובייקט. האובייקט מקבל בתור פרמטר מחרוזת (לא משנה אם זו string או *char), וצריך לשמור את המידע. אתה יכול להשתמש ב-*char או ב-string. חוץ מפעולת השמירה, מדי פעם תיקרא פונקציית GetName, וזהו. שום דבר מעבר. בוא נשווה - אם אני משתמש ב-*char אני צריך לעשות: (אני מניח שה-sName היא אכן מחרוזת תקינה, ומניח שיהיה זכרון - שתי הבעיות הללו ממילא זהות לשימוש ב-string או ב-*char במקרה הזה).
object::eek:bject(const char *sName) { size_t s = strlen(sName); m_sName = new char[s+1]; memcpy(m_sName, sName, s); m_sName = '\0'; }

לעומת זאת, בשימוש ב-string, היינו עושים:
object::eek:bject(const char *sName) : m_sName(sName) { }​
הפונקציה שתיקרא, לפחות במימוש ב-MSVC, היא (basic_string(const _Elem *_Ptr. ה-ctor הנ"ל עושה את כל הדברים הבאים: 1. קריאה ל-Default CTOR של mybase שלו - כלומר ל-String_val_. 2.קריאה לפונקציה Tidy_, שמאפסת את המחרוזת (מיותר). 3. אח"כ הוא קורא לפונקציה assign. פונקציית ה-assign עושה את הדברים הבאים: 3.1. בודקת את אורך המחרוזת על ידי קריאה לפונקציה הסטטית length של ה-Traits של המחרוזת. 3.2. קוראת ל-assign נוספת יחד עם האורך, שעושה את זה: 3.2.2. בודקת אם הגודל שקיבלה נמצא בתוך ה-ptr שקיבלה כדי לראות אם אולי זה substring... 3.2.2. קוראת ל-Grow_, שעושה בדיקות שונות ומשונות על הקלט שלה כדי להחליט מה היא צריכה לעשות. 3.2.3. קוראת ל-Copy_ כדי להגדיל את המקום המוקצה בזכרון. Copy_ בעצמה עושה עוד כל מיני דברים שנעזוב אותם עכשיו. 3.2.3. שמה NULL בסוף המחרוזת. אני חושב שאין שום ספק מי יותר בזבזני. עכשיו, כמובן שכל זה בא כדי לספק יכולות גנריות וכו' - אבל לא תמיד צריך את זה - מה שמחזיר אותי לטענתי המקורית. ככל ששפה היא גבוהה יותר - היא בזבזנית יותר. זה Trade off ברור וידוע. ככל שאתה גנרי יותר, ככה אתה עושה יותר פעולות מיותרות. העניין הוא שיש קו אדום מסוים, שבו ה-tradeoff הזה מפסיק להשתלם. למשל, אפשר לכתוב באסמבלי, ואז זה יהיה (תיאורטית - רק אם אתה באמת תוכניתן מבריק) מהיר יותר, אפשר לעלות מדרגה ל-C, ואפשר לעלות עוד 20 מדרגות ל - ++C. פה, לדעתי ה-TRADE OFF עדיין משתלם. אם עולים עוד יותר - נגיד, ל-JAVA - זה מפסיק להשתלם ונעשה בזבזני מדי. ++C איטית יותר מ-C. זו עובדה. אפשר, בתכנות זהיר וחסכוני, לדאוג למינימום שבמינימום של PENALTY. אי אפשר להעלים את המחיר - אלא אם משתמשים אך ורק ב-FEATURE-ים שאינם גוזלים בכלל זמן ב-RUNTIME - כמו למשל TEMPLATES שהזכרת.
 

eyalbd

New member
בוא ניתן למספרים לדבר

כתבתי בנצ'מרק די פשוט והתוצאות שוות. שים לב שכל הפונקציות שאתה מתאר הן inline וחלקן ייתכן שהו noop בזמן ריצה. הקוד המצורף מראה שהביצועים של הקוד שאתה נותן ובין שימוש פשוט של std::string זהים פחות או יותר לפעמים אחד מהיר יותר ולפעמים השני. הקוד מצורף למטה (בדקתי עם GCC על לינוקס - לא יודע אם יעבוד על חלונות). מה שעשיתי הוא בניה של std::string ו-*char במשך 3 שניות. ספרתי את מספר הלולאות עבור שני המקרים. אתה יודע מה? אני קצת מופתע כי string יותר מהיר מעט (בהחלט ייתכן שיש לי באג). הנה התוצאות:
Results (14399312 / 14001730), Ratio: 1.0284 [char* / string] Results (13520723 / 13960761), Ratio: 0.96848 [char* / string] Results (13361509 / 14782539), Ratio: 0.903871 [char* / string] Results (13730967 / 15273513), Ratio: 0.899005 [char* / string] Results (13718939 / 14261259), Ratio: 0.961973 [char* / string] Results (13596139 / 14954997), Ratio: 0.909137 [char* / string] Results (13970072 / 15179357), Ratio: 0.920334 [char* / string]​
בסוגריים מספר הלולאות. ברוב המקרים המספר של *char היה נמוך יותר. בקיצור הטענה ש string יותר איטי אין לה אחיזה רבה במציאות (למעט אולי מקרים שבהם אין צורך בהקצאה דינמית) הנה הקוד של התוכנית כולה:
#include <string> #include <iostream> #include <signal.h> #include <unistd.h> using namespace std; std::string string_dup(const char* s); char* char_dup(const char* s); //----------------------------------------------------------------------------- bool done_loop = false; void alarm_handler(int) { done_loop = true; } //----------------------------------------------------------------------------- int main() { // do a little benchmark // int i; int alarm_delay = 3; // Set signal handler for alarm // signal(SIGALRM, alarm_handler); // ask for alarm and call string_dup for alarm_delay seconds // alarm( alarm_delay ); for (done_loop = false, i=0; !done_loop; ++i) { string s = string_dup("Just a String"); } int string_count = i; // ask for alarm and call char_dup for alarm_delay seconds // alarm(alarm_delay); for (done_loop = false, i = 0; !done_loop; ++i) { char* p = char_dup("Just a String"); delete []p; } int char_count = i; // Print results // cout << "Results (" << char_count << " / " << string_count << "), Ratio: " << double(char_count) / string_count << " [char* / string]" << endl; } //----------------------------------------------------------------------------- std::string string_dup(const char* s) { return std::string(s); } char* char_dup(const char* s) { int len = strlen(s) + 1; char* p = new char[len]; memcpy(p, s, len); return p; }​
 

אלדד28

New member
בוא ניתן למספרים לדבר

לא אהבתי את שיטת שלוש השניות. אני מעדיף לעשות את הפעולה X פעמים ולבדוק זמנים - אז עשיתי את זה. קודם כל, הנה התוצאות (בשבילך התאמתי את זה לשלוש שניות פחות או יותר) - מדובר, אגב, ב - 1,100,000 פעולות.
Results: string dup = 2812ms, char dup = 1125ms. Results: string dup = 2750ms, char dup = 1078ms. Results: string dup = 2750ms, char dup = 1079ms. Results: string dup = 2843ms, char dup = 1110ms. Results: string dup = 2812ms, char dup = 1125ms. Results: string dup = 2844ms, char dup = 1109ms. Results: string dup = 2813ms, char dup = 1094ms. Results: string dup = 2828ms, char dup = 1109ms. Results: string dup = 2859ms, char dup = 1110ms. Results: string dup = 2797ms, char dup = 1093ms.​
כלומר, פי שלוש לטובת char. עברתי ל-RELEASE, והתוצאות השתפרו פלאים, אבל עדיין יש בין 10% ל-20% לטובת ה-char:
Results: string dup = 547ms, char dup = 437ms. Results: string dup = 531ms, char dup = 438ms. Results: string dup = 531ms, char dup = 438ms. Results: string dup = 515ms, char dup = 453ms. Results: string dup = 516ms, char dup = 438ms. Results: string dup = 516ms, char dup = 437ms. Results: string dup = 532ms, char dup = 437ms. Results: string dup = 531ms, char dup = 438ms. Results: string dup = 531ms, char dup = 422ms. Results: string dup = 515ms, char dup = 453ms.​
והתוכנית כולה (מבוססת על שלך):
#include <windows.h> #include <string> #include <iostream> using namespace std; std::string string_dup(const char* s); char* char_dup(const char* s); int main() { unsigned int num_of_chars = 1100000; unsigned int nStr, nChar; int i,j; for (j = 0; j < 10; j++) { nStr = GetTickCount(); for (i = 0; i < num_of_chars; i++) { string s = string_dup("Just a String"); } nStr = GetTickCount() - nStr; nChar = GetTickCount(); for (i = 0; i < num_of_chars; i++) { char* p = char_dup("Just a String"); delete []p; } nChar = GetTickCount() - nChar; cout << "Results: " << "string dup = " << nStr << "ms, char dup = " << nChar << "ms." << endl; } return 0; } //----------------------------------------------------------------------------- std::string string_dup(const char* s) { return std::string(s); } char* char_dup(const char* s) { int len = strlen(s) + 1; char* p = new char[len]; memcpy(p, s, len); return p; }​
I REST MY CASE - כמו שאמרתי בהתחלה, יש הבדלי מהירות בין C לבין ++C. הם קיימים בתיאוריה ובפרקטיקה גם יחד. בספר (המומלץ מאוד מאוד) של Bulka ושל Mayhew, הנקרא ++Efficient C, הם אומרים ככה -
We concede that in general, when comparing a C program to a C++ version of what appears to be the same thing, the C program is generally faster. However, we also claim that the apparent similarity of the two progams typically is based on their data handling functionality, not their correctness, robustness, or ease of maintenance.​
כלומר, כמו שאמרתי לאורך כל הדרך, תוכנה ב-C תהיה יותר מהירה באופן עקרוני, אבל היתרונות של ++C יותר ממכסים על החסרון היחסי הזה, כיוון שב-99% מהמקרים (אם אתה יודע מה אתה עושה), בסופו של דבר ++C מספקת לך כלים שכתיבה מחודשת שלהם ב-C תגרום לתוכנית לרוץ באיטיות גדולה יותר. למשל, אם היינו מכניסים לתמונה גם וקטור שגדל עם הזמן, הגרסה של C הייתה איטית יותר מהגרסה של ++C, בגלל ש-STL עושה עבודה מצוינת.
 

voguemaster

New member
אני לא יודע לגבי המהירות

כי אני לא בטוח שיש ביסוס לטענה שלך שבתיאוריה IOSTREAM צריכה להיות מהירה יותר, אבל בוא נתעכב רגע על מה ש-string נותנת לך. הכתיבה קלה יותר והיא מונעת במקרה זה buffer overflow (אם כי לא ברור ב-100%, נדמה לי שיש דרך בכל זאת, אי אפשר להגן בצורה מושלמת במצבים כאלה, צריך לקטוע את ה-INPUT ידנית).
 

eyalbd

New member
אתן לך הסבר קצר

לדוגמא printf - היא מכילה אינטרפרטר לפורמט שאותו היא מריצה בזמן ריצה. כאשר מוצאים type מסויים קוראים לפונקציה (או מבצעים קוד) שממיר אותו למחרוזת. עם cout יש קריאה ישירה לאופרטור ללא parsing של פורמט בזמן ריצה. בתיאוריה זה צריך להיות מהיר יותר. בפרקטיקה עדיין לא.
 

זהיר

New member
++C איטית מ C ? המממ...

Bjarne Stroustrup מראה ש ++C יכולה להיות מהירה מ C פי 4 ויותר תכנתו בזהירות
 

erezsh

New member
אוי השטויות שהוא עשה שם

ברור שעם תכנות כזה C תהיה יותר איטית...
 

DNile

New member
שים לב לאיך משנים את ההדגשה,

והמשפט משנה משמעותו: Bjarne Stroustrup מראה ש ++C יכולה להיות מהירה מ C פי 4 ויותר תכנתו בזהירות
 

זהיר

New member
אם כבר בדקדוקי עניות אתה עוסק

אז בהגדרה ++C לא יכולה להיות איטת מ C, מפני שכל קוד שנכתב ב C יכול להכתב גם ב ++C (פרט לחלק מהתוספות של C99, ולמיטב ידיעתי אינם משפיעים על מהירות). וההדגשה היתה על מהירות - כי זה היה בתשובה לטענה שהיא איטית.
 

erezsh

New member
בדיוק ההפך

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