איך משווים נכון מהירות בין גרסאות תוכנה ב-Windows
· עודכן בתאריך: · Go Komura · Windows, Benchmark, Performance, Profiling, Power Management
היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 16 Mar 2026)
- פרסום ראשון
לצטט את המאמר הזה(DOI (ארכיון רשום): 10.5281/zenodo.22173516)
מזהי ה־DOI שלהלן מפנים לגרסאות שנשמרו בעבר בארכיון, ועשויים שלא להתאים לטקסט הנוכחי. להפניה לטקסט הנוכחי, השתמשו בכתובת של דף זה.
Go Komura (2026). איך משווים נכון מהירות בין גרסאות תוכנה ב-Windows. KomuraSoft LLC. https://comcomponent.com/he/blog/windows-benchmark-comparing-program-versions/
- DOI (ארכיון רשום)
- 10.5281/zenodo.22173516
- DOI (הגרסה האחרונה שנרשמה)
- 10.5281/zenodo.22173517
רוצים להשוות גרסה A וגרסה B של תוכנה ב-Windows. הדבר הכי גרוע שאפשר לעשות הוא להריץ כל גרסה פעם אחת על אותו מחשב, ואז להגיד “נראה ש-B מהיר ב-8%”.
יכול להיות שה-8% האלה הם באמת הבדל בקוד. אבל ב-benchmark על Windows, הסיפור הנפוץ הוא שההבדל הגיע מ-Power mode, Power plan, חום, עדכון ברקע, search indexing, virus scan, affinity, סדר ההרצה או מצב cache. צריך לנטרל את התנאים האלה אחד-אחד.
flowchart TB
accTitle: מה באמת עומד מאחורי "נראה שמהיר ב-8%"
accDescr: תרשים שמראה שהבדל מהרצה בודדת בכל גרסה יכול להיות הבדל בקוד, אבל בדרך כלל זה חשמל, חום, רעש או cache, וצריך לנטרל את התנאים אחד-אחד.
one1["הרצה אחת לכל גרסה, ואז השוואה"] --> dif2["מתקבל 'נראה שמהיר ב-8%'"]
dif2 -->|"יכול להיות"| code1["הבדל אמיתי בקוד"]
dif2 -->|"הגורם הנפוץ"| env1["חשמל, חום, רעש, cache"]
env1 --> crush1["מנטרלים תנאים אחד-אחד"]
איור 1: הבדל מהרצה בודדת הוא לא בהכרח הבדל בקוד. אי אפשר לקבוע עד שמנטרלים את התנאים.
המאמר הזה מרכז דרך להשוות מהירות הרצה בין גרסאות שונות של תוכנה ב-Windows, כמה שיותר קרוב להבדל שבקוד עצמו.
היעד העיקרי הוא Windows 11, אבל רוב הפקודות כמו powercfg ו-start עובדות באותה צורה גם ב-Windows 10.
מונחים שכדאי לקבע מראש
בגוף המאמר מופיעים מונחים באנגלית. כדי לא להיתקע בהופעה הראשונה, נרכז אותם כאן.
| מונח | משמעות |
|---|---|
| ETW | Event Tracing for Windows. תשתית tracing שכלולה ב-Windows. אפשר לרשום יחד אירועים שמגיעים מ-OS, מ-drivers ומיישומים |
| WPR / WPA | Windows Performance Recorder ו-Windows Performance Analyzer. כלי שרושם traces של ETW, וכלי שפותח ומנתח אותם. שניהם כלולים ב-Windows ADK |
| clean boot | הליך שעוצר services ו-startup apps שאינם של Microsoft, ומאתחל בהרכב מינימלי. משתמשים בו כדי להקטין רעש מתוכנות resident |
| PGO | Profile-Guided Optimization. מנגנון שלוקח סטטיסטיקה של branches וקריאות מהרצה אחת, ומשתמש בה להחלטות אופטימיזציה ב-build הבא. תנאי ה-build משתנים, ולכן זה סעיף לבדיקה אם שני הצדדים באמת בני השוואה |
| p95 / p99 | percentile. כשמסדרים את כל ה-runs מהמהיר לאיטי, הערך שנמצא ב-95% / 99% מלמטה. “אחת מכל 20 הרצות איטית מזה” זה p95 |
| NUMA | Non-Uniform Memory Access. ארכיטקטורה שבה המרחק מה-CPU לזיכרון אינו אחיד. מהירות הגישה לזיכרון משתנה לפי ה-node שעליו רצה התוכנית |
| core parking | מנגנון ניהול חשמל שמרדים logical processors שלא בשימוש כשהעומס נמוך |
קודם המסקנה
אם מצמצמים למה שבאמת משפר reproducibility, אלה שש הנקודות הבאות.
-
קובעים קודם מה רוצים להשוות האם מחפשים הבדל בקוד, או חוויית משתמש אמיתית. הסביבה שצריך ליישר משתנה בהתאם.
-
מתעדים Power mode ו-Power plan כשני דברים נפרדים ב-Windows, אם מערבבים ביניהם, ההשוואה נוטה להפוך להשוואת מדיניות חיסכון בחשמל של ה-OS.
-
מפרידים בין ההרצה הראשונה הקרה לבין steady state אחרי שהמערכת התחממה מהיר רק בפעם הראשונה, או איטי רק בהמשך — זה לא נדיר.
-
מריצים לסירוגין, למשל A→B→A→B אם מריצים קודם את כל A ורק אחר כך את B, נספגים אצל צד אחד חום ומצב פעילות ברקע.
-
מסתכלים לא רק על הממוצע, אלא גם על החציון ועל הפיזור ערך חריג אחד יכול לעוות את כל התמונה. הממוצע שביר יותר ממה שנראה.
-
אם ההבדל קטן, יורדים לסיבה עם ETW / WPR דיון לפי תחושה בלבד משאיר את שני הצדדים בלי ראיה, והוויכוח לא זז.
ב-diagram, solid line מציינת relation שתמיד מתקיים ו-dashed line מציינת relation מותנה (התנאים מופיעים בהסבר של כל relation ב-detail page). הרשימה המלאה של ה-relations (סה”כ 25, כולל evidence ו-certainty) וההגדרות של ה-concepts המרכזיים נמצאות ב-detail page של ה-knowledge map (ביפנית). Data: JSON-LD / Turtle
קודם קובעים מה רוצים להשוות
“השוואת מהירות” נשמע כמו דבר אחד, אבל בפועל יש שני סוגים.
1. השוואה שמחפשת הבדל בקוד
השוואה שרוצה לדעת אם המימוש עצמו נהיה מהיר יותר בעקבות שינוי אלגוריתם, שינוי מבנה נתונים, אופטימיזציה של ה-compiler, או עדכון runtime.
במקרה הזה מקטינים ככל האפשר את רעש הסביבה. session ייעודי ל-benchmark, Power mode מקובע, התראות כבויות, דיכוי של search indexing וסנכרון, ואם צריך — גם clean boot.
2. השוואה שמחפשת חוויית משתמש אמיתית
השוואה שרוצה לדעת מה המשתמש מרגיש בפועל על Windows יומיומי אחרי ההפצה.
במקרה הזה אסור לבטל את כל הרעש שקיים במציאות. השוואה בסביבה יומיומית שמכילה סנכרון OneDrive, Defender, התראות והגדרות חשמל רגילות מתקרבת יותר לתוצאה מציאותית.
אם מערבבים בין השניים, המסקנה מתעוותת. דברים כמו “במעבדה זה 12% יותר מהיר, במציאות זה בתוך הרעש” או “במציאות זה מהיר יותר, אבל ב-CPU time אין שינוי” קורים בקלות.
flowchart TB
accTitle: לא מערבבים בין שני סוגי ההשוואה
accDescr: תרשים שמראה שבהשוואה שמחפשת הבדל בקוד מקטינים רעש סביבה, ובהשוואה שמחפשת חוויית משתמש אמיתית משאירים רעש יומיומי, וערבוב בין השניים מעוות את המסקנה.
q5["מה רוצים להשוות"] -->|"הבדל בקוד"| lab1["סביבת מעבדה בלי רעש"]
q5 -->|"חוויית משתמש אמיתית"| real1["סביבה יומיומית עם רעש"]
q5 -.->|"אם מערבבים"| twist2["המסקנה מתעוותת"]
איור 2: הסביבה שצריך ליישר הפוכה לפי המטרה, ולכן קובעים קודם באיזה סוג השוואה מדובר.
מה בעיקר מזיז תוצאות ב-Windows
קודם נרכז בגסות מה גורם לתוצאות לקפוץ.
| שכבה | גורם לתנודתיות | דוגמה טיפוסית |
|---|---|---|
| חומרה | CPU / GPU, זיכרון, SSD, קירור | מחשב נייד דק, יש או אין מעמד קירור |
| קושחה | BIOS / UEFI, בקרה של היצרן | מדיניות חיסכון בחשמל, בקרת מאוורר |
| OS | Windows build, drivers, מצב עדכון | גם על אותו מחשב, ההתנהגות משתנה אחרי עדכון |
| חשמל | AC / DC, Power mode, Power plan | על סוללה זה עולם אחר |
| חום | טמפרטורת חדר, מאוורר, עומס קודם | turbo רק בהרצה הראשונה, ירידת תדר בהמשך |
| רקע | Update, Defender, סנכרון, התראות | סריקה או סנכרון רצים באמצע ההרצה |
| scheduling | priority, affinity, NUMA | שיבוץ ה-CPU משתנה לפי המחשב |
| נתונים / cache | cache של ה-OS, cache של היישום | איטי רק בפעם הראשונה, מהיר רק מהפעם השנייה ואילך |
| תנאי build | Debug / Release, PGO, לוגים כן/לא | בפועל משווים דברים שונים לגמרי |
בקיצור, גם “אותו מחשב Windows” הוא ניסוי אחר אם התנאים לא מיושרים.
flowchart TB
accTitle: בלי תנאים מיושרים זה ניסוי אחר
accDescr: תרשים שמראה שגם כשמודדים על אותו מחשב Windows, אם תנאים רב-שכבתיים מחומרה ועד חשמל, חום, רקע ותנאי build לא מיושרים, זה בפועל ניסוי אחר, ורק קיבוע של התנאים הופך את זה להשוואה.
same1["מדידה על אותו מחשב Windows"] -.->|"התנאים לא מיושרים"| oth1["בפועל, ניסוי אחר"]
same1 -->|"קיבוע ותיעוד של תנאים בכמה שכבות"| cmp1["רק אז זו השוואה"]
איור 3: גם כשהמחשב זהה, אם התנאים בין השכבות לא מיושרים, ההשוואה לא מחזיקה.
מפרידים בין Power mode ל-Power plan
זו נקודה חשובה מאוד.
ב-Windows יש Power mode באפליקציית Settings, ויש Power plan מסורתי (תוכנית החשמל שרואים ב-powercfg).
הם נראים דומים ולכן מערבבים ביניהם. טיפול רשלני הופך את תנאי ההשוואה לעמומים, ו-reproducibility של התוצאות נעלם.
באפליקציית Settings של Windows בוחרים Power mode דרך Settings > System > Power & battery.
לפי התיעוד של Microsoft אפשר להחליף בין Best power efficiency, Balanced ו-Best performance לכל אחד מ-Plugged in / On Battery. בנוסף, כש-Power mode משתנה, זה משפיע גם על הגדרות החשמל מאחוריו ועל התנהגות PPM (Processor Power Management). כלומר, הבדל רק כאן יכול לשנות מדיניות של core parking ושל scaling של ביצועים.
Power plan, לעומת זאת, הוא תוכנית חשמל מסורתית כמו Balanced או High performance.
בודקים אותה עם powercfg /list או powercfg /getactivescheme.
מה שמסבך כאן הוא שב-Windows יש גם overlay של Power mode וגם Power plan. אם מציירים את הקשר, זה נראה כך:
flowchart TB
subgraph upper["שכבה עליונה: Power mode - overlay"]
direction LR
M1["Best power efficiency"]
M2["Balanced"]
M3["Best performance"]
end
subgraph lower["שכבה תחתונה: Power plan"]
direction LR
P1["Balanced"]
P2["High performance"]
P3["custom plan"]
end
UI["אפליקציית Settings — Power mode תחת Power and battery"] --> upper
CLI["מעבר עם powercfg /setactive"] --> lower
upper --> PPM["ההגדרה שבאמת פועלת — PPM ותת-קבוצת graphics"]
lower --> PPM
AC["חיבור AC או סוללה"] --> PPM
PPM --> RESULT["תקרת תדר / core parking / scaling של ביצועים"]
איור 4: שתי השכבות — Power mode (overlay) ו-Power plan — יחד עם AC/DC קובעות את הגדרת החשמל שבאמת פועלת.
אי אפשר לקבוע את ההתנהגות בפועל רק מהשכבה העליונה או רק מהתחתונה. לכן בתוצאת benchmark, לפחות תעדו:
- האם זה AC או סוללה
- מהו ה-Power mode
- מהו ה-Active power plan
תוצאת benchmark בלי שלושת אלה לא ניתנת לשחזור כשחוזרים אליה אחר כך.
flowchart TB
accTitle: שלושת הפרטים שתמיד מתעדים
accDescr: תרשים שמראה שאם לא מתעדים יחד עם התוצאה האם זה AC או סוללה, מהו ה-Power mode ומהו ה-Active power plan, אי אפשר לשחזר את התנאים אחר כך.
r1["AC או סוללה"] --> rec2["מתועד יחד עם התוצאה"]
r2["Power mode"] --> rec2
r3["Active power plan"] --> rec2
rec2 --> rst1["אפשר לשחזר את התנאים אחר כך"]
איור 5: שלושת הפרטים סביב החשמל הם המינימום שבלעדיו התוצאה עצמה לא ניתנת לשחזור.
קודם מקבעים תנאי חשמל
-
מחשב נייד תמיד משווים על AC הפעלה מסוללה נוטה להכניס הגבלה שלא התכוונתם אליה.
-
מקבעים את ה-Power mode ל-benchmark, מנסים קודם
Best performance. -
מתעדים את ה-Active power plan שומרים עם
powercfgאת הערך הנוכחי.
powercfg /list
powercfg /getactivescheme
הפלט של powercfg /list מוצג בתיעוד של Microsoft בצורה הבאה. ל-plan הפעיל מתווסף * בסוף השורה. בסביבה יפנית, הכותרת ושם ה-plan מופיעים ביפנית.
Existing Power Schemes (* Active)
-----------------------------------
Power Scheme GUID: {guidPlan1} (Balanced) *
Power Scheme GUID: {guidPlan2} (Power saver)
את ה-GUID שהתקבל כאן מעתיקים כמו שהוא לעמודת power_plan בקובץ התוצאה. הנקודה היא לתעד GUID, לא שם. גם כשכתוב “Balanced”, ייתכן שזו תוכנית אחרת ששוכפלה או הותאמה אישית.
- אם צריך, עוברים ל-High performance
# Balanced
powercfg /setactive 381b4222-f694-41f0-9685-ff5bb260df2e
# High performance
powercfg /setactive 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c
אפשר להחליף Power mode משורת פקודה?
זו נקודה שקל להיתקע בה. ברשימת אפשרויות שורת הפקודה המתועדות של powercfg אין אפשרות לבחור מחדש את Power mode (ה-overlay) עצמו. ההליך הרשמי הוא דרך Settings > System > Power & battery באפליקציית Settings.
מצד שני, powercfg כן תומך בקריאה ובכתיבה של ערכי ההגדרה של סכימת ה-overlay. בתיעוד כתוב:
- אם מעבירים ל-
powercfg /qאת ה-alias ואת תת-הקבוצה של ה-overlay, אפשר לקרוא את ההגדרות בצד ה-overlay powercfg /setacvalueindexו-/setdcvalueindexניתנים לשימוש גם בסכימת overlay- אם לא מציינים סכימה, היעד הוא ה-overlay הפעיל כרגע (ואם אין overlay, ה-Power plan הנוכחי)
- את רשימת ה-aliases בודקים עם
powercfg /aliases
כלומר, מה שאפשר לעשות בפקודה הוא “לקרוא ולכוונן את תוכן ה-overlay שפועל עכשיו”, לא “לבחור איזה overlay פעיל”. כנוהל reproducibility ל-benchmark, מעשי יותר לקבע את Power mode ידנית באפליקציית Settings, ולכתוב את הערך בתוצאה. בנוהל כותבים במפורש “הוגדר Power mode = Best performance”, ובודקים על המסך בכל הרצה.
flowchart TB
accTitle: מה powercfg יכול ומה לא
accDescr: תרשים שמראה ש-powercfg יכול לקרוא ולכוונן את תוכן ה-overlay הפעיל, אבל אין אפשרות לשנות איזה overlay נבחר, ולכן מקבעים את Power mode ידנית באפליקציית Settings ומתעדים את הערך.
pc1["powercfg"] -->|"יכול"| rw1["קריאה וכוונון של תוכן ה-overlay"]
pc1 -.->|"לא יכול"| sel1["שינוי איזה overlay נבחר"]
sel1 --> hand1["קיבוע ידני באפליקציית Settings ותיעוד"]
איור 6: אי אפשר לשנות בפקודה איזה overlay נבחר, ולכן מקבעים ידנית ומתעדים.
“High performance לא מופיע” זה מצב רגיל
גם זו נקודה שנתקעים בה. לפי התיעוד של Microsoft, במכשירים עם Modern Standby מותרות רק Balanced, או plan שנגזר מ-Balanced. לכן זו לא בהכרח תקלה של “High performance נעלם”. ייתכן שכך הדגם תוכנן.
בנוסף Microsoft מציינת: אם אי אפשר לשנות את Power mode, ייתכן שנבחר custom power plan, ולכן כדאי לנסות קודם Balanced. כשה-UI של Power mode לא זז, כאן כדאי לחשוד קודם.
flowchart TB
accTitle: איך לקרוא מקרה שבו High performance לא מופיע
accDescr: תרשים שמראה שבמכשירים עם Modern Standby מותרות רק Balanced או plan שנגזר ממנה, ולכן היעדר High performance הוא תכנון, וכש-UI של Power mode לא זז חושדים קודם ב-custom plan ומנסים Balanced.
nohp1["High performance לא נמצא"] --> ms1["אם יש Modern Standby, זה לפי התכנון"]
nomv1["ה-UI של Power mode לא זז"] --> cst1["חושדים ב-custom plan"]
cst1 --> bl1["מנסים קודם Balanced"]
איור 7: plan חסר או UI שלא זז אינם בהכרח תקלה. קודם בודקים את תכנון הדגם ואת ה-plan שנבחר.
מצמצמים רעש ברקע
Windows, גם כשרוצים למדוד בשקט, מריץ ברקע עדכונים, indexing וסריקות. קודם מקטינים את הכמות הזו.
קודם מאתחלים ומחכים שהמערכת תירגע
אחרי שינוי הגדרה, מאתחלים פעם אחת. לא מריצים מיד אחרי login, אלא מחכים כמה דקות. מיד אחרי אתחול, Update, indexing, סנכרון, Defender ותוכנות resident עדיין עסוקים.
flowchart TB
accTitle: מאתחלים ומחכים שהמערכת תירגע
accDescr: תרשים שמראה שאחרי שינוי הגדרה מאתחלים פעם אחת, ומכיוון שמיד אחרי האתחול Update, indexing, סנכרון ו-Defender עדיין רצים, לא מריצים מיד אחרי login אלא מחכים כמה דקות לפני שמתחילים למדוד.
chg1["משנים הגדרה"] --> rb1["מאתחלים פעם אחת"]
rb1 --> wt1["מחכים כמה דקות אחרי login"]
wt1 --> ms2["רק אז מתחילים למדוד"]
rb1 -.-> nzz1["מיד אחרי אתחול, תוכנות resident עדיין עסוקות"]
איור 8: מתחילים למדוד רק אחרי שפעילות הרקע נרגעה, אחרי האתחול.
להשוואה קפדנית משתמשים ב-clean boot
Microsoft מתארת הליך שמגיע להרכב startup מינימלי בעזרת clean boot.
עוצרים services שאינם של Microsoft עם msconfig, ומבטלים Startup apps ב-Task Manager.
זה חזק להקטנת רעש. אבל זה מתרחק מסביבת שימוש יומיומית, ולכן מתאים ל”השוואת מעבדה שמחפשת הבדל בקוד”.
משתיקים התראות
באנר ההתראות של Windows נראה קל, ומפריע יותר ממה שנדמה. מעבר להפרעה הוויזואלית, הוא יכול לשנות גם תזמון הרצה, פוקוס, ופעילות של אפליקציות ברקע.
מפעילים ידנית Do not disturb, או לפחות מכבים התראות בזמן ה-benchmark.
מדכאים search indexing וסנכרון
אם ה-benchmark קורא הרבה קבצים, כותב הרבה תוצרים, או בונה מחדש source tree שוב ושוב, search indexing וסנכרון ענן פוגעים במדידה בשקט.
- מוציאים את תיקיית ה-benchmark מיעדי ה-indexing
- עוצרים סנכרון של OneDrive / Dropbox / Google Drive וכדומה
- סוגרים דפדפן, Teams, Discord, Slack
זה לא מרשים, אבל כשזה משפיע — זה משפיע חזק.
flowchart TB
accTitle: רעש שפוגע ב-benchmark שנוגע בהרבה קבצים
accDescr: תרשים שמראה שב-benchmark שקורא וכותב הרבה קבצים, search indexing, סנכרון ענן ותוכנות resident פוגעים במדידה, ולכן exclusion או עצירה מקטינים רעש.
ix1["search indexing"] --> hit1["פוגע ב-benchmark שנוגע בהרבה קבצים"]
sy1["סנכרון ענן"] --> hit1
ap2["תוכנות resident"] --> hit1
hit1 --> cutn1["exclusion ועצירה מקטינים רעש"]
איור 9: ככל שה-benchmark קורא וכותב יותר קבצים, עצירת indexing וסנכרון משפיעה יותר.
השוואה בלי ליישר חום בדרך כלל משווה חום
CPU ו-GPU משנים clock כשהם קרים לעומת אחרי שהתחממו. גם אותו קוד רץ בתנאים אחרים בכל הרצה. זה בולט במיוחד במחשב נייד, mini-PC דק, ומחשב שולחני קטן.
flowchart TB
accTitle: איך חום משנה את התנאים
accDescr: תרשים שמראה ש-CPU ו-GPU משנים clock כשהם קרים לעומת אחרי שהתחממו, ולכן גם אותו קוד רץ בתנאים אחרים בכל הרצה, והשוואה בלי ליישר חום משווה בפועל חום.
cold1["הרצה במצב קר"] --> hot1["ההתחממות משנה את ה-clock"]
hot1 --> vary1["התנאים משתנים בכל הרצה"]
vary1 -.-> heatc1["השוואה בלי ליישר חום משווה חום"]
איור 10: ה-clock זז עם החום. אם לא מיישרים תנאי חום, משווים קירור ולא קוד.
כללים שכדאי לשמור
- מיישרים ככל האפשר את טמפרטורת החדר
- מקבעים איך המחשב הנייד מונח
- מקבעים את הרכב מתאם ה-AC, ה-dock והמסכים החיצוניים
- לא עושים עבודה כבדה לפני ה-benchmark
- מודדים בנפרד את ההרצה הראשונה ואת ה-steady state
סדר ההרצה: לסירוגין
נמנעים מ-A עשר פעמים ואז B עשר פעמים. חום, cache ופעילות ברקע נצברים אז בצורה מוטה.
מומלץ אחד מאלה:
A B A B A B ...A B B A A B B A ...- מייצרים מראש סדר אקראי, ורצים לפיו
flowchart TB
accTitle: סדר ההרצה משנה איך ההטיה נצברת
accDescr: תרשים שמראה שאם מריצים קודם את כל A ואז את כל B, הטיה של חום, cache ופעילות ברקע נופלת רק על צד אחד, ואילו הרצה לסירוגין או בסדר אקראי מפזרת את ההטיה לשני הצדדים ומסירה את השפעת הסדר מההבדל.
seq1["כל A → כל B"] --> bias1["ההטיה נופלת רק על צד אחד"]
alt1["לסירוגין A B A B, או סדר אקראי"] --> even1["ההטיה מתפזרת לשני הצדדים"]
even1 --> fair1["אפשר להוריד את השפעת הסדר מההבדל"]
איור 11: הרצה מרוכזת גוררת גם את ההטיה לתוך ההשוואה, ולכן רצים לסירוגין או באקראי.
מה שמודדים קובע מה “מהיר” אומר
אם דוחסים “מהיר” למספר אחד, בדרך כלל זה נשבר. שלושת המדדים הייצוגיים שכדאי לראות ב-Windows:
1. Wall-clock time (זמן שעון קיר)
הזמן שהמשתמש מחכה. זה הכי קרוב לחוויית end-to-end, ולכן זה הערך הראשון שבודקים.
ב-Windows, QueryPerformanceCounter (QPC) משמש לקבלת זמן ברזולוציה גבוהה.
ב-managed code, הבסיס הוא Stopwatch.
להסתכל על מילישניות עם DateTime.Now זה קצת חשוף מדי.
2. CPU time (user + kernel)
הזמן שבו התהליך באמת השתמש ב-CPU, שמתקבל עם GetProcessTimes.
זה נוח כדי לראות יעילות חישוב. למשל, אם wall-clock ירד אבל CPU time לא השתנה, ייתכן ש-cache, I/O, המתנה או scheduling הם מה שמשפיע.
3. Cycle count (מספר מחזורי CPU)
עם QueryProcessCycleTime אפשר לקבל את מספר מחזורי ה-CPU של כל התהליך.
גם זה מדד ל-CPU work, אבל הוא מראה פן אחר מ-wall-clock. נוח במיוחד כשרוצים לראות “האם זמן ההמתנה זהה, אבל חלק החישוב נהיה קל יותר”.
flowchart TB
accTitle: איזה פן כל אחד משלושת המדדים מראה
accDescr: תרשים שמראה ש-wall-clock time הוא הזמן שהמשתמש מחכה, CPU time הוא זמן ה-CPU שהתהליך באמת צרך, ו-cycle count הוא כובד חלק החישוב, ורק בשילוב אפשר לקרוא מה המהירות אומרת.
spd1["בודקים מה 'מהיר' באמת אומר"] --> w1["wall-clock: זמן המתנה"]
spd1 --> u1["CPU time: זמן CPU בפועל"]
spd1 --> cy1["cycle: כובד חלק החישוב"]
w1 -.-> mixr1["מסיקים סיבה מהשילוב"]
איור 12: לא דוחסים למספר אחד. קוראים את משמעות המהירות משילוב שלושת המדדים.
priority, affinity ו-NUMA הם המוצא האחרון
לפעמים אלה משפיעים. אבל אם נוגעים בהם מההתחלה רק כי הם משפיעים, קל לייצר תופעה אחרת.
קודם מודדים במצב רגיל
אם ההבדל מופיע ב-default, יש ערך בהבדל הזה כשלעצמו.
אם ישר מכניסים /high או /affinity, מכניסים “תנאי שלא קורה ב-Windows אמיתי”.
flowchart TB
accTitle: priority ו-affinity הם המוצא האחרון
accDescr: תרשים שמראה שקודם מודדים ב-default, ואם מופיע הבדל יש בו ערך, ושהזרקת priority או affinity ישר מכניסה תנאי שלא קורה ב-Windows אמיתי, ולכן אם משתמשים בזה, זה רק בסוף עם מטרה ברורה.
def1["קודם מודדים ב-default"] --> val1["הבדל שמופיע — יש בו ערך"]
early1["מכניסים ישר /high או /affinity"] -.-> art1["מכניסים תנאי שלא קורה בפועל"]
val1 -->|"אם צריך, מגדירים מטרה"| lastr1["ומקבעים כמוצא אחרון"]
איור 13: priority ו-affinity באים אחרי שמסיימים מדידה ב-default, ורק עם מטרה ברורה.
אם משתמשים, מבהירים את המטרה
- /high: רוצים להקטין הפרעה מתהליכים אחרים
- /affinity: רוצים לקבע שיבוץ CPU לצורך השוואה
- שליטה ב-NUMA: במחשב גדול, רוצים ליישר גם locality של זיכרון
הפקודה start של Windows יכולה להפעיל עם priority class ו-affinity mask.
start "" /high /wait myapp.exe --bench case1.json
start "" /affinity F /high /wait myapp.exe --bench case1.json
עם זאת, נמנעים מ-/realtime
/realtime אפשר להשתמש בו, אבל עדיף לא.
זה נוטה לא להוריד רעש, אלא לייצר תקלה אחרת.
נוהל מדידה מומלץ
לאור כל זה, הנה נוהל שנוח להריץ בפועל.
נוהל שנוטה למעבדה
- מקבעים את יעד ההשוואה
- commit hash / build number
- גרסת compiler / runtime
- Debug / Release
- לוגים, assert, tracing כן/לא
- מקבעים את תנאי המחשב
- Windows build
- גרסת BIOS / UEFI
- גרסת driver
- חיבור AC
- טמפרטורת חדר, אופן ההצבה
- מקבעים תנאי חשמל
- קובעים את ה-Power mode
- מתעדים את ה-Active power plan
- מאתחלים
- מחכים כמה דקות לפני ה-benchmark
- אם צריך, clean boot
- מוסיפים warm-up
- מריצים A / B לסירוגין
- דואגים למספר הרצות מספיק
- שומרים חציון, min, max, p95
- שומרים raw data
- אם ההבדל קטן, לוקחים ETW / WPR
כמה פעמים מריצים
הנה גם קו מנחה לסעיף 9, “דואגים למספר הרצות מספיק”. זה לא פתרון סטטיסטי מדויק, אלא נקודת נחיתה מעשית.
| מה רוצים לראות | קו מנחה למספר הרצות לכל גרסה |
|---|---|
| רוצים לראות רק חציון, ולוודא הבדל גדול (מעל 10%) | 10 |
| רוצים לטעון הבדל של כמה אחוזים, וגם לראות פיזור | 30 |
| רוצים לקרוא גם p95 | 30 ומעלה. ב-20 הרצות, p95 הופך לערך אחד או שניים העליונים עצמם, ומושפע ישירות מערכים חריגים |
זמן הביצוע אפשר לאמוד לפי זמן הרצה בודדת × מספר הרצות × מספר גרסאות + warm-up. אם עיבוד של 30 שניות רץ 30 פעמים לכל אחד מ-A / B, זה יוצא בערך 35 דקות כולל warm-up. אם זה לא ריאלי, עדיף לחתוך את יעד המדידה (להוציא רק את השלב הכבד) מאשר לקצץ במספר ההרצות.
אם לא ברור מתי לעצור, הדרך הפשוטה היא להגדיל את מספר ההרצות תוך מעקב אחרי מגמת החציון, ולעצור כשההגדלה כבר לא מזיזה אותו.
flowchart TB
accTitle: מתי עוצרים את מספר ההרצות
accDescr: תרשים שמראה שמגדילים את מספר ההרצות תוך מעקב אחרי מגמת החציון, ועוצרים כשהחציון כבר לא זז גם כשמוסיפים הרצות.
add2["מגדילים את מספר ההרצות"] --> mdz1["עוקבים אחרי מגמת החציון"]
mdz1 -->|"עדיין זז"| add2
mdz1 -->|"כבר לא זז גם אחרי הגדלה"| stop1["עוצרים כאן"]
איור 14: גם בלי לקבע מראש את מספר ההרצות, אפשר לעצור בנקודה שהחציון התייצב.
פרטים ששווה לתעד — יעזרו אחר כך
ב-CSV או ב-JSON של ה-benchmark, שווה לשמור לפחות את אלה:
timestamp,version,scenario,elapsed_ms,user_ms,kernel_ms,cycles,power_mode,power_plan,ac_or_dc,room_temp_c,notes
אם אפשר, נוח להוסיף גם:
cpu_package_temp_start_c,cpu_package_temp_end_c,affinity_mask,priority_class,windows_build,driver_version
ב-benchmark, לפעמים היכולת לפרש אחר כך חשובה יותר מעצם המדידה.
מסתכלים לא רק על הממוצע, אלא גם על החציון והפיזור
הממוצע נוח, אבל ב-benchmark על Windows הוא נשבר בקלות. סריקת Defender אחת, התראה אחת, או תהליך אחר שהכה ב-SSD — והממוצע נמשך הצידה.
flowchart TB
accTitle: הממוצע נמשך אחרי ערך חריג
accDescr: תרשים שמראה שרעש בודד של סריקת Defender, התראה או I/O של תהליך אחר מושך את הממוצע, ולכן מתבססים על החציון ומוסיפים p95, p99 ו-min/max כדי לקרוא לפי פיזור.
once3["רעש בודד נכנס"] --> avg1["הממוצע נמשך הצידה"]
med2["מתבססים על החציון"] --> dist1["מוסיפים גם p95 / p99 ו-min / max"]
dist1 --> robust1["קריאה עמידה יותר לערך חריג"]
איור 15: הממוצע נשבר מרעש בודד, ולכן קוראים לפי שילוב של חציון ופיזור.
השילוב המומלץ:
- חציון: מסתכלים על זה קודם
- p95 / p99: בודקים אם ה-tail התדרדר
- min / max: בודקים איך זה סוטה
- box plot או scatter: מועיל כשההבדל קטן
איך קוראים כשמופיע הבדל
פרשנות התוצאה קלה יותר כשמסתכלים על שילוב.
מהיר רק ב-wall-clock
ייתכן שיפור ב-I/O, בזמן המתנה, ב-cache או ב-scheduling.
גם CPU time וגם cycle יורדים
סביר שהמימוש עצמו נהיה קל יותר.
איטי / מהיר רק בפעם הראשונה
זה הבדל cold / warm. חושדים ב-startup, באתחול, ביצירת cache, ב-JIT.
נהיה איטי יותר ככל שחוזרים
חושדים בחום, throttling, לחץ זיכרון, פעילות ברקע.
flowchart TB
accTitle: קוראים את הסיבה מתבנית ההבדל
accDescr: תרשים שמראה שאם ההבדל הוא רק ב-wall-clock חושדים בהמתנה או I/O, אם גם CPU time יורד חושדים במימוש קל יותר, אם ההבדל רק בפעם הראשונה חושדים ב-cold מול warm, ואם ההרצות המאוחרות איטיות יותר חושדים בחום או פעילות ברקע.
pt2["מסתכלים על תבנית ההבדל"] -->|"רק wall-clock"| c1a["המתנה / I/O"]
pt2 -->|"גם CPU time יורד"| c2a["מימוש קל יותר"]
pt2 -->|"רק בפעם הראשונה"| c3a["cold / warm"]
pt2 -->|"איטי בהמשך"| c4a["חום / פעילות ברקע"]
איור 16: לא ההבדל עצמו, אלא התבנית שבה הוא מופיע, מכוונת לסיבה.
יורדים עד “למה זה מהיר” עם ETW / WPR
כשההבדל קטן, או שהסיבה לא ברורה, הגישה הסטנדרטית היא לעבור לכלי ETW (Event Tracing for Windows) של Windows.
Windows Performance Recorder (WPR) של Microsoft הוא כלי הקלטה מבוסס ETW, וכלול ב-Windows ADK.
אפשר לרשום יחד CPU, I/O, context switch, page fault ועוד.
ברמה המינימלית זה נראה כך:
wpr -start CPU -filemode
REM כאן מריצים את ה-benchmark
wpr -stop trace.etl
אחרי פתיחה ב-WPA, הגרפים הראשונים שבודקים בדרך כלל קבועים.
| מה רוצים לראות | הגרף שפותחים | איך קוראים |
|---|---|---|
| באיזו פונקציה ה-CPU נצרך | CPU Usage (Sampled) | ממיינים לפי Weight, ומשווים stack בין A ל-B. כי זה sampling, עיבוד קצר כמו DPC / ISR לא תמיד נראה |
| למה יש המתנה | CPU Usage (Precise) | בודקים Ready time, זמן המתנה, וסיבת context switch. הבדל של המתנה ל-lock או ל-I/O מופיע כאן |
| האם יש חסימה שמקורה ב-driver | DPC/ISR | בודקים זמן לפי מודול. אם זה גדול, ההבדל מלכתחילה לא בצד היישום |
| האם הדיסק משפיע | Disk Usage | בודקים מספר וגודל פעולות I/O, וזמן שירות |
בהשוואה, העיקרון הוא לקחת trace אחד לכל אחד מ-A ו-B, על אותו תרחיש, ולהציג את אותו גרף זה לצד זה. מ-trace בודד אי אפשר להחליט “האם זה איטי”.
בשלב הזה אפשר לעבור מ- “B מהיר ב-3%” ל- “B מקטין המתנה ל-lock ו-ready time יורד” “A פותח יותר קבצים ולכן ה-cold start איטי יותר” — לדבר עם סיבה.
flowchart TB
accTitle: מהבדל מספרי בלבד להבדל עם סיבה
accDescr: תרשים שמראה שכשההבדל קטן או הסיבה לא ברורה, לוקחים עם WPR trace אחד לכל אחד מ-A ו-B על אותו תרחיש, ומשווים ב-WPA את אותו גרף זה לצד זה, ומגיעים לדבר עם סיבה במקום רק אחוז.
small2["ההבדל קטן / הסיבה לא ברורה"] --> tr1["לוקחים trace ל-A ול-B עם WPR"]
tr1 --> cmp2["משווים ב-WPA את אותו גרף זה לצד זה"]
cmp2 --> rsn1["אפשר לדבר עם סיבה"]
cmp2 -.-> onen1["trace בודד לא מספיק כדי להחליט אם זה איטי"]
איור 17: כשיורדים עד ETW, “מהיר ב-X%” הופך ל”למה זה מהיר”.
checklist בעמוד אחד
לבסוף, בצורה שאפשר להדביק ישירות לנוהל.
מקבעים
- קיבעתי את יעד ההשוואה (commit hash / build number / Debug או Release / תנאי build כמו PGO / לוגים ו-assert כן/לא)
- במחשב נייד חיברתי AC
- קיבעתי את Power mode באפליקציית Settings
- בדקתי את Active power plan עם
powercfg /getactivescheme - עצרתי התראות. עצרתי search indexing וסנכרון ענן
- אם צריך, ביצעתי clean boot
- אתחלתי, וחיכיתי כמה דקות לפני שהתחלתי
מריצים
- הכנסתי warm-up
- מדדתי בנפרד cold (ראשון) ו-warm (steady state)
- הרצתי A / B לסירוגין, או בסדר אקראי
- קבעתי מספר הרצות והרצתי (ראו את הטבלה למעלה)
מתעדים
- שמרתי raw data של שורה אחת להרצה (
elapsed_ms/user_ms/kernel_ms/cycles) - שמרתי AC או DC, Power mode, GUID של ה-Power plan, Windows build, גרסת driver
- שמרתי טמפרטורת חדר ומצב הצבה
- רשמתי גם תנאים שלא קיבעתי
מפרשים
- בדקתי חציון. לא החלטתי לפי ממוצע בלבד
- בדקתי p95 / p99 של ה-tail
- בדקתי min / max לערכים חריגים
- הסקתי סיבה משילוב wall-clock / CPU time / cycle
- כשההבדל קטן, ירדתי עד ETW / WPR
סיכום
בהשוואת תוכנה בין גרסאות ב-Windows, מה שבאמת משפיע הוא לא טריק ראוותני. מה שחשוב הוא נוהג שקט אבל משפיע על reproducibility מהסוג הבא:
- קיבוע ותיעוד של AC / Power mode / Power plan
- הפרדה בין cold ל-warm
- הרצה לסירוגין של A / B
- בדיקת חציון ופיזור
- אם צריך, clean boot
- אם ההבדל קטן, ירידה עד הסיבה עם ETW / WPR
והדבר הכי חשוב הוא לכתוב יחד עם התוצאה מה קיבעתם ומה לא קיבעתם. benchmark הוא גם השוואת מהירות, וגם תיעוד תנאי הניסוי.
דיווח האצה בלי תיעוד תנאים: אחרים לא יכולים לוודא אם מגיעים לאותה תוצאה. נשארים רק מספרים, ולא נשארת דרך לשחזור. לעומת זאת, אם התנאים כתובים כראוי, גם אם ההבדל קטן, יש בתוצאה ערך אמיתי.
flowchart TB
accTitle: תיעוד התנאים קובע את ערך התוצאה
accDescr: תרשים שמראה שדוח האצה בלי תנאים נשארים בו רק מספרים ואחרים לא יכולים לוודא, ואילו דוח עם תנאים כתובים כראוי נשארת בו דרך שחזור, כך שגם הבדל קטן שם יש ערך.
norec1["דיווח בלי תיעוד תנאים"] --> onlyn1["נשארים רק מספרים"]
onlyn1 --> norep1["אחרים לא יכולים לוודא"]
rec3["דיווח עם תנאים כתובים"] --> rep1["נשארת דרך שחזור"]
rep1 --> worth1["גם הבדל קטן — יש ערך"]
איור 18: ערך ה-benchmark טמון פחות במספרים ויותר בתיעוד מה קובע ומה לא נקבע.
מקורות
- Microsoft Support: Change the power mode for your Windows PC
- Microsoft Learn: Power Policy Settings
- Microsoft Learn: Customize the Windows performance power slider
- Microsoft Learn: Powercfg command-line options
- Microsoft Support: How to perform a clean boot in Windows
- Microsoft Support: Notifications and Do Not Disturb in Windows
- Microsoft Support: Search indexing in Windows
- Microsoft Learn: Configure custom exclusions for Microsoft Defender Antivirus
- Microsoft Support: Device Security in the Windows Security App
- Microsoft Learn: QueryPerformanceCounter function
- Microsoft Learn: Acquiring high-resolution time stamps
- Microsoft Learn: GetProcessTimes function
- Microsoft Learn: QueryProcessCycleTime function
- Microsoft Learn: start command
- Microsoft Learn: SetPriorityClass function
- Microsoft Learn: SetProcessAffinityMask function
- Microsoft Learn: Processor Groups
- Microsoft Learn: Windows Performance Recorder
- Microsoft Learn: WPR Command-Line Options
- Microsoft Learn: CPU Analysis in Windows Performance Analyzer - איזה גרף מציג מה.
- Microsoft Learn: Set the Default Power Plan - דוגמת פלט של
powercfg -LIST.
מאמרים קשורים
מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.
השוואת ביצועים הוגנת בין C#, C++, Java ו-Go
איך משווים בהגינות את מהירות הריצה של C#, C++, Java ו-Go: תכנון המדידה, warm-up, קיבוע הסביבה, קריאת הסטטיסטיקה, ופריטי benchmark קונקרטיים.
איך קיצור דרך ב-Windows מוצא קובץ שהעברתם? — המיקום של הקובץ והזהות שלו הם שני דברים שונים
העברתם את הקובץ המקורי, ובכל זאת הקיצור פותח אותו. Windows מחפש את היעד לא רק לפי הנתיב השמור, אלא גם לפי מזהי מעקב ומאפיינים של הקובץ, ו...
האם עדיין צריך "הסרה בטוחה" של כונן USB? — מבט מ"הסרה מהירה" ומטמון הכתיבה
אפשר לשלוף כונן USB ברגע שההעתקה הסתיימה? ההבדל בין מטמון הכתיבה, "הסרה מהירה" ו"ביצועים גבוהים" מסביר מה תפקידה של ההסרה הבטוחה. המאמר כ...
למה האודיו נקטע כשה-CPU לא עסוק? — מבט דרך buffer ו-deadline
האודיו נקטע בזמן שהשימוש ב-CPU נמוך. ההסבר יוצא מה-buffer של הניגון ומה-deadline של המילוי מחדש, ממשיך למה buffer גדול יותר מוסיף השהיה, ...
למה RDP איטי למרות חיבור מהיר? — להפריד בין input, rendering ורשת
בדיקת המהירות מראה מהירות גבוהה, ובכל זאת ה-input וה-scroll ב-Remote Desktop מאחרים. ההסבר עובר מ-round trips והעברת המסך, דרך השוואה לפי...
נושאים קשורים
העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.
נושאים טכניים ב-Windows
שער לנושאי פיתוח Windows, חקירת תקלות וניצול נכסים קיימים.
שירותים הקשורים לנושא הזה
המאמר קשור ישירות לשירותים הבאים.
ייעוץ טכני וסקירת תכנון
תכנון השוואת ביצועים, איך מיישרים את תנאי המדידה, ועד חקירה עם ETW / WPR — נושא שמתאים לייעוץ טכני ול-design review.
חקירת תקלות ואיתור גורמים
כשגרסה אחת מהירה יותר מהשנייה, זרימת העבודה שמפרידה בין תנאי חשמל, חום, רעש ברקע והבדל במימוש מתקדמת בקלות כחקירת באג וניתוח שורש.
שאלות נפוצות
שאלות נפוצות בפניות בנושא המאמר.
- מה הסיבות העיקריות לכך שתוצאות benchmark ב-Windows קופצות?
- יש גורמים בכמה שכבות: Power mode ו-Power plan, חום, עדכונים ברקע, search indexing, virus scan, priority ו-affinity, סדר ההרצה, ומצב cache. גם על אותו מחשב Windows, אם התנאים האלה לא מיושרים, זה בפועל ניסוי אחר. במיוחד במחשב נייד ההתנהגות משתנה מאוד בין חיבור AC לסוללה, ולכן חשוב להשוות תמיד על AC ולתעד את התנאים.
- מה ההבדל בין Power mode ל-Power plan?
- Power mode הוא המעבר בין Best power efficiency, Balanced ו-Best performance שבוחרים ב-Power & battery באפליקציית Settings. הוא משפיע על הגדרות החשמל מאחוריו וגם על התנהגות PPM (Processor Power Management). Power plan הוא תוכנית החשמל המסורתית שרואים ב-powercfg, למשל Balanced או High performance. ב-Windows שניהם קיימים, ולכן בתוצאת benchmark צריך לתעד לפחות שלושה דברים: AC או סוללה, מהו ה-Power mode, ומהו ה-Active power plan.
- זה תקלה אם High performance לא מופיע ברשימת ה-Power plan?
- כנראה שלא. לפי התיעוד של Microsoft, במכשירים עם Modern Standby מותרות רק Balanced, או plan שנגזר מ-Balanced. כלומר זה נורמלי שהדגם בכלל לא מציג High performance. בנוסף, אם אי אפשר לשנות את ה-UI של Power mode, ייתכן שנבחר custom power plan, והדרך המהירה היא לנסות קודם Balanced.
- באיזה סדר כדאי להריץ השוואת מהירות בין גרסה A לגרסה B?
- לא מריצים קודם את כל A ורק אחר כך את B. חום, cache ופעילות ברקע נצברים אז רק על צד אחד. מריצים לסירוגין A B A B, או לפי סדר אקראי שנוצר מראש. בנוסף מפרידים בין ההרצה הראשונה הקרה (cold) לבין steady state אחרי שהמערכת התחממה, ומסתכלים לא רק על הממוצע אלא גם על החציון, p95, min ו-max, כדי שערך חריג אחד לא ימשוך את התוצאה.